I need to duplicate the same shape in a slide using Apache POI (XSLF) ppt.
I can do the something like this below code ?
static void cloneShape(XMLSlideShow slideShow, int slideNumber, String textBoxId) {
Optional<XSLFShape> textBoxopt = getShapesByName(slideShow, slideNumber, textBoxId).stream().findFirst();
XSLFAutoShape shapeToBeCloned = (XSLFAutoShape) textBoxopt.get();
XSLFShapeContainer slide = slideShow.getSlides().get(slideNumber);
XSLFAutoShape shape1 = slide.createAutoShape(***shapeToBeCloned***);
There is not any clone method for XSLFShapes. And even if it would, then there is not any method to add a cloned XSLFShape to the XSSFSheet (slide). There is XSSFSheet.addShape(XSLFShape shape) but this does nothing but throwing UnsupportedOperationException. I love the sense of humor of the apache poi developers.
So if one want copy a shape of a slide, then one only is able using the underlying objects. The class org.apache.xmlbeans.XmlObject provides a copy method which makes a deep copy of the XML. Then that copy needs to be added into the shape tree of the slide. Then the shape tree of the slide needs to be new initialized. After that the high level object of the shape can be got from XSSFSheet.getShapes(). Unfortunately most of the needed methods are not public. So reflection needs to be used.
Following code shows one way to do this. It simply clones all shapes except group shapes and graphical object frame shapes in each slide of the given PPTIn.pptx.
import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.sl.usermodel.*;
import org.apache.poi.xslf.usermodel.*;
import java.util.List;
import java.util.ArrayList;
public class PowerPointCloneShape {
static List<XSLFShape> getShapesByName(XMLSlideShow slideShow, String shapeName) {
List<XSLFShape> shapes = new ArrayList<XSLFShape>();
for (XSLFSlide slide : slideShow.getSlides()) {
for (XSLFShape shape : slide.getShapes()) {
//System.out.println(shape.getShapeName());
if (shapeName.equals(shape.getShapeName())) {
shapes.add(shape);
}
}
}
return shapes;
}
static List<XSLFShape> getShapes(XMLSlideShow slideShow) {
List<XSLFShape> shapes = new ArrayList<XSLFShape>();
for (XSLFSlide slide : slideShow.getSlides()) {
for (XSLFShape shape : slide.getShapes()) {
shapes.add(shape);
}
}
return shapes;
}
// method to new initialize drawing and shapes in sheet from updated shape tree
static void initDrawingAndShapes(XSLFSheet sheet) throws Exception {
java.lang.reflect.Field _drawing = XSLFSheet.class.getDeclaredField("_drawing");
_drawing.setAccessible(true);
_drawing.set(sheet, null);
java.lang.reflect.Field _shapes = XSLFSheet.class.getDeclaredField("_shapes");
_shapes.setAccessible(true);
_shapes.set(sheet, null);
java.lang.reflect.Method initDrawingAndShapes = XSLFSheet.class.getDeclaredMethod("initDrawingAndShapes");
initDrawingAndShapes.setAccessible(true);
initDrawingAndShapes.invoke(sheet);
}
// method to allocate the next shape ID in sheet
static int allocateShapeId(XSLFSheet sheet) throws Exception {
java.lang.reflect.Method allocateShapeId = XSLFSheet.class.getDeclaredMethod("allocateShapeId");
allocateShapeId.setAccessible(true);
int nextId = (int)allocateShapeId.invoke(sheet);
return nextId;
}
// method to get the shape tree of sheet
static org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape getSpTree(XSLFSheet sheet) throws Exception {
java.lang.reflect.Field _spTree = XSLFSheet.class.getDeclaredField("_spTree");
_spTree.setAccessible(true);
org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape spTree = (org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape)_spTree.get(sheet);
return spTree;
}
// method to clone a shape contained in a sheet
static XSLFShape cloneShape(XSLFShape shape) throws Exception {
// first clone low level XML
org.apache.xmlbeans.XmlObject xmlObject = shape.getXmlObject();
org.apache.xmlbeans.XmlObject xmlClone = xmlObject.copy();
//System.out.println(xmlClone.getClass().getName());
// then create high level clone shapes
if (xmlClone instanceof org.openxmlformats.schemas.presentationml.x2006.main.CTShape) { // simple shape
org.openxmlformats.schemas.presentationml.x2006.main.CTShape ctShapeClone = (org.openxmlformats.schemas.presentationml.x2006.main.CTShape)xmlClone;
// get sheet
XSLFSheet sheet = shape.getSheet();
// set new ID
int nextId = allocateShapeId(sheet);
ctShapeClone.getNvSpPr().getCNvPr().setId(nextId);
// add into the shape tree of sheet
org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape spTree = getSpTree(sheet);
spTree.addNewSp();
spTree.setSpArray(spTree.sizeOfSpArray()-1, ctShapeClone);
// new initialize drawing and shapes in sheet
initDrawingAndShapes(sheet);
// get clone
XSLFShape clone = sheet.getShapes().get(sheet.getShapes().size()-1);
return clone;
} else if (xmlClone instanceof org.openxmlformats.schemas.presentationml.x2006.main.CTPicture) { // picture shape
org.openxmlformats.schemas.presentationml.x2006.main.CTPicture ctPictureClone = (org.openxmlformats.schemas.presentationml.x2006.main.CTPicture)xmlClone;
XSLFSheet sheet = shape.getSheet();
int nextId = allocateShapeId(sheet);
ctPictureClone.getNvPicPr().getCNvPr().setId(nextId);
org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape spTree = getSpTree(sheet);
spTree.addNewPic();
spTree.setPicArray(spTree.sizeOfPicArray()-1, ctPictureClone);
initDrawingAndShapes(sheet);
XSLFShape clone = sheet.getShapes().get(sheet.getShapes().size()-1);
return clone;
} else if (xmlClone instanceof org.openxmlformats.schemas.presentationml.x2006.main.CTConnector) { // connector shape
org.openxmlformats.schemas.presentationml.x2006.main.CTConnector ctConnectorClone = (org.openxmlformats.schemas.presentationml.x2006.main.CTConnector)xmlClone;
XSLFSheet sheet = shape.getSheet();
int nextId = allocateShapeId(sheet);
ctConnectorClone.getNvCxnSpPr().getCNvPr().setId(nextId);
org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape spTree = getSpTree(sheet);
spTree.addNewCxnSp();
spTree.setCxnSpArray(spTree.sizeOfCxnSpArray()-1, ctConnectorClone);
initDrawingAndShapes(sheet);
XSLFShape clone = sheet.getShapes().get(sheet.getShapes().size()-1);
// connector has connecting points which also simple are cloned but would must be new adjusted
return clone;
} else if (xmlClone instanceof org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape) { // group shape
// cloning is not that simple
} else if (xmlClone instanceof org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame) { // graphical object frame shape (table, chart, diagram, ...)
// cloning is not that simple
}
return null;
}
public static void main(String args[]) throws Exception {
XMLSlideShow slideShow = new XMLSlideShow(new FileInputStream("./PPTIn.pptx"));
//List<XSLFShape> shapes = getShapesByName(slideShow, "Textbox 1");
List<XSLFShape> shapes = getShapes(slideShow);
System.out.println(shapes);
//if (shapes.size() > 0 ) {
//XSLFShape shape = shapes.get(0);
for (XSLFShape shape : shapes) {
System.out.println("source: " + shape);
XSLFShape clone = cloneShape(shape);
System.out.println("clone: " + clone);
if (clone instanceof PlaceableShape) {
if (!clone.isPlaceholder() || clone.getPlaceholder() == Placeholder.CONTENT) { // do not change anchor of placeholders except content
PlaceableShape placeableShape = (PlaceableShape)clone;
java.awt.geom.Rectangle2D anchor = shape.getAnchor();
placeableShape.setAnchor(new java.awt.geom.Rectangle2D.Double(anchor.getX()+100, anchor.getY()+100, anchor.getWidth(), anchor.getHeight()));
//System.out.println(clone.getAnchor());
}
}
if (clone instanceof XSLFTextShape) {
XSLFTextShape textShape = (XSLFTextShape)clone;
if (textShape.getTextParagraphs().size() > 0 && textShape.getTextParagraphs().get(0).getTextRuns().size() > 0) {
textShape.getTextParagraphs().get(0).getTextRuns().get(0).setText("new text");
} else {
textShape.setText("new text");
}
//System.out.println(textShape.getText());
}
}
FileOutputStream out = new FileOutputStream("./PPTOut.pptx");
slideShow.write(out);
out.close();
slideShow.close();
}
}
If after cloning you got warning shape id X has been already used,
try clear shapeIds before calling initDrawingAndShapes:
static void clearShapeIds(XSLFSheet sheet) {
Field _shapeIds = XSLFSheet.class.getDeclaredField("shapeIds");
_shapeIds.setAccessible(true);
((SparseBitSet) _shapeIds.get(sheet)).clear();
}
Related
Let's assume i have a word document, with this body.
Word document before replacing images
private void findImages(XWPFParagraph p) {
for (XWPFRun r : p.getRuns()) {
for (XWPFPicture pic : r.getEmbeddedPictures()) {
XWPFPicture picture = pic;
XWPFPictureData source = picture.getPictureData();
BufferedImage qrCodeImage = printVersionService.generateQRCodeImage("JASAW EMA WWS");
File imageFile = new File("image.jpg");
try {
ImageIO.write(qrCodeImage, "jpg", imageFile);
} catch (IOException e) {
e.printStackTrace();
}
try ( FileInputStream in = new FileInputStream(imageFile);
OutputStream out = source.getPackagePart().getOutputStream();
) {
byte[] buffer = new byte[2048];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
So this code replaces any image with QR code.
But I have one trouble.
Word Document after replacing
So my question is?
How can I replace only the image i chose or how can i replace inserted figure with text with image generated by my own function?
Detecting the picture and replacing the picture data will be the simplest. In following answer I have shown how to detect and replace pictures by name: Java Apache POI: insert an image "infront the text". If you do not know the name of the embedded picture, a picture also can be detected by alt text. To edit the alt text of a picture, open the context menu by right mouse click on the picture and choose Edit A̲lt Text from that context menu.
In How to read alt text of image in word document apache.poi I have shown already how to read alt text of image.
So code could look like:
import java.io.FileInputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
public class WordReplacePictureData {
static org.apache.xmlbeans.XmlObject getInlineOrAnchor(org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPictureToFind, org.apache.xmlbeans.XmlObject inlineOrAnchor) {
String declareNameSpaces = "declare namespace pic='http://schemas.openxmlformats.org/drawingml/2006/picture'; ";
org.apache.xmlbeans.XmlObject[] selectedObjects = inlineOrAnchor.selectPath(
declareNameSpaces
+ "$this//pic:pic");
for (org.apache.xmlbeans.XmlObject selectedObject : selectedObjects) {
if (selectedObject instanceof org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) {
org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPicture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture)selectedObject;
if (ctPictureToFind.equals(ctPicture)) {
// this is the inlineOrAnchor for that picture
return inlineOrAnchor;
}
}
}
return null;
}
static org.apache.xmlbeans.XmlObject getInlineOrAnchor(XWPFRun run, XWPFPicture picture) {
org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture ctPictureToFind = picture.getCTPicture();
for (org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing drawing : run.getCTR().getDrawingList()) {
for (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline inline : drawing.getInlineList()) {
org.apache.xmlbeans.XmlObject inlineOrAnchor = getInlineOrAnchor(ctPictureToFind, inline);
// if inlineOrAnchor is not null, then this is the inline for that picture
if (inlineOrAnchor != null) return inlineOrAnchor;
}
for (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor anchor : drawing.getAnchorList()) {
org.apache.xmlbeans.XmlObject inlineOrAnchor = getInlineOrAnchor(ctPictureToFind, anchor);
// if inlineOrAnchor is not null, then this is the anchor for that picture
if (inlineOrAnchor != null) return inlineOrAnchor;
}
}
return null;
}
static org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps getNonVisualDrawingProps(org.apache.xmlbeans.XmlObject inlineOrAnchor) {
if (inlineOrAnchor == null) return null;
if (inlineOrAnchor instanceof org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline) {
org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline inline = (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline)inlineOrAnchor;
return inline.getDocPr();
} else if (inlineOrAnchor instanceof org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor) {
org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor anchor = (org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor)inlineOrAnchor;
return anchor.getDocPr();
}
return null;
}
static String getSummary(org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps nonVisualDrawingProps) {
if (nonVisualDrawingProps == null) return "";
String summary = "Id:=" + nonVisualDrawingProps.getId();
summary += " Name:=" + nonVisualDrawingProps.getName();
summary += " Title:=" + nonVisualDrawingProps.getTitle();
summary += " Descr:=" + nonVisualDrawingProps.getDescr();
return summary;
}
static XWPFPicture getPictureByAltText(XWPFRun run, String altText) {
if (altText == null) return null;
for (XWPFPicture picture : run.getEmbeddedPictures()) {
String altTextSummary = getSummary(getNonVisualDrawingProps(getInlineOrAnchor(run, picture)));
System.out.println(altTextSummary);
if (altTextSummary.contains(altText)) {
return picture;
}
}
return null;
}
static void replacePictureData(XWPFPictureData source, String pictureResultPath) {
try ( FileInputStream in = new FileInputStream(pictureResultPath);
OutputStream out = source.getPackagePart().getOutputStream();
) {
byte[] buffer = new byte[2048];
int length;
while ((length = in.read(buffer)) > 0) {
out.write(buffer, 0, length);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
static void replacePicture(XWPFRun run, String altText, String pictureResultPath) {
XWPFPicture picture = getPictureByAltText(run, altText);
if (picture != null) {
XWPFPictureData source = picture.getPictureData();
replacePictureData(source, pictureResultPath);
}
}
public static void main(String[] args) throws Exception {
String templatePath = "./source.docx";
String resultPath = "./result.docx";
String altText = "Placeholder QR-Code";
String pictureResultPath = "./QR.jpg";
try ( XWPFDocument document = new XWPFDocument(new FileInputStream(templatePath));
FileOutputStream out = new FileOutputStream(resultPath);
) {
for (IBodyElement bodyElement : document.getBodyElements()) {
if (bodyElement instanceof XWPFParagraph) {
XWPFParagraph paragraph = (XWPFParagraph)bodyElement;
for (XWPFRun run : paragraph.getRuns()) {
replacePicture(run, altText, pictureResultPath);
}
}
}
document.write(out);
}
}
}
This replaces the picture or pictures having alt text "Placeholder QR-Code". All other pictures remain as they are.
Replacing shapes with pictures is very laborious as shapes are stored in alternate content elements (to choice shape and fallback) and so the shape needs to be changed as well as the fallback. If one would let the fallback untouched, then applications which rely on that fallback will further show the old shape. Furthermore detecting shapes by text box content is not really much simpler than detecting pictures by alt text content.
So, I started using Physics Body Editor as an extension to libgdx. I also use Android Studio to compile my code, so I can run an app on a real device.
But, unfortunately, as I create a new loader, like this:
BodyEditorLoader loader = new BodyEditorLoader(Gdx.files.internal("tnkA.json"));
logcat gives me the following error:
java.lang.NoSuchMethodError: No virtual method parse(Ljava/lang/String;)Ljava/lang/Object;
Clearly, something wrong with the Physics Body Editor.
Is there any way to fix this? Thanks!
There is the full error:
02-12 13:39:15.406 2372-2387/com.tynibattles04.game.android E/AndroidRuntime﹕ FATAL EXCEPTION: GLThread 172
Process: com.tynibattles04.game.android, PID: 2372
java.lang.NoSuchMethodError: No virtual method parse(Ljava/lang/String;)Ljava/lang/Object;
in class Lcom/badlogic/gdx/utils/JsonReader;
or its super classes (declaration of 'com.badlogic.gdx.utils.JsonReader' appears
in /data/app/com.tynibattles04.game.android-1/base.apk)
at aurelienribon.bodyeditor.BodyEditorLoader.readJson(BodyEditorLoader.java:179)
at aurelienribon.bodyeditor.BodyEditorLoader.<init>(BodyEditorLoader.java:41)
at com.tynibattles04.game.TinyBattles.createBottle(TinyBattles.java:127)
at com.tynibattles04.game.TinyBattles.create(TinyBattles.java:74)
at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:241)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1511)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1239)
look this maybe this can help with anything :
https://code.google.com/p/box2d-editor/issues/detail?id=25
https://gist.github.com/zudov/5566204
package aurelienribon.bodyeditor;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Loads the collision fixtures defined with the Physics Body Editor
* application. You only need to give it a body and the corresponding fixture
* name, and it will attach these fixtures to your body.
*
* #author Aurelien Ribon | http://www.aurelienribon.com
*/
public class BodyEditorLoader {
// Model
private final Model model;
// Reusable stuff
private final List<Vector2> vectorPool = new ArrayList<Vector2>();
private final PolygonShape polygonShape = new PolygonShape();
private final CircleShape circleShape = new CircleShape();
private final Vector2 vec = new Vector2();
// -------------------------------------------------------------------------
// Ctors
// -------------------------------------------------------------------------
public BodyEditorLoader(FileHandle file) {
if (file == null) throw new NullPointerException("file is null");
model = readJson(file.readString());
}
public BodyEditorLoader(String str) {
if (str == null) throw new NullPointerException("str is null");
model = readJson(str);
}
// -------------------------------------------------------------------------
// Public API
// -------------------------------------------------------------------------
/**
* Creates and applies the fixtures defined in the editor. The name
* parameter is used to retrieve the right fixture from the loaded file.
* <br/><br/>
*
* The body reference point (the red cross in the tool) is by default
* located at the bottom left corner of the image. This reference point
* will be put right over the BodyDef position point. Therefore, you should
* place this reference point carefully to let you place your body in your
* world easily with its BodyDef.position point. Note that to draw an image
* at the position of your body, you will need to know this reference point
* (see {#link #getOrigin(java.lang.String, float)}.
* <br/><br/>
*
* Also, saved shapes are normalized. As shown in the tool, the width of
* the image is considered to be always 1 meter. Thus, you need to provide
* a scale factor so the polygons get resized according to your needs (not
* every body is 1 meter large in your game, I guess).
*
* #param body The Box2d body you want to attach the fixture to.
* #param name The name of the fixture you want to load.
* #param fd The fixture parameters to apply to the created body fixture.
* #param scale The desired scale of the body. The default width is 1.
*/
public void attachFixture(Body body, String name, FixtureDef fd, float scale) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null) throw new RuntimeException("Name '" + name + "' was not found.");
Vector2 origin = vec.set(rbModel.origin).mul(scale);
for (int i=0, n=rbModel.polygons.size(); i<n; i++) {
PolygonModel polygon = rbModel.polygons.get(i);
Vector2[] vertices = polygon.buffer;
for (int ii=0, nn=vertices.length; ii<nn; ii++) {
vertices[ii] = newVec().set(polygon.vertices.get(ii)).mul(scale);
vertices[ii].sub(origin);
}
polygonShape.set(vertices);
fd.shape = polygonShape;
body.createFixture(fd);
for (int ii=0, nn=vertices.length; ii<nn; ii++) {
free(vertices[ii]);
}
}
for (int i=0, n=rbModel.circles.size(); i<n; i++) {
CircleModel circle = rbModel.circles.get(i);
Vector2 center = newVec().set(circle.center).mul(scale);
float radius = circle.radius * scale;
circleShape.setPosition(center);
circleShape.setRadius(radius);
fd.shape = circleShape;
body.createFixture(fd);
free(center);
}
}
/**
* Gets the image path attached to the given name.
*/
public String getImagePath(String name) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null) throw new RuntimeException("Name '" + name + "' was not found.");
return rbModel.imagePath;
}
/**
* Gets the origin point attached to the given name. Since the point is
* normalized in [0,1] coordinates, it needs to be scaled to your body
* size. Warning: this method returns the same Vector2 object each time, so
* copy it if you need it for later use.
*/
public Vector2 getOrigin(String name, float scale) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null)
throw new RuntimeException("Name '" + name + "' was not found.");
return vec.set(rbModel.origin).scl(scale);
}
/**
* <b>For advanced users only.</b> Lets you access the internal model of
* this loader and modify it. Be aware that any modification is permanent
* and that you should really know what you are doing.
*/
public Model getInternalModel() {
return model;
}
// -------------------------------------------------------------------------
// Json Models
// -------------------------------------------------------------------------
public static class Model {
public final Map<String, RigidBodyModel> rigidBodies = new HashMap<String, RigidBodyModel>();
}
public static class RigidBodyModel {
public String name;
public String imagePath;
public final Vector2 origin = new Vector2();
public final List<PolygonModel> polygons = new ArrayList<PolygonModel>();
public final List<CircleModel> circles = new ArrayList<CircleModel>();
}
public static class PolygonModel {
public final List<Vector2> vertices = new ArrayList<Vector2>();
private Vector2[] buffer; // used to avoid allocation in attachFixture()
}
public static class CircleModel {
public final Vector2 center = new Vector2();
public float radius;
}
// -------------------------------------------------------------------------
// Json reading process
// -------------------------------------------------------------------------
private Model readJson(String str) {
Model m = new Model();
JsonValue map = new JsonReader().parse(str);
JsonValue bodyElem = map.getChild("rigidBodies");
for (; bodyElem != null; bodyElem = bodyElem.next()) {
RigidBodyModel rbModel = readRigidBody(bodyElem);
m.rigidBodies.put(rbModel.name, rbModel);
}
return m;
}
private RigidBodyModel readRigidBody(JsonValue bodyElem) {
RigidBodyModel rbModel = new RigidBodyModel();
rbModel.name = bodyElem.getString("name");
rbModel.imagePath = bodyElem.getString("imagePath");
JsonValue originElem = bodyElem.get("origin");
rbModel.origin.x = originElem.getFloat("x");
rbModel.origin.y = originElem.getFloat("y");
// polygons
JsonValue polygonsElem = bodyElem.getChild("polygons");
for (; polygonsElem != null ;polygonsElem = polygonsElem.next()){
PolygonModel polygon = new PolygonModel();
rbModel.polygons.add(polygon);
JsonValue vertexElem = polygonsElem.child();
for (; vertexElem != null; vertexElem = vertexElem.next()) {
float x = vertexElem.getFloat("x");
float y = vertexElem.getFloat("y");
polygon.vertices.add(new Vector2(x, y));
}
polygon.buffer = new Vector2[polygon.vertices.size()];
}
// circles
JsonValue circleElem = bodyElem.getChild("circles");
for (; circleElem != null; circleElem = circleElem.next()) {
CircleModel circle = new CircleModel();
rbModel.circles.add(circle);
circle.center.x = circleElem.getFloat("cx");
circle.center.y = circleElem.getFloat("cy");
circle.radius = circleElem.getFloat("r");
}
return rbModel;
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
private Vector2 newVec() {
return vectorPool.isEmpty() ? new Vector2() : vectorPool.remove(0);
}
private void free(Vector2 v) {
vectorPool.add(v);
}
}
This code is on GitHub, but it was once the reporsitorio deleted because the user account change, I'll post it here so they do not depend account Git.(also with some changes to the code).
I'm trying to load a file using LibGDX's internal file loader via:
"Gdx.files.internal();"
however I get the error:
"GdxRuntimeException: File not Found: data\characters\collisons\misaka\running_aabb.json (Internal)"
This is my code where I am loading the data:
private BodyEditorLoader standingAABB;
private BodyEditorLoader movingAABB;
private BodyEditorLoader currentAABB;
public Player(String name, int x, int y, int width, int height) {
//...
standingAABB = new BodyEditorLoader(Gdx.files.internal("data/characters/collisions/" + name + "/standing_aabb.json"));
movingAABB = new BodyEditorLoader(Gdx.files.internal("data/characters/collisons/" + name + "/running_aabb.json"));
currentAABB = standingAABB;
//...
}
As the error is stating that it cannot load "running_aabb.json" I am assuming that it is able to load "standing_aabb.json".
This is what my assets folder looks like:
As you can see, the file exists where it should be but it cannot be found. I have already tried refreshing the project as well as cleaning the project and reopening Eclipse.
Anyone know what might be causing this error?
BodyEditorLoader.java contents (This isn't mine so I'm not sure which parts are related):
package aurelienribon.bodyeditor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
/**
* Loads the collision fixtures defined with the Physics Body Editor
* application. You only need to give it a body and the corresponding fixture
* name, and it will attach these fixtures to your body.
*
* #author Aurelien Ribon | http://www.aurelienribon.com
*/
public class BodyEditorLoader {
// Model
private final Model model;
// Reusable stuff
private final List<Vector2> vectorPool = new ArrayList<Vector2>();
private final PolygonShape polygonShape = new PolygonShape();
private final CircleShape circleShape = new CircleShape();
private final Vector2 vec = new Vector2();
// -------------------------------------------------------------------------
// Ctors
// -------------------------------------------------------------------------
public BodyEditorLoader(FileHandle file) {
if (file == null) throw new NullPointerException("file is null");
model = readJson(file.readString());
}
public BodyEditorLoader(String str) {
if (str == null) throw new NullPointerException("str is null");
model = readJson(str);
}
// -------------------------------------------------------------------------
// Public API
// -------------------------------------------------------------------------
/**
* Creates and applies the fixtures defined in the editor. The name
* parameter is used to retrieve the right fixture from the loaded file.
* <br/><br/>
*
* The body reference point (the red cross in the tool) is by default
* located at the bottom left corner of the image. This reference point
* will be put right over the BodyDef position point. Therefore, you should
* place this reference point carefully to let you place your body in your
* world easily with its BodyDef.position point. Note that to draw an image
* at the position of your body, you will need to know this reference point
* (see {#link #getOrigin(java.lang.String, float)}.
* <br/><br/>
*
* Also, saved shapes are normalized. As shown in the tool, the width of
* the image is considered to be always 1 meter. Thus, you need to provide
* a scale factor so the polygons get resized according to your needs (not
* every body is 1 meter large in your game, I guess).
*
* #param body The Box2d body you want to attach the fixture to.
* #param name The name of the fixture you want to load.
* #param fd The fixture parameters to apply to the created body fixture.
* #param scale The desired scale of the body. The default width is 1.
*/
public void attachFixture(Body body, String name, FixtureDef fd, float scale) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null) throw new RuntimeException("Name '" + name + "' was not found.");
//Changed mul() call to scl()
Vector2 origin = vec.set(rbModel.origin).scl(scale);
for (int i=0, n=rbModel.polygons.size(); i<n; i++) {
PolygonModel polygon = rbModel.polygons.get(i);
Vector2[] vertices = polygon.buffer;
for (int ii=0, nn=vertices.length; ii<nn; ii++) {
//Changed mul() call to scl()
vertices[ii] = newVec().set(polygon.vertices.get(ii)).scl(scale);
vertices[ii].sub(origin);
}
polygonShape.set(vertices);
fd.shape = polygonShape;
body.createFixture(fd);
for (int ii=0, nn=vertices.length; ii<nn; ii++) {
free(vertices[ii]);
}
}
for (int i=0, n=rbModel.circles.size(); i<n; i++) {
CircleModel circle = rbModel.circles.get(i);
//Changed mul() call to scl()
Vector2 center = newVec().set(circle.center).scl(scale);
float radius = circle.radius * scale;
circleShape.setPosition(center);
circleShape.setRadius(radius);
fd.shape = circleShape;
body.createFixture(fd);
free(center);
}
}
/**
* Gets the image path attached to the given name.
*/
public String getImagePath(String name) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null) throw new RuntimeException("Name '" + name + "' was not found.");
return rbModel.imagePath;
}
/**
* Gets the origin point attached to the given name. Since the point is
* normalized in [0,1] coordinates, it needs to be scaled to your body
* size. Warning: this method returns the same Vector2 object each time, so
* copy it if you need it for later use.
*/
public Vector2 getOrigin(String name, float scale) {
RigidBodyModel rbModel = model.rigidBodies.get(name);
if (rbModel == null) throw new RuntimeException("Name '" + name + "' was not found.");
//Changed mul() call to scl()
return vec.set(rbModel.origin).scl(scale);
}
/**
* <b>For advanced users only.</b> Lets you access the internal model of
* this loader and modify it. Be aware that any modification is permanent
* and that you should really know what you are doing.
*/
public Model getInternalModel() {
return model;
}
// -------------------------------------------------------------------------
// Json Models
// -------------------------------------------------------------------------
public static class Model {
public final Map<String, RigidBodyModel> rigidBodies = new HashMap<String, RigidBodyModel>();
}
public static class RigidBodyModel {
public String name;
public String imagePath;
public final Vector2 origin = new Vector2();
public final List<PolygonModel> polygons = new ArrayList<PolygonModel>();
public final List<CircleModel> circles = new ArrayList<CircleModel>();
}
public static class PolygonModel {
public final List<Vector2> vertices = new ArrayList<Vector2>();
private Vector2[] buffer; // used to avoid allocation in attachFixture()
}
public static class CircleModel {
public final Vector2 center = new Vector2();
public float radius;
}
// -------------------------------------------------------------------------
// Json reading process
// -------------------------------------------------------------------------
private Model readJson(String str) {
Model m = new Model();
JsonValue map = new JsonReader().parse(str);
JsonValue bodyElem = map.getChild("rigidBodies");
for (; bodyElem != null; bodyElem = bodyElem.next()) {
RigidBodyModel rbModel = readRigidBody(bodyElem);
m.rigidBodies.put(rbModel.name, rbModel);
}
return m;
}
private RigidBodyModel readRigidBody(JsonValue bodyElem) {
RigidBodyModel rbModel = new RigidBodyModel();
rbModel.name = bodyElem.getString("name");
rbModel.imagePath = bodyElem.getString("imagePath");
JsonValue originElem = bodyElem.get("origin");
rbModel.origin.x = originElem.getFloat("x");
rbModel.origin.y = originElem.getFloat("y");
// polygons
JsonValue polygonsElem = bodyElem.getChild("polygons");
for (; polygonsElem != null ;polygonsElem = polygonsElem.next()){
PolygonModel polygon = new PolygonModel();
rbModel.polygons.add(polygon);
JsonValue vertexElem = polygonsElem.child();
for (; vertexElem != null; vertexElem = vertexElem.next()) {
float x = vertexElem.getFloat("x");
float y = vertexElem.getFloat("y");
polygon.vertices.add(new Vector2(x, y));
}
polygon.buffer = new Vector2[polygon.vertices.size()];
}
// circles
JsonValue circleElem = bodyElem.getChild("circles");
for (; circleElem != null; circleElem = circleElem.next()) {
CircleModel circle = new CircleModel();
rbModel.circles.add(circle);
circle.center.x = circleElem.getFloat("cx");
circle.center.y = circleElem.getFloat("cy");
circle.radius = circleElem.getFloat("r");
}
return rbModel;
}
// -------------------------------------------------------------------------
// Helpers
// -------------------------------------------------------------------------
private Vector2 newVec() {
return vectorPool.isEmpty() ? new Vector2() : vectorPool.remove(0);
}
private void free(Vector2 v) {
vectorPool.add(v);
}
}
You have misprint in second path: collisons. It should be collisions.
So I have my BufferedImages:
private BufferedImage sdk1, sdk2, sdk3, sdk4, sdk5, sdk6, sdk7, sdk8, sdk9, sdk10, bc;
And my Array values set:
ArrayList<Card> deck1 = new ArrayList(50);
deck1.add(CardList.Spade);
I was wondering, can I assign an image to "Spade" in my Array list? So when it's used on input of the Scanner, it will display an image in a JFrame.
Scanner monSummon = new Scanner(System.in);
int whichMonsterPOS1 = monSummon.nextInt();
Sorry if I can't explain it anymore, and thanks in advance.
You Could
Use some kind of Map, keyed to an instance of Card...
private Map cardImages;
//...
cardImages = new HashMap<Card, BufferedImage>(25);
//...
Card card = ...;
sdk1 = ...;
cardImages.put(card, sdk1);
You Could
Provide a Image property for your Card, this would allow you to create a specific implementation of the required card, supplying the image property directly, for example...
public class AceOfSpadesCard extends Card {
private BufferedImage img;
public AceOfSpadesCard() {
img = ...;
}
public BufferedImage getImage() {
return img;
}
}
In this case, I would make Card abstract and make the getImage method abstract
Or, if that's to much, simply supply a parameter via the Cards constructor.
An example Card class instance that also contains references for the Image to be drawn. Then it's just a matter of putting a set of Cards in an ArrayList (or build a Deck model you can then manipulate) and calling paint on the Card's bufferedImage.
package model.playing;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import model.AbstractCard;
public class PlayingCard extends AbstractCard {
private String[] values = {"ace", "two", "three", "four", "five", "six", "seven",
"eight", "nine", "ten", "jack", "queen", "king"};
private BufferedImage drawableTarget;
private BufferedImage drawableBackTarget;
public PlayingCard(String suit, int value, String desc) throws Exception {
setFlipped(false);
setSuit(suit);
if(null == getSuit()) {
throw new Exception("Suit not found!");
} else if(getSuit().equals("joker")) {
throw new Exception("That's not how you create a joker!");
}
if(value < 14) {
setValue(value);
} else {
throw new Exception("Invalid value, expecting 13 or less!");
}
setDescription(desc);
}
// removed Joker instantiation to keep short
public BufferedImage returnDrawable() {
URL url = null;
BufferedImage img = null;
if(isFlipped()) {
if(null != getDrawableTarget()) {
img = getDrawableTarget();
} else {
url = getClass().getResource("/suits/" + getSuit()
+ "/" + getValues()[getValue() - 1] + ".png");
try {
img = ImageIO.read(url);
setDrawableTarget(img);
} catch (IOException e) {
e.printStackTrace();
}
}
} else {
if(null != getDrawableBackTarget()) {
img = getDrawableBackTarget();
} else {
url = getClass().getResource("/suits/back.png");
try {
img = ImageIO.read(url);
setDrawableBackTarget(img);
} catch (IOException e) {
e.printStackTrace();
}
}
}
return img;
}
// removed all getters and setters to save on space; they're not important
}
I'm new in coding and I have a problem to understand something. I follow the example form Parse.com Doc and wrote this.
public void getData() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseClass");
query.getInBackground("lxFzCTeOcl", new GetCallback<ParseObject>() {
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
String object = parseObject.getString("value");
int object_value = Integer.parseInt(obiect);
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
}
I understand this like:
I send query to server
get obiect with "lxFzCTeOcl" id
if there is no exception I create String object which takes string
form "value" column.
convert String to int
My question is: How can I use object_value for example to make a chart or put it into a table?
Here we will add the array list to your code and start to store an object inside the array every time we call the getData method in your class.
private ArrayList<Integer> dataArray;
public void getData() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("ParseClass");
query.getInBackground("lxFzCTeOcl", new GetCallback<ParseObject>() {
public void done(ParseObject parseObject, ParseException e) {
if (e == null) {
String object = parseObject.getString("value");
Integer objectValue = Integer.parseInt(obiect);
if(dataArray==null)
dataArray = new ArrayList<Integer>();
dataArray.add(objectValue);
} else {
Log.d("score", "Error: " + e.getMessage());
}
}
});
}
And here I'm just adding a simple example of how to create a simple pie chart using our array list (note that I used the lib AChartEngine http://www.achartengine.org/):
private static int[] COLORS = new int[] { Color.GREEN, Color.BLUE,Color.MAGENTA, Color.CYAN };
private GraphicalView createPieChart(ArrayList<Integer> data){
GraphicalView chartView;
CategorySeries series = new CategorySeries("PIE");
for (int i = 0; i < VALUES.length; i++) {
series.add(i, data.get(i));
SimpleSeriesRenderer renderer = new SimpleSeriesRenderer();
renderer.setColor(COLORS[(series.getItemCount() - 1) % COLORS.length]);
mRenderer.addSeriesRenderer(renderer);
}
chartView = ChartFactory.getPieChartView(this, series, new DefaultRenderer());
chartView.repaint();
return chartView;
}
Now you can add this GraphicalView to your view.
The returned object is much like a map, with key/value pairs. In your example, the key is "value", which makes it a little confusing, but it would be like this if you wanted all fields:
for (Field field : myInstance.getClass().getDeclaredFields()) {
String name = field.getName();
value = field.get(myInstance).toString();
map.put(name, value);
}