diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index afc4323c9..9f2e83234 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -76,6 +76,7 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.Container; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.text.ParseException; import com.jpexs.decompiler.flash.types.GLYPHENTRY; @@ -161,7 +162,9 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi public FlashPlayerPanel flashPanel; public JPanel displayPanel; public ImagePanel imagePanel; + public ImagePanel shapeImagePanel; final static String CARDFLASHPANEL = "Flash card"; + final static String CARDSHAPEPANEL = "Shape card"; final static String CARDIMAGEPANEL = "Image card"; final static String CARDEMPTYPANEL = "Empty card"; final static String CARDACTIONSCRIPTPANEL = "ActionScript card"; @@ -628,6 +631,12 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi imagesCard.add(imageButtonsPanel, BorderLayout.SOUTH); displayPanel.add(imagesCard, CARDIMAGEPANEL); + + JPanel shapesCard = new JPanel(new BorderLayout()); + shapeImagePanel = new ImagePanel(); + shapesCard.add(shapeImagePanel, BorderLayout.CENTER); + displayPanel.add(shapesCard, CARDSHAPEPANEL); + displayPanel.add(new JPanel(), CARDEMPTYPANEL); if (actionPanel != null) { displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); @@ -1814,6 +1823,9 @@ public class MainFrame extends JFrame implements ActionListener, TreeSelectionLi imageButtonsPanel.setVisible(((ImageTag) tagObj).importSupported()); showCard(CARDIMAGEPANEL); imagePanel.setImage(((ImageTag) tagObj).getImage(swf.tags)); + } else if (tagObj instanceof ShapeTag) { + showCard(CARDSHAPEPANEL); + shapeImagePanel.setImage(((ShapeTag) tagObj).toImage(swf.tags)); } else if ((tagObj instanceof FrameNode && ((FrameNode) tagObj).isDisplayed()) || (((tagObj instanceof CharacterTag) || (tagObj instanceof FontTag)) && (tagObj instanceof Tag))) { try { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index c80ff571e..778f571af 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -22,9 +22,11 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Set; public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTag { @@ -53,6 +55,11 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa return shapes.toSVG(2); } + @Override + public BufferedImage toImage(List tags) { + return shapes.toImage(2, tags); + } + @Override public int getCharacterID() { return shapeId; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 84cee3cca..6d8689197 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -22,9 +22,11 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Set; public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTag { @@ -58,6 +60,11 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa return shapes.toSVG(3); } + @Override + public BufferedImage toImage(List tags) { + return shapes.toImage(3, tags); + } + @Override public int getCharacterID() { return shapeId; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index feaa26cd0..0202b0463 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -22,9 +22,11 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Set; public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTag { @@ -57,6 +59,11 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa return shapes.toSVG(4); } + @Override + public BufferedImage toImage(List tags) { + return shapes.toImage(4, tags); + } + @Override public int getCharacterID() { return shapeId; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index c0a6e2493..b9c955990 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -22,9 +22,11 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Set; public class DefineShapeTag extends CharacterTag implements BoundedTag, ShapeTag { @@ -70,4 +72,9 @@ public class DefineShapeTag extends CharacterTag implements BoundedTag, ShapeTag public String toSVG() { return shapes.toSVG(1); } + + @Override + public BufferedImage toImage(List tags) { + return shapes.toImage(1, tags); + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index 08e15eb05..06855602d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -16,7 +16,10 @@ */ package com.jpexs.decompiler.flash.tags.base; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import java.awt.image.BufferedImage; +import java.util.List; /** * @@ -29,4 +32,6 @@ public interface ShapeTag { public String toSVG(); public int getShapeNum(); + + public BufferedImage toImage(List tags); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java b/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java index 6eb3901c7..783a296ed 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/MATRIX.java @@ -65,7 +65,7 @@ public class MATRIX implements Serializable { @Override public String toString() { - return "[MATRIX scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]"; + return "[MATRIX scale:" + getScaleXFloat() + "," + getScaleYFloat() + ", rotate:" + getRotateSkew0Float() + "," + getRotateSkew1Float() + ", translate:" + translateX + "," + translateY + "]"; } public float toFloat(int i) { @@ -79,6 +79,22 @@ public class MATRIX implements Serializable { return ret; } + public float getRotateSkew0Float() { + return (hasRotate ? toFloat(rotateSkew0) : 0); + } + + public float getRotateSkew1Float() { + return (hasRotate ? toFloat(rotateSkew1) : 0); + } + + public float getScaleXFloat() { + return (hasScale ? toFloat(scaleX) : 1); + } + + public float getScaleYFloat() { + return (hasScale ? toFloat(scaleY) : 1); + } + public MATRIX merge(MATRIX m) { MATRIX ret = new MATRIX(); ret.translateX = m.translateX + this.translateX; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java index aa6c2cd2a..6505b647a 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -16,8 +16,10 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import java.awt.image.BufferedImage; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -51,6 +53,10 @@ public class SHAPE implements NeedsCharacters { return SHAPERECORD.shapeToSVG(shapeNum, null, null, numFillBits, numLineBits, shapeRecords); } + public BufferedImage toImage(int shapeNum, List tags) { + return SHAPERECORD.shapeToImage(tags, shapeNum, null, null, numFillBits, numLineBits, shapeRecords); + } + public RECT getBounds() { return SHAPERECORD.getBounds(shapeRecords); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index d94d0dc4b..a35cae70f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -16,8 +16,10 @@ */ package com.jpexs.decompiler.flash.types; +import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import java.awt.image.BufferedImage; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -54,6 +56,10 @@ public class SHAPEWITHSTYLE implements NeedsCharacters { return SHAPERECORD.shapeToSVG(shapeNum, fillStyles, lineStyles, numFillBits, numLineBits, shapeRecords); } + public BufferedImage toImage(int shapeNum, List tags) { + return SHAPERECORD.shapeToImage(tags, shapeNum, fillStyles, lineStyles, numFillBits, numLineBits, shapeRecords); + } + public RECT getBounds() { return SHAPERECORD.getBounds(shapeRecords); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index cbdc615a4..bbe0ccc24 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -16,13 +16,31 @@ */ package com.jpexs.decompiler.flash.types.shaperecords; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.GRADIENT; import com.jpexs.decompiler.flash.types.LINESTYLE; import com.jpexs.decompiler.flash.types.LINESTYLE2; import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.LinearGradientPaint; +import java.awt.MultipleGradientPaint.CycleMethod; +import java.awt.Point; +import java.awt.RadialGradientPaint; +import java.awt.Rectangle; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -55,6 +73,282 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters { public FILLSTYLE fillStyle1; public List edges = new ArrayList(); + public void draw(int startX, int startY, Graphics2D g, int shapeNum) { + AffineTransform oldAf = g.getTransform(); + AffineTransform trans20 = AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0); + //g.setTransform(trans20); + boolean ok = false; + if (shapeNum == 4) { + if (lineStyle2 == null) { + ok = false; + } else if (!lineStyle2.hasFillFlag) { + g.setPaint(new Color(lineStyle2.color.red, lineStyle2.color.green, lineStyle2.color.blue, lineStyle2.color.alpha)); + int capStyle = 0; + switch (lineStyle2.startCapStyle) { + case LINESTYLE2.NO_CAP: + capStyle = BasicStroke.CAP_BUTT; + break; + case LINESTYLE2.ROUND_CAP: + capStyle = BasicStroke.CAP_ROUND; + break; + case LINESTYLE2.SQUARE_CAP: + capStyle = BasicStroke.CAP_SQUARE; + break; + } + int joinStyle = 0; + switch (lineStyle2.joinStyle) { + case LINESTYLE2.BEVEL_JOIN: + joinStyle = BasicStroke.JOIN_BEVEL; + break; + case LINESTYLE2.MITER_JOIN: + joinStyle = BasicStroke.JOIN_MITER; + break; + case LINESTYLE2.ROUND_JOIN: + joinStyle = BasicStroke.JOIN_ROUND; + break; + } + if (joinStyle == BasicStroke.JOIN_MITER) { + g.setStroke(new BasicStroke(lineStyle2.width / 20, capStyle, joinStyle, lineStyle2.miterLimitFactor)); + } else { + g.setStroke(new BasicStroke(lineStyle2.width / 20, capStyle, joinStyle)); + } + ok = true; + } + } else { + if (lineStyle == null) { + ok = false; + } else { + g.setStroke(new BasicStroke(lineStyle.width / 20, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + ok = true; + } + } + if (ok) { + g.draw(trans20.createTransformedShape(toGeneralPath(startX, startY))); + } + g.setTransform(oldAf); + g.setClip(null); + } + + private AffineTransform matrixToTransform(MATRIX mat) { + return new AffineTransform(mat.getScaleXFloat(), mat.getRotateSkew0Float(), + mat.getRotateSkew1Float(), mat.getScaleYFloat(), + mat.translateX, mat.translateY); + //mat.translateX,mat.translateY); + /*AffineTransform move=AffineTransform.getTranslateInstance(mat.translateX, mat.translateY); + AffineTransform rotate =AffineTransform.getRotateInstance(mat.getRotateSkew0Float(), mat.getRotateSkew1Float()); + AffineTransform scale=AffineTransform.getScaleInstance(mat.getScaleXFloat(), mat.getScaleYFloat()); + AffineTransform af=scale; + AffineTransform scale20=AffineTransform.getScaleInstance(1/20.0, 1/20.0); + + //af.concatenate(move); + //af.concatenate(scale20); + af.concatenate(rotate); + af.concatenate(scale); + return af;*/ + } + + public void fill(List tags, int startX, int startY, Graphics2D g, int shapeNum) { + AffineTransform oldAf = g.getTransform(); + AffineTransform trans20 = AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0); + g.setTransform(trans20); + int maxRepeat = 200; + boolean ok = false; + switch (fillStyle0.fillStyleType) { + case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP: + case FILLSTYLE.REPEATING_BITMAP: + case FILLSTYLE.CLIPPED_BITMAP: + case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP: + ImageTag image = null; + for (Tag t : tags) { + if (t instanceof ImageTag) { + ImageTag i = (ImageTag) t; + if (i.getCharacterID() == fillStyle0.bitmapId) { + image = i; + break; + } + } + } + if (image != null) { + g.setClip(toGeneralPath(startX, startY)); + AffineTransform btrans = matrixToTransform(fillStyle0.bitmapMatrix); + btrans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0)); + btrans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20)); + g.setTransform(btrans); + BufferedImage img = image.getImage(tags); + g.setPaint(new TexturePaint(img, new Rectangle(img.getWidth(), img.getHeight()))); + g.fill(new Rectangle(-16384 * maxRepeat, -16384 * maxRepeat, 16384 * 2 * maxRepeat, 16384 * 2 * maxRepeat)); + g.setTransform(oldAf); + g.setClip(null); + } + break; + case FILLSTYLE.FOCAL_RADIAL_GRADIENT: + float focRadFractions[] = new float[fillStyle0.focalGradient.gradientRecords.length]; + Color focRadColors[] = new Color[fillStyle0.focalGradient.gradientRecords.length]; + for (int i = 0; i < fillStyle0.focalGradient.gradientRecords.length; i++) { + focRadFractions[i] = fillStyle0.focalGradient.gradientRecords[i].getRatioFloat(); + if (shapeNum >= 3) { + focRadColors[i] = new Color(fillStyle0.focalGradient.gradientRecords[i].colorA.red, fillStyle0.focalGradient.gradientRecords[i].colorA.green, fillStyle0.focalGradient.gradientRecords[i].colorA.blue, fillStyle0.focalGradient.gradientRecords[i].colorA.alpha); + } else { + focRadColors[i] = new Color(fillStyle0.focalGradient.gradientRecords[i].color.red, fillStyle0.focalGradient.gradientRecords[i].color.green, fillStyle0.focalGradient.gradientRecords[i].color.blue); + } + } + RGB focEndColor = fillStyle0.focalGradient.gradientRecords[fillStyle0.focalGradient.gradientRecords.length - 1].color; + RGBA focEndColorA = fillStyle0.focalGradient.gradientRecords[fillStyle0.focalGradient.gradientRecords.length - 1].colorA; + if (shapeNum >= 3) { + g.setPaint(new Color(focEndColorA.red, focEndColorA.green, focEndColorA.blue, focEndColorA.alpha)); + } else { + g.setPaint(new Color(focEndColor.red, focEndColor.green, focEndColor.blue)); + } + GeneralPath focPath = toGeneralPath(startX, startY); + g.fill(focPath); + g.setClip(focPath); + AffineTransform focTrans = matrixToTransform(fillStyle0.gradientMatrix); + focTrans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0)); + focTrans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20)); + g.setTransform(focTrans); + CycleMethod cm = CycleMethod.NO_CYCLE; + if (fillStyle0.focalGradient.spreadMode == GRADIENT.SPREAD_PAD_MODE) { + cm = CycleMethod.NO_CYCLE; + } else if (fillStyle0.focalGradient.spreadMode == GRADIENT.SPREAD_REFLECT_MODE) { + cm = CycleMethod.REFLECT; + } else if (fillStyle0.focalGradient.spreadMode == GRADIENT.SPREAD_REPEAT_MODE) { + cm = CycleMethod.REPEAT; + } + + + g.setPaint(new RadialGradientPaint(new Point(0, 0), 16384, new Point((int) (fillStyle0.focalGradient.focalPoint * 16384), 0), focRadFractions, focRadColors, cm)); + g.fill(new Rectangle(-16384 * maxRepeat, -16384 * maxRepeat, 16384 * 2 * maxRepeat, 16384 * 2 * maxRepeat)); + g.setTransform(oldAf); + g.setClip(null); + return; + case FILLSTYLE.RADIAL_GRADIENT: + float radFractions[] = new float[fillStyle0.gradient.gradientRecords.length]; + Color radColors[] = new Color[fillStyle0.gradient.gradientRecords.length]; + for (int i = 0; i < fillStyle0.gradient.gradientRecords.length; i++) { + radFractions[i] = fillStyle0.gradient.gradientRecords[i].getRatioFloat(); + if (shapeNum >= 3) { + radColors[i] = new Color(fillStyle0.gradient.gradientRecords[i].colorA.red, fillStyle0.gradient.gradientRecords[i].colorA.green, fillStyle0.gradient.gradientRecords[i].colorA.blue, fillStyle0.gradient.gradientRecords[i].colorA.alpha); + } else { + radColors[i] = new Color(fillStyle0.gradient.gradientRecords[i].color.red, fillStyle0.gradient.gradientRecords[i].color.green, fillStyle0.gradient.gradientRecords[i].color.blue); + } + } + RGB endColor = fillStyle0.gradient.gradientRecords[fillStyle0.gradient.gradientRecords.length - 1].color; + RGBA endColorA = fillStyle0.gradient.gradientRecords[fillStyle0.gradient.gradientRecords.length - 1].colorA; + if (shapeNum >= 3) { + g.setPaint(new Color(endColorA.red, endColorA.green, endColorA.blue, endColorA.alpha)); + } else { + g.setPaint(new Color(endColor.red, endColor.green, endColor.blue)); + } + GeneralPath path = toGeneralPath(startX, startY); + g.fill(path); + g.setClip(path); + AffineTransform trans = matrixToTransform(fillStyle0.gradientMatrix); + trans.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0)); + trans.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20)); + g.setTransform(trans); + + CycleMethod cmRad = CycleMethod.NO_CYCLE; + if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_PAD_MODE) { + cmRad = CycleMethod.NO_CYCLE; + } else if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_REFLECT_MODE) { + cmRad = CycleMethod.REFLECT; + } else if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_REPEAT_MODE) { + cmRad = CycleMethod.REPEAT; + } + + g.setPaint(new RadialGradientPaint(new Point(0, 0), 16384, radFractions, radColors, cmRad)); + g.fill(new Rectangle(-16384 * maxRepeat, -16384 * maxRepeat, 16384 * 2 * maxRepeat, 16384 * 2 * maxRepeat)); + g.setTransform(oldAf); + g.setClip(null); + return; + case FILLSTYLE.LINEAR_GRADIENT: + float fractions[] = new float[fillStyle0.gradient.gradientRecords.length]; + Color colors[] = new Color[fillStyle0.gradient.gradientRecords.length]; + for (int i = 0; i < fillStyle0.gradient.gradientRecords.length; i++) { + fractions[i] = fillStyle0.gradient.gradientRecords[i].getRatioFloat(); + if (shapeNum >= 3) { + colors[i] = new Color(fillStyle0.gradient.gradientRecords[i].colorA.red, fillStyle0.gradient.gradientRecords[i].colorA.green, fillStyle0.gradient.gradientRecords[i].colorA.blue, fillStyle0.gradient.gradientRecords[i].colorA.alpha); + } else { + colors[i] = new Color(fillStyle0.gradient.gradientRecords[i].color.red, fillStyle0.gradient.gradientRecords[i].color.green, fillStyle0.gradient.gradientRecords[i].color.blue); + } + } + GeneralPath pathLin = toGeneralPath(startX, startY); + g.fill(pathLin); + g.setClip(pathLin); + AffineTransform transLin = matrixToTransform(fillStyle0.gradientMatrix); + transLin.preConcatenate(AffineTransform.getScaleInstance(1 / 20.0, 1 / 20.0)); + transLin.preConcatenate(AffineTransform.getTranslateInstance(startX / 20, startY / 20)); + g.setTransform(transLin); + + CycleMethod cmLin = CycleMethod.NO_CYCLE; + if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_PAD_MODE) { + cmLin = CycleMethod.NO_CYCLE; + } else if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_REFLECT_MODE) { + cmLin = CycleMethod.REFLECT; + } else if (fillStyle0.gradient.spreadMode == GRADIENT.SPREAD_REPEAT_MODE) { + cmLin = CycleMethod.REPEAT; + } + + + g.setPaint(new LinearGradientPaint(new Point(-16384, 0), new Point(16384, 0), fractions, colors, cmLin)); + g.fill(new Rectangle(-16384 * maxRepeat, -16384 * maxRepeat, 16384 * 2 * maxRepeat, 16384 * 2 * maxRepeat)); + g.setTransform(oldAf); + g.setClip(null); + ok = true; + return; + case FILLSTYLE.SOLID: + Color c = null; + if (shapeNum >= 3) { + c = new Color(fillStyle0.colorA.red, fillStyle0.colorA.green, fillStyle0.colorA.blue, fillStyle0.colorA.alpha); + } else { + c = new Color(fillStyle0.color.red, fillStyle0.color.green, fillStyle0.color.blue); + } + g.setPaint(c); + ok = true; + break; + } + if (ok) { + GeneralPath path = toGeneralPath(startX, startY); + g.fill(path); + } + g.setTransform(oldAf); + g.setClip(null); + } + + public void drawTo(List tags, int startX, int startY, Graphics2D g, int shapeNum) { + fill(tags, startX, startY, g, shapeNum); + draw(startX, startY, g, shapeNum); + } + + public GeneralPath toGeneralPath(int startX, int startY) { + + GeneralPath ret = new GeneralPath(); + int x = startX; + int y = startY; + for (SHAPERECORD rec : edges) { + int nx = rec.changeX(x); + int ny = rec.changeY(y); + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateMoveTo) { + nx += startX; + ny += startY; + ret.moveTo(nx, ny); + } + } + if (rec instanceof StraightEdgeRecord) { + ret.lineTo(nx, ny); + } + if (rec instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) rec; + ret.quadTo((x + cer.controlDeltaX), (y + cer.controlDeltaY), (x + cer.controlDeltaX + cer.anchorDeltaX), (y + cer.controlDeltaY + cer.anchorDeltaY)); + } + x = nx; + y = ny; + } + return ret; + } + public boolean sameStyle(Path p) { return fillStyle0 == p.fillStyle0 && ((useLineStyle2 && (p.lineStyle2 == lineStyle2)) || ((!useLineStyle2) && (p.lineStyle == lineStyle))); } @@ -128,19 +422,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters { return new RECT(min_x, max_x, min_y, max_y); } - /** - * Convert shape to SVG - * - * @param shapeNum - * @param fillStyles - * @param lineStylesList - * @param numFillBits - * @param numLineBits - * @param records - * @return Shape converted to SVG - */ - public static String shapeToSVG(int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List records) { - String ret = ""; + private static List getPaths(RECT bounds, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List records) { List paths = new ArrayList(); Path path = new Path(); int x = 0; @@ -267,20 +549,53 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters { paths3.add(p1); } } + bounds.Xmax = max_x; + bounds.Ymax = max_y; + bounds.Xmin = min_x; + bounds.Ymin = min_y; + return paths3; + } + + /** + * Convert shape to SVG + * + * @param shapeNum + * @param fillStyles + * @param lineStylesList + * @param numFillBits + * @param numLineBits + * @param records + * @return Shape converted to SVG + */ + public static String shapeToSVG(int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List records) { + String ret = ""; + RECT bounds = new RECT(); + List paths = getPaths(bounds, shapeNum, fillStyles, lineStylesList, numFillBits, numLineBits, records); ret = ""; - for (Path p : paths3) { + for (Path p : paths) { ret += p.toSVG(shapeNum); } ret = " \n" + "\n" - + "" + ret + "" + ""; return ret; } + public static BufferedImage shapeToImage(List tags, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, int numFillBits, int numLineBits, List records) { + RECT rect = new RECT(); + List paths = getPaths(rect, shapeNum, fillStyles, lineStylesList, numFillBits, numLineBits, records); + BufferedImage ret = new BufferedImage(rect.getWidth() / 20 + 2, rect.getHeight() / 20 + 2, BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D g = (Graphics2D) ret.getGraphics(); + for (Path p : paths) { + p.drawTo(tags, -rect.Xmin, -rect.Ymin, g, shapeNum); + } + return ret; + } + public abstract boolean isMove(); }