diff --git a/trunk/src/com/jpexs/asdec/gui/TagPanel.java b/trunk/src/com/jpexs/asdec/gui/TagPanel.java index aecfcc841..7a856601e 100644 --- a/trunk/src/com/jpexs/asdec/gui/TagPanel.java +++ b/trunk/src/com/jpexs/asdec/gui/TagPanel.java @@ -14,8 +14,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.gui; import com.jpexs.asdec.SWF; @@ -28,6 +26,11 @@ import com.jpexs.asdec.tags.DefineBitsLosslessTag; import com.jpexs.asdec.tags.DefineBitsTag; import com.jpexs.asdec.tags.DefineMorphShape2Tag; import com.jpexs.asdec.tags.DefineMorphShapeTag; +import com.jpexs.asdec.tags.DefineShape2Tag; +import com.jpexs.asdec.tags.DefineShape3Tag; +import com.jpexs.asdec.tags.DefineShape4Tag; +import com.jpexs.asdec.tags.DefineShapeTag; +import com.jpexs.asdec.tags.DefineSpriteTag; import com.jpexs.asdec.tags.DefineTextTag; import com.jpexs.asdec.tags.EndTag; import com.jpexs.asdec.tags.JPEGTablesTag; @@ -132,7 +135,7 @@ public class TagPanel extends JPanel implements ListSelectionListener { swtPanel.setBackground(Color.white); displayPanel.add(swtPanel, CARDFLASHPANEL); } - imagePanel = new ImagePanel(); + imagePanel = new ImagePanel(); displayPanel.add(imagePanel, CARDIMAGEPANEL); displayPanel.add(new JPanel(), CARDEMPTYPANEL); CardLayout cl = (CardLayout) (displayPanel.getLayout()); @@ -217,8 +220,13 @@ public class TagPanel extends JPanel implements ListSelectionListener { mat.hasScale = false; mat.translateX = 0; mat.translateY = 0; - if (tagObj instanceof BoundedTag) { - RECT r = ((BoundedTag) tagObj).getRect(); + if ((tagObj instanceof BoundedTag) || (tagObj instanceof DefineSpriteTag)) { + RECT r = null; + if (tagObj instanceof DefineSpriteTag) { + r = ((DefineSpriteTag) tagObj).getRect(characters); + } else { + r = ((BoundedTag) tagObj).getRect(); + } mat.translateX = -r.Xmin; mat.translateY = -r.Ymin; mat.translateX = mat.translateX + width / 2 - r.getWidth() / 2; diff --git a/trunk/src/com/jpexs/asdec/tags/DefineSpriteTag.java b/trunk/src/com/jpexs/asdec/tags/DefineSpriteTag.java index 203ff1ad0..a3031e8a1 100644 --- a/trunk/src/com/jpexs/asdec/tags/DefineSpriteTag.java +++ b/trunk/src/com/jpexs/asdec/tags/DefineSpriteTag.java @@ -14,21 +14,24 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.tags; import com.jpexs.asdec.Main; import com.jpexs.asdec.SWFInputStream; import com.jpexs.asdec.SWFOutputStream; import com.jpexs.asdec.abc.CopyOutputStream; +import com.jpexs.asdec.tags.base.BoundedTag; import com.jpexs.asdec.tags.base.CharacterTag; import com.jpexs.asdec.tags.base.Container; +import com.jpexs.asdec.types.MATRIX; +import com.jpexs.asdec.types.RECT; +import java.awt.Point; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -57,6 +60,64 @@ public class DefineSpriteTag extends CharacterTag implements Container { return spriteId; } + private RECT getCharacterBounds(HashMap allCharacters, Set characters) { + RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE,Integer.MIN_VALUE); + for (int c : characters) { + Tag t = allCharacters.get(c); + RECT r = null; + if (t instanceof BoundedTag) { + r = ((BoundedTag) t).getRect(); + } else if (t instanceof DefineSpriteTag) { + r = ((DefineSpriteTag) t).getRect(allCharacters); + } + if (r != null) { + ret.Xmin = Math.min(r.Xmin, ret.Xmin); + ret.Ymin = Math.min(r.Ymin, ret.Ymin); + ret.Xmax = Math.max(r.Xmax, ret.Xmax); + ret.Ymax = Math.max(r.Ymax, ret.Ymax); + } + } + return ret; + } + + public RECT getRect(HashMap characters) { + RECT ret = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE,Integer.MIN_VALUE); + for (Tag t : subTags) { + Set needed = t.getNeededCharacters(); + if(needed.isEmpty()){ + continue; + } + RECT r = getCharacterBounds(characters, needed); + MATRIX m = null; + if (t instanceof PlaceObjectTag) { + m = ((PlaceObjectTag) t).matrix; + } + if (t instanceof PlaceObject2Tag) { + if (((PlaceObject2Tag) t).placeFlagHasMatrix) { + m = ((PlaceObject2Tag) t).matrix; + } + } + if (t instanceof PlaceObject3Tag) { + if (((PlaceObject3Tag) t).placeFlagHasMatrix) { + m = ((PlaceObject3Tag) t).matrix; + } + } + if (m != null) { + Point topleft = m.apply(new Point(r.Xmin, r.Ymin)); + Point bottomright = m.apply(new Point(r.Xmax, r.Ymax)); + r.Xmin=Math.min(topleft.x,bottomright.x); + r.Ymin=Math.min(topleft.y,bottomright.y); + r.Xmax=Math.max(topleft.x,bottomright.x); + r.Ymax=Math.max(topleft.y,bottomright.y); + } + ret.Xmin = Math.min(r.Xmin, ret.Xmin); + ret.Ymin = Math.min(r.Ymin, ret.Ymin); + ret.Xmax = Math.max(r.Xmax, ret.Xmax); + ret.Ymax = Math.max(r.Ymax, ret.Ymax); + } + return ret; + } + /** * Constructor * diff --git a/trunk/src/com/jpexs/asdec/types/LINESTYLEARRAY.java b/trunk/src/com/jpexs/asdec/types/LINESTYLEARRAY.java index b751cc699..fd60c4f91 100644 --- a/trunk/src/com/jpexs/asdec/types/LINESTYLEARRAY.java +++ b/trunk/src/com/jpexs/asdec/types/LINESTYLEARRAY.java @@ -23,7 +23,7 @@ package com.jpexs.asdec.types; * @author JPEXS */ public class LINESTYLEARRAY { - + public LINESTYLE lineStyles[]; public LINESTYLE2 lineStyles2[]; } diff --git a/trunk/src/com/jpexs/asdec/types/MATRIX.java b/trunk/src/com/jpexs/asdec/types/MATRIX.java index 72d7efd0c..539c0ace4 100644 --- a/trunk/src/com/jpexs/asdec/types/MATRIX.java +++ b/trunk/src/com/jpexs/asdec/types/MATRIX.java @@ -14,10 +14,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.types; +import java.awt.Point; + /** * Represents a standard 2x3 transformation matrix of the sort commonly used in * 2D graphics @@ -66,4 +66,15 @@ public class MATRIX { public String toString() { return "[MATRIX scale:" + scaleX + "," + scaleY + ", rotate:" + rotateSkew0 + "," + rotateSkew1 + ", translate:" + translateX + "," + translateY + "]"; } + + private float toFloat(int i){ + return ((float)i)/(1<<16); + } + + public Point apply(Point p) { + Point ret = new Point(); + ret.x = (int)(p.x * (hasScale?toFloat(scaleX):1) + p.y * (hasRotate?toFloat(rotateSkew1):0) + translateX); + ret.y = (int) (p.x * (hasRotate?toFloat(rotateSkew0):0) + p.y * (hasScale?toFloat(scaleY):1) + translateY); + return ret; + } } diff --git a/trunk/src/com/jpexs/asdec/types/RGB.java b/trunk/src/com/jpexs/asdec/types/RGB.java index f77caf15e..0ad1e12c0 100644 --- a/trunk/src/com/jpexs/asdec/types/RGB.java +++ b/trunk/src/com/jpexs/asdec/types/RGB.java @@ -46,4 +46,20 @@ public class RGB { public RGB() { } + + public String toHexRGB(){ + String rh=Integer.toHexString(red); + if(rh.length()<2){ + rh="0"+rh; + } + String gh=Integer.toHexString(green); + if(gh.length()<2){ + gh="0"+gh; + } + String bh=Integer.toHexString(blue); + if(bh.length()<2){ + bh="0"+bh; + } + return "#"+rh+gh+bh; + } } diff --git a/trunk/src/com/jpexs/asdec/types/RGBA.java b/trunk/src/com/jpexs/asdec/types/RGBA.java index c14ea2320..d69a14acf 100644 --- a/trunk/src/com/jpexs/asdec/types/RGBA.java +++ b/trunk/src/com/jpexs/asdec/types/RGBA.java @@ -41,4 +41,20 @@ public class RGBA { * Alpha value defining opacity */ public int alpha; + + public String toHexRGB(){ + String rh=Integer.toHexString(red); + if(rh.length()<2){ + rh="0"+rh; + } + String gh=Integer.toHexString(green); + if(gh.length()<2){ + gh="0"+gh; + } + String bh=Integer.toHexString(blue); + if(bh.length()<2){ + bh="0"+bh; + } + return "#"+rh+gh+bh; + } } diff --git a/trunk/src/com/jpexs/asdec/types/SHAPE.java b/trunk/src/com/jpexs/asdec/types/SHAPE.java index 3d5a21ed5..a36981139 100644 --- a/trunk/src/com/jpexs/asdec/types/SHAPE.java +++ b/trunk/src/com/jpexs/asdec/types/SHAPE.java @@ -30,4 +30,17 @@ public class SHAPE { public int numFillBits; public int numLineBits; public List shapeRecords; + + /** + * EXPERIMENTAL + * @param shapeNum + * @return + */ + public String toSVG(int shapeNum){ + return SHAPERECORD.shapeToSVG(shapeNum,null, null, numFillBits, numLineBits, shapeRecords); + } + + public RECT getBounds(){ + return SHAPERECORD.getBounds(shapeRecords); + } } diff --git a/trunk/src/com/jpexs/asdec/types/SHAPEWITHSTYLE.java b/trunk/src/com/jpexs/asdec/types/SHAPEWITHSTYLE.java index 0bb94f329..d52801ae0 100644 --- a/trunk/src/com/jpexs/asdec/types/SHAPEWITHSTYLE.java +++ b/trunk/src/com/jpexs/asdec/types/SHAPEWITHSTYLE.java @@ -32,4 +32,17 @@ public class SHAPEWITHSTYLE { public int numFillBits; public int numLineBits; public List shapeRecords; + + /** + * EXPERIMENTAL + * @param shapeNum + * @return + */ + public String toSVG(int shapeNum){ + return SHAPERECORD.shapeToSVG(shapeNum,fillStyles, lineStyles, numFillBits, numLineBits, shapeRecords); + } + + public RECT getBounds(){ + return SHAPERECORD.getBounds(shapeRecords); + } } diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/CurvedEdgeRecord.java b/trunk/src/com/jpexs/asdec/types/shaperecords/CurvedEdgeRecord.java index df98ae77a..3a7663618 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/CurvedEdgeRecord.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/CurvedEdgeRecord.java @@ -22,7 +22,7 @@ package com.jpexs.asdec.types.shaperecords; * * @author JPEXS */ -public class CurvedEdgeRecord implements SHAPERECORD { +public class CurvedEdgeRecord extends SHAPERECORD { public int typeFlag = 1; public int straightFlag = 0; diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/EndShapeRecord.java b/trunk/src/com/jpexs/asdec/types/shaperecords/EndShapeRecord.java index e829fdc4e..ef68b9a1c 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/EndShapeRecord.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/EndShapeRecord.java @@ -22,7 +22,7 @@ package com.jpexs.asdec.types.shaperecords; * * @author JPEXS */ -public class EndShapeRecord implements SHAPERECORD { +public class EndShapeRecord extends SHAPERECORD { public int typeFlag = 0; public int endOfShape = 0; diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java b/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java index 54e3732fe..e4af8cc7e 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/SHAPERECORD.java @@ -14,13 +14,250 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - - package com.jpexs.asdec.types.shaperecords; +import com.jpexs.asdec.types.FILLSTYLE; +import com.jpexs.asdec.types.FILLSTYLEARRAY; +import com.jpexs.asdec.types.LINESTYLE; +import com.jpexs.asdec.types.LINESTYLE2; +import com.jpexs.asdec.types.LINESTYLEARRAY; +import com.jpexs.asdec.types.RECT; +import com.jpexs.asdec.types.RGB; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + /** * * @author JPEXS */ -public interface SHAPERECORD { +public abstract class SHAPERECORD { + + public static float twipToPixel(int twip) { + return ((float) twip) / 20.0f; + } + + private static class Path { + public LINESTYLE lineStyle; + public LINESTYLE2 lineStyle2; + public boolean useLineStyle2; + public FILLSTYLE fillStyle0; + public FILLSTYLE fillStyle1; + public String points; + } + + public static RECT getBounds(List records){ + int x = 0; + int y = 0; + int max_x = 0; + int max_y = 0; + int min_x = Integer.MAX_VALUE; + int min_y = Integer.MAX_VALUE; + boolean started = false; + for (SHAPERECORD r : records) { + if (r instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) r; + if (scr.stateMoveTo) { + x = scr.moveDeltaX; + y = scr.moveDeltaY; + started = true; + } + } + if (r instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) r; + if (ser.generalLineFlag) { + x += ser.deltaX; + y += ser.deltaY; + started = true; + } else if (ser.vertLineFlag) { + y += ser.deltaY; + started = true; + } else { + x += ser.deltaX; + started = true; + } + } + if (r instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) r; + x += cer.controlDeltaX + cer.anchorDeltaX; + y += cer.controlDeltaY + cer.anchorDeltaY; + started = true; + } + if (x > max_x) { + max_x = x; + } + if (y > max_y) { + max_y = y; + } + if (started) { + if (y < min_y) { + min_y = y; + } + if (x < min_x) { + min_x = x; + } + } + } + return new RECT(min_x,max_x,min_y,max_y); + } + + /** + * EXPERIMENTAL - convert shape to SVG + * + * TODO: Fix fill styles + * + * @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 = ""; + List paths = new ArrayList(); + Path path = new Path(); + boolean styleChanged = false; + int x = 0; + int y = 0; + int max_x = 0; + int max_y = 0; + int min_x = Integer.MAX_VALUE; + int min_y = Integer.MAX_VALUE; + boolean started = false; + for (SHAPERECORD r : records) { + if (r instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) r; + if (scr.stateNewStyles) { + fillStyles = scr.fillStyles; + lineStylesList = scr.lineStyles; + numFillBits = scr.numFillBits; + numLineBits = scr.numLineBits; + } + if (scr.stateFillStyle0) { + styleChanged = true; + if (scr.fillStyle0 == 0) { + path.fillStyle0 = null; + } else { + path.fillStyle0 = fillStyles.fillStyles[scr.fillStyle0 - 1]; + } + } + if (scr.stateFillStyle1) { + styleChanged = true; + if (scr.fillStyle1 == 0) { + path.fillStyle1 = null; + } else { + path.fillStyle1 = fillStyles.fillStyles[scr.fillStyle1 - 1]; + } + } + if (scr.stateLineStyle) { + styleChanged = true; + if (shapeNum>=4) { + path.useLineStyle2 = true; + if (scr.lineStyle == 0) { + path.lineStyle2 = null; + } else { + path.lineStyle2 = lineStylesList.lineStyles2[scr.lineStyle - 1]; + } + } else { + path.useLineStyle2 = false; + if (scr.lineStyle == 0) { + path.lineStyle = null; + } else { + path.lineStyle = lineStylesList.lineStyles[scr.lineStyle - 1]; + } + } + } + if (scr.stateMoveTo) { + ret += "M " + twipToPixel(scr.moveDeltaX) + " " + twipToPixel(scr.moveDeltaY); + x = scr.moveDeltaX; + y = scr.moveDeltaY; + + started = true; + } + } else if (styleChanged) { + styleChanged = false; + path.points = ret; + ret = "M " + twipToPixel(x) + " " + twipToPixel(y); + paths.add(path); + path = new Path(); + } + if (r instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) r; + if (ser.generalLineFlag) { + ret += "l " + twipToPixel(ser.deltaX) + " " + twipToPixel(ser.deltaY); + x += ser.deltaX; + y += ser.deltaY; + started = true; + } else if (ser.vertLineFlag) { + ret += "v " + twipToPixel(ser.deltaY); + y += ser.deltaY; + started = true; + } else { + ret += "h " + twipToPixel(ser.deltaX); + x += ser.deltaX; + started = true; + } + } + if (r instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) r; + ret += "q " + twipToPixel(cer.controlDeltaX) + " " + twipToPixel(cer.controlDeltaY) + " " + twipToPixel(cer.controlDeltaX + cer.anchorDeltaX) + " " + twipToPixel(cer.controlDeltaY + cer.anchorDeltaY); + x += cer.controlDeltaX + cer.anchorDeltaX; + y += cer.controlDeltaY + cer.anchorDeltaY; + started = true; + } + if (x > max_x) { + max_x = x; + } + if (y > max_y) { + max_y = y; + } + if (started) { + if (y < min_y) { + min_y = y; + } + if (x < min_x) { + min_x = x; + } + } + } + path.points = ret; + paths.add(path); + ret = ""; + for (Path p : paths) { + String params = ""; + String f = ""; + if (p.fillStyle0 != null) { + if (p.fillStyle0.fillStyleType == FILLSTYLE.SOLID) { + f = " fill=\"" + ((shapeNum >= 3) ? p.fillStyle0.colorA.toHexRGB() : p.fillStyle0.color.toHexRGB()) + "\""; + } + } else if (p.fillStyle1 != null) { + if (p.fillStyle1.fillStyleType == FILLSTYLE.SOLID) { + f = " fill=\"" + ((shapeNum >= 3) ? p.fillStyle1.colorA.toHexRGB() : p.fillStyle1.color.toHexRGB()) + "\""; + } + } + if (p.fillStyle0 != null && p.fillStyle1 != null) { + Random rnd = new Random(); + f = " fill=\"" + (new RGB(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256))).toHexRGB() + "\""; + } + params += f; + if ((!p.useLineStyle2) && p.lineStyle != null) { + params += " stroke=\"" + ((shapeNum >= 3) ? p.lineStyle.colorA.toHexRGB() : p.lineStyle.color.toHexRGB()) + "\""; + } + if (p.useLineStyle2 && p.lineStyle2 != null) { + params += " stroke-width=\"" + twipToPixel(p.lineStyle2.width) + "\" stroke=\"" + p.lineStyle2.color.toHexRGB() + "\""; + } + ret += ""; + } + ret = " \n" + + "\n" + + "" + ret + "" + + ""; + return ret; + } } diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/StraightEdgeRecord.java b/trunk/src/com/jpexs/asdec/types/shaperecords/StraightEdgeRecord.java index addc3a2d8..f6c47ceb9 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/StraightEdgeRecord.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/StraightEdgeRecord.java @@ -22,7 +22,7 @@ package com.jpexs.asdec.types.shaperecords; * * @author JPEXS */ -public class StraightEdgeRecord implements SHAPERECORD { +public class StraightEdgeRecord extends SHAPERECORD { public int typeFlag = 1; public int straightFlag = 1; diff --git a/trunk/src/com/jpexs/asdec/types/shaperecords/StyleChangeRecord.java b/trunk/src/com/jpexs/asdec/types/shaperecords/StyleChangeRecord.java index ee0e992c7..6480795b0 100644 --- a/trunk/src/com/jpexs/asdec/types/shaperecords/StyleChangeRecord.java +++ b/trunk/src/com/jpexs/asdec/types/shaperecords/StyleChangeRecord.java @@ -25,7 +25,7 @@ import com.jpexs.asdec.types.LINESTYLEARRAY; * * @author JPEXS */ -public class StyleChangeRecord implements SHAPERECORD { +public class StyleChangeRecord extends SHAPERECORD { public int typeFlag = 0; public boolean stateNewStyles;