diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 9285d05ff..abb6533e3 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -94,7 +94,6 @@ import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.Container; import com.jpexs.decompiler.flash.tags.base.ContainerItem; import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.base.RemoveTag; @@ -102,6 +101,7 @@ import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.tags.base.TextTag; +import com.jpexs.decompiler.flash.timeline.Clip; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.Timeline; @@ -177,7 +177,6 @@ import java.util.zip.InflaterInputStream; import javax.imageio.ImageIO; import javax.imageio.stream.FileImageOutputStream; import javax.imageio.stream.ImageOutputStream; -import javax.imageio.stream.MemoryCacheImageOutputStream; import net.kroo.elliot.GifSequenceWriter; import org.monte.media.VideoFormatKeys; import org.monte.media.avi.AVIWriter; @@ -2389,18 +2388,6 @@ public final class SWF implements TreeItem, Timelined { } } - private static class Clip { - - public Shape shape; - public int clipDepth; - - public Clip(Shape clip, int clipDepth) { - this.shape = clip; - this.clipDepth = clipDepth; - } - - } - public static void frameToImage(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { float unzoom = (float) SWF.unitDivisor; if (timeline.frames.size() <= frame) { @@ -2416,7 +2403,7 @@ public final class SWF implements TreeItem, Timelined { for (int i = 1; i <= timeline.getMaxDepth(); i++) { for (int c = 0; c < clips.size(); c++) { - if (clips.get(c).clipDepth == i) { + if (clips.get(c).depth == i) { g.setClip(prevClips.get(c)); prevClips.remove(c); clips.remove(c); @@ -2450,7 +2437,7 @@ public final class SWF implements TreeItem, Timelined { DrawableTag drawable = (DrawableTag) character; SerializableImage img; Matrix drawMatrix = new Matrix(); - int dframe = 0 + (time + layer.time) % drawable.getNumFrames(); + int dframe = (time + layer.time) % drawable.getNumFrames(); if (character instanceof ButtonTag) { ButtonTag bt = (ButtonTag) character; dframe = ButtonTag.FRAME_UP; @@ -2463,64 +2450,56 @@ public final class SWF implements TreeItem, Timelined { } } - if (drawable instanceof BoundedTag) { - BoundedTag bounded = (BoundedTag) drawable; - RECT boundRect = bounded.getRect(); - ExportRectangle rect = new ExportRectangle(boundRect); - rect = mat.transform(rect); - Matrix m = mat.clone(); - if (layer.filters != null) { - // calculate size after applying the filters - double deltaXMax = 0; - double deltaYMax = 0; - for (FILTER filter : layer.filters) { - double x = filter.getDeltaX(); - double y = filter.getDeltaY(); - deltaXMax = Math.max(x, deltaXMax); - deltaYMax = Math.max(y, deltaYMax); - } - rect.xMin -= deltaXMax * SWF.unitDivisor; - rect.xMax += deltaXMax * SWF.unitDivisor; - rect.yMin -= deltaYMax * SWF.unitDivisor; - rect.yMax += deltaYMax * SWF.unitDivisor; + RECT boundRect = drawable.getRect(); + ExportRectangle rect = new ExportRectangle(boundRect); + rect = mat.transform(rect); + Matrix m = mat.clone(); + if (layer.filters != null) { + // calculate size after applying the filters + double deltaXMax = 0; + double deltaYMax = 0; + for (FILTER filter : layer.filters) { + double x = filter.getDeltaX(); + double y = filter.getDeltaY(); + deltaXMax = Math.max(x, deltaXMax); + deltaYMax = Math.max(y, deltaYMax); } - - rect.xMin = Math.max(0, rect.xMin); - rect.yMin = Math.max(0, rect.yMin); - - int newWidth = (int) (rect.getWidth() / SWF.unitDivisor); - int newHeight = (int) (rect.getHeight() / SWF.unitDivisor); - int deltaX = (int) (rect.xMin / SWF.unitDivisor); - int deltaY = (int) (rect.yMin / SWF.unitDivisor); - newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; - newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; - - if (newWidth <= 0 || newHeight <= 0) { - continue; - } - - img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); - img.fillTransparent(); - - m.translate(-rect.xMin, -rect.yMin); - drawMatrix.translate(rect.xMin, rect.yMin); - - drawable.toImage(dframe, layer.time + time, layer.ratio, stateUnderCursor, mouseButton, img, m, clrTrans); - //if(stateUnderCursor == layer){ - /* if(true){ - Graphics2D gg = (Graphics2D)img.getGraphics(); - gg.setStroke(new BasicStroke(3)); - gg.setPaint(Color.red); - gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); - gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(frame, layer.ratio, stateUnderCursor, mouseButton, m))); - }*/ - } else if (drawable instanceof FontTag) { - // only DefineFont tags - FontTag fontTag = (FontTag) drawable; - img = fontTag.toImage(dframe, layer.ratio, transformation, clrTrans); - } else { - throw new Error("Unsupported drawable."); + rect.xMin -= deltaXMax * SWF.unitDivisor; + rect.xMax += deltaXMax * SWF.unitDivisor; + rect.yMin -= deltaYMax * SWF.unitDivisor; + rect.yMax += deltaYMax * SWF.unitDivisor; } + + rect.xMin = Math.max(0, rect.xMin); + rect.yMin = Math.max(0, rect.yMin); + + int newWidth = (int) (rect.getWidth() / SWF.unitDivisor); + int newHeight = (int) (rect.getHeight() / SWF.unitDivisor); + int deltaX = (int) (rect.xMin / SWF.unitDivisor); + int deltaY = (int) (rect.yMin / SWF.unitDivisor); + newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; + newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; + + if (newWidth <= 0 || newHeight <= 0) { + continue; + } + + img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); + img.fillTransparent(); + + m.translate(-rect.xMin, -rect.yMin); + drawMatrix.translate(rect.xMin, rect.yMin); + + drawable.toImage(dframe, layer.time + time, layer.ratio, stateUnderCursor, mouseButton, img, m, clrTrans); + //if(stateUnderCursor == layer){ + /* if(true){ + Graphics2D gg = (Graphics2D)img.getGraphics(); + gg.setStroke(new BasicStroke(3)); + gg.setPaint(Color.red); + gg.setTransform(AffineTransform.getTranslateInstance(0, 0)); + gg.draw(SHAPERECORD.twipToPixelShape(drawable.getOutline(frame, layer.ratio, stateUnderCursor, mouseButton, m))); + }*/ + if (layer.filters != null) { for (FILTER filter : layer.filters) { img = filter.apply(img); diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java index 42c545fed..04f804782 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java @@ -23,13 +23,9 @@ import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.GRADIENT; import com.jpexs.decompiler.flash.types.GRADRECORD; -import com.jpexs.decompiler.flash.types.LINESTYLE; import com.jpexs.decompiler.flash.types.LINESTYLE2; -import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import com.jpexs.helpers.SerializableImage; import java.awt.BasicStroke; import java.awt.Color; @@ -67,13 +63,7 @@ public class BitmapExporter extends ShapeExporterBase implements IShapeExporter private Stroke defaultStroke; private double unitDivisor; - public static SerializableImage export(SWF swf, SHAPE shape, Color defaultColor, ColorTransform colorTransform) { - BitmapExporter exporter = new BitmapExporter(swf, shape, defaultColor, colorTransform); - exporter.export(); - return exporter.getImage(); - } - - public static void exportTo(SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + public static void export(SWF swf, SHAPE shape, Color defaultColor, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { BitmapExporter exporter = new BitmapExporter(swf, shape, defaultColor, colorTransform); exporter.exportTo(image, transformation); } @@ -84,34 +74,6 @@ public class BitmapExporter extends ShapeExporterBase implements IShapeExporter this.defaultColor = defaultColor; } - @Override - public void export() { - List records = shape.shapeRecords; - RECT bounds = SHAPERECORD.getBounds(records); - int maxLineWidthTwips = 0; - if (shape instanceof SHAPEWITHSTYLE) { - SHAPEWITHSTYLE shapeWithStyle = (SHAPEWITHSTYLE) shape; - for (LINESTYLE lineStyle : shapeWithStyle.lineStyles.lineStyles) { - if (lineStyle.width > maxLineWidthTwips) { - maxLineWidthTwips = lineStyle.width; - } - } - } - unitDivisor = SWF.unitDivisor; - double maxLineWidth = maxLineWidthTwips / unitDivisor / 2; - deltaX = bounds.Xmin / unitDivisor - maxLineWidth; - deltaY = bounds.Ymin / unitDivisor - maxLineWidth; - double width = bounds.getWidth() / unitDivisor + 2 * (maxLineWidth + 1); - double height = bounds.getHeight() / unitDivisor + 2 * (maxLineWidth + 1); - image = new SerializableImage((int) width, (int) height, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - - graphics = (Graphics2D) image.getGraphics(); - - defaultStroke = graphics.getStroke(); - super.export(); - } - private void exportTo(SerializableImage image, Matrix transformation) { this.image = image; graphics = (Graphics2D) image.getGraphics(); diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/PathExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/PathExporter.java new file mode 100644 index 000000000..af11f3057 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/PathExporter.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2010-2014 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.exporters; + +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.GRADRECORD; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.SHAPE; +import java.awt.geom.GeneralPath; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class PathExporter extends ShapeExporterBase { + + private final List paths = new ArrayList<>(); + private GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + + private final double unitDivisor = 1; + + public static List export(SHAPE shape) { + PathExporter exporter = new PathExporter(shape, new ColorTransform()); + exporter.export(); + return exporter.paths; + } + + private PathExporter(SHAPE shape, ColorTransform colorTransform) { + super(shape, colorTransform); + } + + @Override + public void export() { + super.export(); + } + + @Override + public void beginShape() { + + } + + @Override + public void endShape(double xMin, double yMin, double xMax, double yMax) { + + } + + @Override + public void beginFills() { + + } + + @Override + public void endFills() { + + } + + @Override + public void beginLines() { + + } + + @Override + public void endLines() { + finalizePath(); + } + + @Override + public void beginFill(RGB color) { + finalizePath(); + } + + @Override + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + finalizePath(); + } + + @Override + public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { + finalizePath(); + } + + @Override + public void endFill() { + finalizePath(); + } + + @Override + public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { + finalizePath(); + } + + @Override + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + + } + + @Override + public void moveTo(double x, double y) { + path.moveTo(x / unitDivisor, y / unitDivisor); + } + + @Override + public void lineTo(double x, double y) { + path.lineTo(x / unitDivisor, y / unitDivisor); + } + + @Override + public void curveTo(double controlX, double controlY, double anchorX, double anchorY) { + path.quadTo(controlX / unitDivisor, controlY / unitDivisor, + anchorX / unitDivisor, anchorY / unitDivisor); + } + + protected void finalizePath() { + paths.add(path); + path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); //For correct intersections display + + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/FontPanel.form b/trunk/src/com/jpexs/decompiler/flash/gui/FontPanel.form index af7a47f55..0d4dba3ef 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/FontPanel.form +++ b/trunk/src/com/jpexs/decompiler/flash/gui/FontPanel.form @@ -14,7 +14,6 @@ - diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index f15c27ee7..0ec53553e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Timeline; @@ -52,7 +51,6 @@ import java.awt.event.MouseListener; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; @@ -122,6 +120,9 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } public Point toImagePoint(Point p) { + if (img == null) { + return null; + } return new Point((p.x - rect.x) * img.getWidth() / rect.width, (p.y - rect.y) * img.getHeight() / rect.height); } @@ -150,6 +151,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } rect = new Rectangle(getWidth() / 2 - w / 2, getHeight() / 2 - h / 2, w, h); + } else { + rect = null; } } @@ -221,13 +224,15 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis m.scale(scale); Point p = e.getPoint(); p = iconPanel.toImagePoint(p); - int x = p.x; - int y = p.y; List objs = new ArrayList<>(); - objs = iconPanel.getObjectsUnderPoint(p); String ret = ""; + if (p != null) { + int x = p.x; + int y = p.y; + objs = iconPanel.getObjectsUnderPoint(p); - ret += " [" + x + "," + y + "] : "; + ret += " [" + x + "," + y + "] : "; + } boolean first = true; for (int i = 0; i < objs.size(); i++) { @@ -468,7 +473,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis soundPlayers.clear(); } - private void nextFrame() { + private void nextFrame(boolean first) { int newframe = frame == timelined.getTimeline().frames.size() - 1 ? 0 : frame + 1; if (stillFrame) { newframe = frame; @@ -480,13 +485,16 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis frame = newframe; time = 0; } else { + if (!first && timelined.getTimeline().isSingleFrame()) { + return; + } time++; } drawFrame(); } private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton) { - String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode()) + "_" + time; + String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode()); SerializableImage img = SWF.getFromCache(key); if (img == null) { if (drawable instanceof BoundedTag) { @@ -497,7 +505,6 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } int width = rect.getWidth(); int height = rect.getHeight(); - double scale = 1.0; SerializableImage image = new SerializableImage((int) (width / SWF.unitDivisor) + 1, (int) (height / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); image.fillTransparent(); @@ -519,18 +526,16 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis }*/ img = image; - } else if (drawable instanceof FontTag) { - // only DefineFont tags - FontTag fontTag = (FontTag) drawable; - img = fontTag.toImage(frame, frame, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform()); } - SWF.putToCache(key, img); + if (drawable.getTimeline().isSingleFrame()) { + SWF.putToCache(key, img); + } } return img; } private void drawFrame() { - if (timelined == null) { + if (timelined == null || timelined.getTimeline().getFrameCount() <= frame) { return; } @@ -539,7 +544,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis mat.translateX = swf.displayRect.Xmin; mat.translateY = swf.displayRect.Ymin; updatePos(lastMouseEvent, false); - BufferedImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton).getBufferedImage(); + SerializableImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton); List sounds = new ArrayList<>(); List soundClasses = new ArrayList<>(); timelined.getTimeline().getSounds(frame, time, stateUnderCursor, mouseButton, sounds, soundClasses); @@ -559,7 +564,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis } } - iconPanel.setImg(new SerializableImage(img)); + iconPanel.setImg(img); } private void playSound(SoundTag st) { @@ -613,9 +618,12 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis if (timelined != null) { timer = new Timer(); timer.schedule(new TimerTask() { + boolean first = true; + @Override public void run() { - nextFrame(); + nextFrame(first); + first = false; } }, 0, 1000 / timelined.getTimeline().frameRate); } else { diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/PreviewImage.java b/trunk/src/com/jpexs/decompiler/flash/gui/PreviewImage.java index e3cdc1b49..7a0f7e0b6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/PreviewImage.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/PreviewImage.java @@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.treeitems.FrameNodeItem; import com.jpexs.decompiler.flash.treeitems.TreeItem; @@ -157,12 +156,7 @@ public class PreviewImage extends JPanel { int height = 0; SerializableImage imgSrc = null; Matrix m = new Matrix(); - if (treeItem instanceof FontTag) { - FontTag fontTag = (FontTag) treeItem; - imgSrc = fontTag.toImage(0, 0, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform()); - width = (imgSrc.getWidth()); - height = (imgSrc.getHeight()); - } else if (treeItem instanceof FrameNodeItem) { + if (treeItem instanceof FrameNodeItem) { FrameNodeItem fn = (FrameNodeItem) treeItem; RECT rect = swf.displayRect; imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.getFrame() - 1, 0, null, 0, rect, Matrix.getScaleInstance(1 / SWF.unitDivisor), new ColorTransform(), null); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index 1c3194ad4..8a2c06047 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -83,6 +83,9 @@ public class DefineButton2Tag extends ButtonTag implements Container { private Timeline timeline; + private boolean isSingleFrameInitialized; + private boolean isSingleFrame; + @Override public int getCharacterId() { return buttonId; @@ -252,6 +255,21 @@ public class DefineButton2Tag extends ButtonTag implements Container { return 1; } + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + @Override public Timeline getTimeline() { if (timeline != null) { diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java index a598c8f81..741a8a58e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineButtonTag.java @@ -87,6 +87,9 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { private Timeline timeline; + private boolean isSingleFrameInitialized; + private boolean isSingleFrame; + @Override public List getRecords() { return characters; @@ -275,6 +278,21 @@ public class DefineButtonTag extends ButtonTag implements ASMSource { return 1; } + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + @Override public GraphTextWriter getActionSourcePrefix(GraphTextWriter writer) { return writer; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index ce90ac618..b92458537 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -957,4 +957,9 @@ public class DefineEditTextTag extends TextTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 20b0ebcb8..0f7f9b8aa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.Matrix; import com.jpexs.decompiler.flash.exporters.Point; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; @@ -59,7 +58,7 @@ import java.util.Set; * * @author JPEXS */ -public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, MorphShapeTag, DrawableTag { +public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag, DrawableTag { @SWFType(BasicType.UI16) public int characterId; @@ -322,7 +321,7 @@ public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, Mo // todo: Currently the generated image is not cached, because the cache // key contains the hashCode of the finalRecord object, and it is always // recreated - BitmapExporter.exportTo(swf, shape, null, image, transformation, colorTransform); + BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); } @Override @@ -337,6 +336,12 @@ public class DefineMorphShape2Tag extends CharacterTag implements BoundedTag, Mo return 65536; } + @Override + public boolean isSingleFrame() { + // Morpshape is a single frame specified with the ratio + return true; + } + @Override public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) { return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 10ed2a36e..529c2cef4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -22,7 +22,6 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.Matrix; import com.jpexs.decompiler.flash.exporters.Point; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; @@ -58,7 +57,7 @@ import java.util.Set; * * @author JPEXS */ -public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, MorphShapeTag, DrawableTag { +public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag, DrawableTag { @SWFType(BasicType.UI16) public int characterId; @@ -305,7 +304,7 @@ public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, Mor // todo: Currently the generated image is not cached, because the cache // key contains the hashCode of the finalRecord object, and it is always // recreated - BitmapExporter.exportTo(swf, shape, null, image, transformation, colorTransform); + BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); } @Override @@ -320,6 +319,12 @@ public class DefineMorphShapeTag extends CharacterTag implements BoundedTag, Mor return 65536; } + @Override + public boolean isSingleFrame() { + // Morpshape is a single frame specified with the ratio + return true; + } + @Override public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) { return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index 291e15006..349d09aaa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -87,4 +87,9 @@ public class DefineShape2Tag extends ShapeTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index f680e25cf..731ac9c0e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -91,4 +91,9 @@ public class DefineShape3Tag extends ShapeTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index 859053a18..d34539353 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -100,4 +100,9 @@ public class DefineShape4Tag extends ShapeTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index c502e0326..30ef1168d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -111,4 +111,9 @@ public class DefineShapeTag extends ShapeTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 6cbb5559c..28be1a6ff 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -54,7 +54,7 @@ import java.util.Set; /** * Defines a sprite character */ -public class DefineSpriteTag extends CharacterTag implements Container, BoundedTag, DrawableTag, Timelined { +public class DefineSpriteTag extends CharacterTag implements Container, DrawableTag, Timelined { /** * Character ID of sprite @@ -75,6 +75,9 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT private Timeline timeline; + private boolean isSingleFrameInitialized; + private boolean isSingleFrame; + @Override public Timeline getTimeline() { if (timeline == null) { @@ -282,6 +285,26 @@ public class DefineSpriteTag extends CharacterTag implements Container, BoundedT return frameCount; } + @Override + public boolean isSingleFrame() { + if (!isSingleFrameInitialized) { + initialiteIsSingleFrame(); + } + return isSingleFrame; + } + + private synchronized void initialiteIsSingleFrame() { + if (!isSingleFrameInitialized) { + if (frameCount > 1) { + isSingleFrameInitialized = true; + return; + } + + isSingleFrame = getTimeline().isSingleFrame(); + isSingleFrameInitialized = true; + } + } + @Override public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) { return getTimeline().getOutline(frame, time, ratio, stateUnderCursor, mouseButton, transformation); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index e15c06d4c..2c892ed24 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -501,4 +501,9 @@ public class DefineText2Tag extends TextTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index b9264af58..032bc8dfe 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -517,4 +517,9 @@ public class DefineTextTag extends TextTag { public int getNumFrames() { return 1; } + + @Override + public boolean isSingleFrame() { + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index 2d0c405c7..9577b8cd6 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -32,7 +32,7 @@ import java.util.List; * * @author JPEXS */ -public abstract class ButtonTag extends CharacterTag implements BoundedTag, DrawableTag, Timelined { +public abstract class ButtonTag extends CharacterTag implements DrawableTag, Timelined { public static int FRAME_UP = 0; public static int FRAME_OVER = 1; diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java index fd129b7a1..f1255ccac 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java @@ -27,7 +27,7 @@ import java.awt.Shape; * * @author JPEXS */ -public interface DrawableTag { +public interface DrawableTag extends BoundedTag { public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform); @@ -35,5 +35,7 @@ public interface DrawableTag { public int getNumFrames(); + public boolean isSingleFrame(); + public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation); } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 4b669be6a..f98b07b40 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -32,10 +32,8 @@ import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import com.jpexs.helpers.SerializableImage; -import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Font; -import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Shape; import java.awt.font.FontRenderContext; @@ -51,7 +49,9 @@ import java.util.Map; * * @author JPEXS */ -public abstract class FontTag extends CharacterTag implements AloneTag, BoundedTag, DrawableTag { +public abstract class FontTag extends CharacterTag implements AloneTag, DrawableTag { + + protected final int previewSize = 500; public FontTag(SWF swf, int id, String name, byte[] data, long pos) { super(swf, id, name, data, pos); @@ -252,15 +252,9 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT return defaultFontName; } - public SerializableImage toImage(int frame, int ratio, Matrix transformation, ColorTransform colorTransform) { - return SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), 500, 500, Color.black, colorTransform); - } - @Override public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - Graphics2D g = (Graphics2D) image.getGraphics(); - g.setComposite(AlphaComposite.SrcOver); - g.drawImage(toImage(0, 0, new Matrix(), colorTransform).getBufferedImage(), transformation.toTransform(), null); + SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, Color.black, colorTransform); } @Override @@ -273,6 +267,11 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT return 1; } + @Override + public boolean isSingleFrame() { + return true; + } + @Override public Shape getOutline(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, Matrix transformation) { RECT r = getRect(); @@ -281,7 +280,7 @@ public abstract class FontTag extends CharacterTag implements AloneTag, BoundedT @Override public RECT getRect() { - return new RECT(0, (int) (500 * SWF.unitDivisor), 0, (int) (500 * SWF.unitDivisor)); + return new RECT(0, (int) (previewSize * SWF.unitDivisor), 0, (int) (previewSize * SWF.unitDivisor)); } } 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 fe063e619..1a319ed90 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -48,6 +48,6 @@ public abstract class ShapeTag extends CharacterTag implements BoundedTag, Drawa @Override public void toImage(int frame, int time, int ratio, DepthState stateUnderCursor, int mouseButton, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - BitmapExporter.exportTo(swf, getShapes(), null, image, transformation, colorTransform); + BitmapExporter.export(swf, getShapes(), null, image, transformation, colorTransform); } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 7bcbbda07..4142298b2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -252,7 +252,7 @@ public abstract class TextTag extends CharacterTag implements BoundedTag, Drawab shape.shapeRecords.add(bottom); shape.shapeRecords.add(left); shape.shapeRecords.add(new EndShapeRecord()); - BitmapExporter.exportTo(swf, shape, null, image, mat, colorTransform); + BitmapExporter.export(swf, shape, null, image, mat, colorTransform); } public static void staticTextToImage(SWF swf, List textRecords, int numText, SerializableImage image, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) { @@ -294,7 +294,7 @@ public abstract class TextTag extends CharacterTag implements BoundedTag, Drawab if (entry.glyphIndex != -1) { // shapeNum: 1 SHAPE shape = glyphs.get(entry.glyphIndex); - BitmapExporter.exportTo(swf, shape, textColor, image, mat, colorTransform); + BitmapExporter.export(swf, shape, textColor, image, mat, colorTransform); x += entry.glyphAdvance; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/trunk/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index 979199201..09cdb5c82 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -19,13 +19,11 @@ package com.jpexs.decompiler.flash.tags.gfx; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.exporters.Matrix; import com.jpexs.decompiler.flash.exporters.Point; import com.jpexs.decompiler.flash.tags.DefineFont2Tag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.KERNINGRECORD; import com.jpexs.decompiler.flash.types.LANGCODE; import com.jpexs.decompiler.flash.types.RECT; @@ -41,8 +39,6 @@ import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.awt.Color; import java.awt.Font; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -111,21 +107,6 @@ public final class DefineCompactedFont extends FontTag implements DrawableTag { shapeCache = fonts.get(0).getGlyphShapes(); } - @Override - public SerializableImage toImage(int frame, int ratio, Matrix transformation, ColorTransform colorTransform) { - List shapes = new ArrayList<>(); - for (int i = 0; i < shapeCache.size(); i++) { - shapes.add(SHAPERECORD.resizeSHAPE(shapeCache.get(i), SWF.unitDivisor)); - } - int cols = (int) Math.ceil(Math.sqrt(shapes.size())); - int size = 500; - if (size / cols < 30) { - size = cols * 30; - } - SerializableImage ret = SHAPERECORD.shapeListToImage(swf, shapes, size, size, Color.black, colorTransform); - return ret; - } - @Override public Point getImagePos(int frame) { return new Point(0, 0); diff --git a/trunk/src/com/jpexs/decompiler/flash/timeline/Clip.java b/trunk/src/com/jpexs/decompiler/flash/timeline/Clip.java new file mode 100644 index 000000000..8c284dc24 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/timeline/Clip.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010-2014 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.timeline; + +import java.awt.Shape; + +/** + * + * @author JPEXS + */ +public class Clip { + + public Shape shape; + public int depth; + + public Clip(Shape shape, int depth) { + this.shape = shape; + this.depth = depth; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/timeline/DepthState.java b/trunk/src/com/jpexs/decompiler/flash/timeline/DepthState.java index 43aa082cd..1e251ed0c 100644 --- a/trunk/src/com/jpexs/decompiler/flash/timeline/DepthState.java +++ b/trunk/src/com/jpexs/decompiler/flash/timeline/DepthState.java @@ -65,7 +65,6 @@ public class DepthState { public DepthState(DepthState obj, Frame frame, boolean sameInstance) { this.frame = frame; swf = obj.swf; - frame = obj.frame; characterId = obj.characterId; matrix = obj.matrix; instanceName = obj.instanceName; diff --git a/trunk/src/com/jpexs/decompiler/flash/timeline/Frame.java b/trunk/src/com/jpexs/decompiler/flash/timeline/Frame.java index 4c21f7238..33385416e 100644 --- a/trunk/src/com/jpexs/decompiler/flash/timeline/Frame.java +++ b/trunk/src/com/jpexs/decompiler/flash/timeline/Frame.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; -import java.awt.Shape; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; @@ -50,16 +49,4 @@ public class Frame { } //Do not copy sounds } - - private class Clip { - - public Shape shape; - public int depth; - - public Clip(Shape shape, int depth) { - this.shape = shape; - this.depth = depth; - } - - } } diff --git a/trunk/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/trunk/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 469ee4db1..77ab4910f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/trunk/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -24,7 +24,6 @@ import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.StartSound2Tag; import com.jpexs.decompiler.flash.tags.StartSoundTag; import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; @@ -171,18 +170,6 @@ public class Timeline { SWF.frameToImage(this, frame, time, stateUnderCursor, mouseButton, image, transformation, colorTransform); } - private class Clip { - - public Shape shape; - public int depth; - - public Clip(Shape shape, int depth) { - this.shape = shape; - this.depth = depth; - } - - } - public void getSounds(int frame, int time, DepthState stateUnderCursor, int mouseButton, List sounds, List soundClasses) { Frame fr = this.frames.get(frame); sounds.addAll(fr.sounds); @@ -232,7 +219,7 @@ public class Timeline { continue; } CharacterTag c = swf.characters.get(ds.characterId); - if ((c instanceof DrawableTag) && (c instanceof BoundedTag)) { + if (c instanceof DrawableTag) { Matrix m = new Matrix(ds.matrix); m = m.preConcatenate(transformation); @@ -297,7 +284,7 @@ public class Timeline { continue; } CharacterTag c = swf.characters.get(ds.characterId); - if ((c instanceof DrawableTag) && (c instanceof BoundedTag)) { + if (c instanceof DrawableTag) { Matrix m = new Matrix(ds.matrix); m = m.preConcatenate(transformation); @@ -334,4 +321,29 @@ public class Timeline { } return area; } + + public boolean isSingleFrame() { + Frame frameObj = frames.get(0); + for (int i = 1; i <= getMaxDepth(); i++) { + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!swf.characters.containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + CharacterTag character = swf.characters.get(layer.characterId); + if (character instanceof DrawableTag) { + DrawableTag drawable = (DrawableTag) character; + if (!drawable.isSingleFrame()) { + return false; + } + } + } + + return true; + } } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java index 5a5686d7a..e62a097d4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -16,8 +16,7 @@ */ package com.jpexs.decompiler.flash.types; -import com.jpexs.decompiler.flash.exporters.Matrix; -import com.jpexs.decompiler.flash.exporters.ShapeExporterBase; +import com.jpexs.decompiler.flash.exporters.PathExporter; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; @@ -25,7 +24,6 @@ import java.awt.Shape; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.io.Serializable; -import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -56,101 +54,7 @@ public class SHAPE implements NeedsCharacters, Serializable { } public Shape getOutline() { - final List paths = new ArrayList<>(); - ShapeExporterBase se = new ShapeExporterBase(this, new ColorTransform()) { - private GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); - - private double unitDivisor; - - @Override - public void export() { - unitDivisor = 1; - super.export(); - } - - @Override - public void beginShape() { - - } - - @Override - public void endShape(double xMin, double yMin, double xMax, double yMax) { - - } - - @Override - public void beginFills() { - - } - - @Override - public void endFills() { - - } - - @Override - public void beginLines() { - - } - - @Override - public void endLines() { - finalizePath(); - } - - @Override - public void beginFill(RGB color) { - finalizePath(); - } - - @Override - public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - finalizePath(); - } - - @Override - public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { - finalizePath(); - } - - @Override - public void endFill() { - finalizePath(); - } - - @Override - public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { - finalizePath(); - } - - @Override - public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - - } - - @Override - public void moveTo(double x, double y) { - path.moveTo(x / unitDivisor, y / unitDivisor); - } - - @Override - public void lineTo(double x, double y) { - path.lineTo(x / unitDivisor, y / unitDivisor); - } - - @Override - public void curveTo(double controlX, double controlY, double anchorX, double anchorY) { - path.quadTo(controlX / unitDivisor, controlY / unitDivisor, - anchorX / unitDivisor, anchorY / unitDivisor); - } - - protected void finalizePath() { - paths.add(path); - path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); //For correct intersections display - - } - }; - se.export(); + List paths = PathExporter.export(this); Area area = new Area(); for (GeneralPath path : paths) { area.add(new Area(path)); 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 fe444e07a..939c9e831 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -19,23 +19,26 @@ package com.jpexs.decompiler.flash.types.shaperecords; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.exporters.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.Matrix; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; +import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.types.ColorTransform; +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 com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.helpers.Helper; import com.jpexs.helpers.SerializableImage; import java.awt.Color; import java.awt.Font; -import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; import java.awt.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; -import java.awt.image.BufferedImage; import java.io.Serializable; import java.util.ArrayList; import java.util.HashSet; @@ -50,6 +53,7 @@ import javax.swing.JPanel; public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Serializable { public static final int MAX_CHARACTERS_IN_FONT_PREVIEW = 400; + private static final boolean DRAW_BOUNDING_BOX = false; public abstract void calculateBits(); @@ -125,34 +129,42 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali return ret; } - public static SerializableImage shapeListToImage(SWF swf, List shapes, int prevWidth, int prevHeight, Color color, ColorTransform colorTransform) { + public static void shapeListToImage(SWF swf, List shapes, SerializableImage image, Color color, ColorTransform colorTransform) { if (shapes.isEmpty()) { - SerializableImage image = new SerializableImage(1, 1, BufferedImage.TYPE_INT_RGB); - image.fillTransparent(); - return image; + return; } - SerializableImage ret = new SerializableImage(prevWidth, prevHeight, SerializableImage.TYPE_INT_ARGB); - Graphics g = ret.getGraphics(); + + int prevWidth = image.getWidth(); + int prevHeight = image.getHeight(); int maxw = 0; int maxh = 0; + int minXMin = 0; + int minYMin = 0; for (SHAPE s : shapes) { RECT r = SHAPERECORD.getBounds(s.shapeRecords); + if (r.Xmax < r.Xmin || r.Ymax < r.Ymin) { + continue; + } if (r.getWidth() > maxw) { maxw = r.getWidth(); } if (r.getHeight() > maxh) { maxh = r.getHeight(); } + if (r.Xmin < minXMin) { + minXMin = r.Xmin; + } + if (r.Ymin < minYMin) { + minYMin = r.Ymin; + } } - maxw /= SWF.unitDivisor; - maxh /= SWF.unitDivisor; int shapeCount = Math.min(MAX_CHARACTERS_IN_FONT_PREVIEW, shapes.size()); int cols = (int) Math.ceil(Math.sqrt(shapeCount)); int pos = 0; - int w2 = prevWidth / cols; - int h2 = prevHeight / cols; + int w2 = (int) (prevWidth * SWF.unitDivisor / cols); + int h2 = (int) (prevHeight * SWF.unitDivisor / cols); int mh = maxh * w2 / maxw; int mw; @@ -173,21 +185,33 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali } // shapeNum: 1 - SerializableImage img = BitmapExporter.export(swf, shapes.get(pos), color, colorTransform); + SHAPE shape = shapes.get(pos); + List records = shape.shapeRecords; + RECT bounds = SHAPERECORD.getBounds(records); - int w1 = img.getWidth(); - int h1 = img.getHeight(); + int w1 = bounds.getWidth(); + int h1 = bounds.getHeight(); - int w = Math.round(ratio * w1); - int h = Math.round(ratio * h1); - int px = x * w2 + w2 / 2 - w / 2; - int py = y * h2 + w2 - h; - g.drawImage(img.getBufferedImage(), px, py, px + w, py + h, 0, 0, w1, h1, null); + double w = ratio * w1; + double h = ratio * h1; + double px = x * w2 + w2 / 2 - w / 2 - minXMin * ratio; + double py = y * h2 - minYMin * ratio; + + Matrix transformation = new Matrix(); + transformation.translate(px, py); + transformation = transformation.concatenate(Matrix.getScaleInstance(ratio)); + BitmapExporter.export(swf, shape, color, image, transformation, colorTransform); + + // draw bounding boxes + if (DRAW_BOUNDING_BOX) { + RGB borderColor = new RGBA(Color.black); + RGB fillColor = new RGBA(new Color(255, 255, 255, 0)); + transformation = Matrix.getTranslateInstance(bounds.Xmin, bounds.Ymin).preConcatenate(transformation); + TextTag.drawBorder(swf, image, borderColor, fillColor, bounds, new MATRIX(), transformation, colorTransform); + } pos++; } } - - return ret; } public abstract boolean isMove();