diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index 31920fa87..c855197c1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -2903,7 +2903,7 @@ public final class SWF implements SWFContainerItem, Timelined { RenderContext renderContext = new RenderContext(); renderContext.cursorPosition = cursorPosition; renderContext.mouseButton = mouseButton; - timeline.toImage(frame, time, renderContext, image, false, m, new Matrix(), m, colorTransform, zoom); + timeline.toImage(frame, time, renderContext, image, false, m, new Matrix(), m, colorTransform, zoom, false); return image; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/DualGraphics2D.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/DualGraphics2D.java new file mode 100644 index 000000000..d4e00150b --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/DualGraphics2D.java @@ -0,0 +1,460 @@ +package com.jpexs.decompiler.flash.exporters; + +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * + * @author JPEXS + */ +public class DualGraphics2D extends Graphics2D { + + private final Graphics2D first; + + private final Graphics2D second; + + public DualGraphics2D(Graphics2D first, Graphics2D second) { + this.first = first; + this.second = second; + } + + @Override + public void draw(Shape s) { + first.draw(s); + second.draw(s); + } + + @Override + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + boolean ok1 = first.drawImage(img, xform, obs); + boolean ok2 = second.drawImage(img, xform, obs); + return ok1 && ok2; //? + } + + @Override + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) { + first.drawImage(img, op, x, y); + second.drawImage(img, op, x, y); + } + + @Override + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + first.drawRenderedImage(img, xform); + second.drawRenderedImage(img, xform); + } + + @Override + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + first.drawRenderableImage(img, xform); + second.drawRenderableImage(img, xform); + } + + @Override + public void drawString(String str, int x, int y) { + first.drawString(str, x, y); + second.drawString(str, x, y); + } + + @Override + public void drawString(String str, float x, float y) { + first.drawString(str, x, y); + second.drawString(str, x, y); + } + + @Override + public void drawString(AttributedCharacterIterator iterator, int x, int y) { + first.drawString(iterator, x, y); + second.drawString(iterator, x, y); + } + + @Override + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + first.drawString(iterator, x, y); + second.drawString(iterator, x, y); + } + + @Override + public void drawGlyphVector(GlyphVector g, float x, float y) { + first.drawGlyphVector(g, x, y); + second.drawGlyphVector(g, x, y); + } + + @Override + public void fill(Shape s) { + first.fill(s); + second.fill(s); + } + + @Override + public boolean hit(Rectangle rect, Shape s, boolean onStroke) { + boolean ok1 = first.hit(rect, s, onStroke); + boolean ok2 = second.hit(rect, s, onStroke); + return ok1 && ok2; //? + } + + @Override + public GraphicsConfiguration getDeviceConfiguration() { + return first.getDeviceConfiguration(); //? + } + + @Override + public void setComposite(Composite comp) { + first.setComposite(comp); + second.setComposite(comp); + } + + @Override + public void setPaint(Paint paint) { + first.setPaint(paint); + second.setPaint(paint); + } + + @Override + public void setStroke(Stroke s) { + first.setStroke(s); + second.setStroke(s); + } + + @Override + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { + first.setRenderingHint(hintKey, hintValue); + second.setRenderingHint(hintKey, hintValue); + } + + @Override + public Object getRenderingHint(RenderingHints.Key hintKey) { + return first.getRenderingHint(hintKey); //? + } + + @Override + public void setRenderingHints(Map hints) { + first.setRenderingHints(hints); + second.setRenderingHints(hints); + } + + @Override + public void addRenderingHints(Map hints) { + first.addRenderingHints(hints); + second.addRenderingHints(hints); + } + + @Override + public RenderingHints getRenderingHints() { + return first.getRenderingHints(); + } + + @Override + public void translate(int x, int y) { + first.translate(x, y); + second.translate(x, y); + } + + @Override + public void translate(double tx, double ty) { + first.translate(tx, ty); + second.translate(tx, ty); + } + + @Override + public void rotate(double theta) { + first.rotate(theta); + second.rotate(theta); + } + + @Override + public void rotate(double theta, double x, double y) { + first.rotate(theta, x, y); + second.rotate(theta, x, y); + } + + @Override + public void scale(double sx, double sy) { + first.scale(sx, sy); + second.scale(sx, sy); + } + + @Override + public void shear(double shx, double shy) { + first.shear(shx, shy); + second.shear(shx, shy); + } + + @Override + public void transform(AffineTransform Tx) { + first.transform(Tx); + second.transform(Tx); + } + + @Override + public void setTransform(AffineTransform Tx) { + first.setTransform(Tx); + second.setTransform(Tx); + } + + @Override + public AffineTransform getTransform() { + return first.getTransform(); + } + + @Override + public Paint getPaint() { + return first.getPaint(); + } + + @Override + public Composite getComposite() { + return first.getComposite(); + } + + @Override + public void setBackground(Color color) { + first.setBackground(color); + second.setBackground(color); + } + + @Override + public Color getBackground() { + return first.getBackground(); + } + + @Override + public Stroke getStroke() { + return first.getStroke(); + } + + @Override + public void clip(Shape s) { + first.clip(s); + second.clip(s); + } + + @Override + public FontRenderContext getFontRenderContext() { + return first.getFontRenderContext(); + } + + @Override + public Graphics create() { + return this; //? + } + + @Override + public Color getColor() { + return first.getColor(); + } + + @Override + public void setColor(Color c) { + first.setColor(c); + second.setColor(c); + } + + @Override + public void setPaintMode() { + first.setPaintMode(); + second.setPaintMode(); + } + + @Override + public void setXORMode(Color c1) { + first.setXORMode(c1); + second.setXORMode(c1); + } + + @Override + public Font getFont() { + return first.getFont(); + } + + @Override + public void setFont(Font font) { + first.setFont(font); + second.setFont(font); + } + + @Override + public FontMetrics getFontMetrics(Font f) { + return first.getFontMetrics(); + } + + @Override + public Rectangle getClipBounds() { + return first.getClipBounds(); + } + + @Override + public void clipRect(int x, int y, int width, int height) { + first.clearRect(x, y, width, height); + second.clipRect(x, y, width, height); + } + + @Override + public void setClip(int x, int y, int width, int height) { + first.setClip(x, y, width, height); + second.setClip(x, y, width, height); + } + + @Override + public Shape getClip() { + return first.getClip(); + } + + @Override + public void setClip(Shape clip) { + first.setClip(clip); + if (clip == null) { + clip = new Rectangle2D.Double(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); //? + } + second.setClip(clip); + } + + @Override + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + first.copyArea(x, y, width, height, dx, dy); + second.copyArea(x, y, width, height, dx, dy); + } + + @Override + public void drawLine(int x1, int y1, int x2, int y2) { + first.drawLine(x1, y1, x2, y2); + second.drawLine(x1, y1, x2, y2); + } + + @Override + public void fillRect(int x, int y, int width, int height) { + first.fillRect(x, y, width, height); + second.fillRect(x, y, width, height); + } + + @Override + public void clearRect(int x, int y, int width, int height) { + first.clearRect(x, y, width, height); + second.clearRect(x, y, width, height); + } + + @Override + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + first.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + second.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + @Override + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { + first.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + second.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + @Override + public void drawOval(int x, int y, int width, int height) { + first.drawOval(x, y, width, height); + second.drawOval(x, y, width, height); + } + + @Override + public void fillOval(int x, int y, int width, int height) { + first.fillOval(x, y, width, height); + second.fillOval(x, y, width, height); + } + + @Override + public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + first.drawArc(x, y, width, height, startAngle, arcAngle); + second.drawArc(x, y, width, height, startAngle, arcAngle); + } + + @Override + public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { + first.fillArc(x, y, width, height, startAngle, arcAngle); + second.fillArc(x, y, width, height, startAngle, arcAngle); + } + + @Override + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { + first.drawPolyline(xPoints, yPoints, nPoints); + second.drawPolyline(xPoints, yPoints, nPoints); + } + + @Override + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { + first.drawPolyline(xPoints, yPoints, nPoints); + second.drawPolyline(xPoints, yPoints, nPoints); + } + + @Override + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { + first.fillPolygon(xPoints, yPoints, nPoints); + second.fillPolygon(xPoints, yPoints, nPoints); + } + + @Override + public boolean drawImage(Image img, int x, int y, ImageObserver observer) { + boolean ok1 = first.drawImage(img, x, y, observer); + boolean ok2 = second.drawImage(img, x, y, observer); + return ok1 && ok2; + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { + boolean ok1 = first.drawImage(img, x, y, width, height, observer); + boolean ok2 = second.drawImage(img, x, y, width, height, observer); + return ok1 && ok2; + } + + @Override + public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { + boolean ok1 = first.drawImage(img, x, y, bgcolor, observer); + boolean ok2 = second.drawImage(img, x, y, bgcolor, observer); + return ok1 && ok2; + } + + @Override + public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) { + boolean ok1 = first.drawImage(img, x, y, width, height, bgcolor, observer); + boolean ok2 = second.drawImage(img, x, y, width, height, bgcolor, observer); + return ok1 && ok2; + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) { + boolean ok1 = first.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + boolean ok2 = second.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + return ok1 && ok2; + } + + @Override + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) { + boolean ok1 = first.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); + boolean ok2 = second.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer); + return ok1 && ok2; + } + + @Override + public void dispose() { + first.dispose(); + second.dispose(); + } + +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index bcc125f9b..5189eb04d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -36,11 +36,14 @@ import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.DefineText2Tag; +import com.jpexs.decompiler.flash.tags.DefineTextTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.Tag; 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.RenderContext; import com.jpexs.decompiler.flash.tags.base.StaticTextTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; @@ -65,13 +68,33 @@ import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; +import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; import gnu.jpdf.PDFGraphics; import gnu.jpdf.PDFJob; +import java.awt.AlphaComposite; import java.awt.Color; +import java.awt.Composite; import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.io.BufferedOutputStream; @@ -80,6 +103,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.text.AttributedCharacterIterator; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -469,13 +493,18 @@ public class FrameExporter { PageFormat pf = new PageFormat(); pf.setOrientation(PageFormat.PORTRAIT); Paper p = new Paper(); - BufferedImage img = frameImages.next(); - p.setSize(img.getWidth() + 10, img.getHeight() + 10); - pf.setPaper(p); + /*BufferedImage img = frameImages.next(); + p.setSize(img.getWidth() + 10, img.getHeight() + 10);*/ + int pos = 0; RECT rect = tim.displayRect; + + double w = (rect.getWidth() * settings.zoom / SWF.unitDivisor); + double h = (rect.getHeight() * settings.zoom / SWF.unitDivisor); + p.setSize(w + 10, h + 10); + pf.setPaper(p); double zoom = settings.zoom; Matrix m = new Matrix(); m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom); @@ -483,19 +512,59 @@ public class FrameExporter { Matrix transformation = m; Map existingFonts = new HashMap<>(); - while (true) { + while (pos < fframes.size()) { int fframe = fframes.get(pos); - Graphics2D g = (Graphics2D) job.getGraphics(pf); - g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null); + final Graphics2D g = (Graphics2D) job.getGraphics(pf); + //g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null); - printStringsToImage(existingFonts, g, fframe, swf, tim, transformation); + SerializableImage image = new SerializableImage((int) w + 1, (int) h + 1, SerializableImage.TYPE_INT_ARGB_PRE) { + + private Graphics2D compositeGraphics; + + @Override + public Graphics getGraphics() { + if (compositeGraphics != null) { + return compositeGraphics; + } + final Graphics2D parentGraphics = (Graphics2D) super.getGraphics(); + compositeGraphics = new DualGraphics2D(parentGraphics, g); + return compositeGraphics; + } + + @Override + public void fillTransparent() { + + } + + }; + //if (backGroundColor == null) { + // image.fillTransparent(); + int imgWidth = (int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1; + int imgHeight = (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1; + if (!fusesTransparency && fbackgroundColor != null) { + g.setComposite(AlphaComposite.Src); + g.setColor(fbackgroundColor); + g.fill(new Rectangle(imgWidth, imgHeight)); + } + + RenderContext renderContext = new RenderContext(); + renderContext.cursorPosition = new Point(-1, -1); + renderContext.mouseButton = 0; + renderContext.stateUnderCursor = new ArrayList<>(); + + try { + tim.toImage(fframe, fframe, renderContext, image, false, m, new Matrix(), m, null, zoom, true); + } catch (Exception ex) { + ex.printStackTrace(); + } + //printStringsToImage(existingFonts, g, fframe, swf, tim, transformation); g.dispose(); - if (frameImages.hasNext()) { + /*if (frameImages.hasNext()) { img = frameImages.next(); } else { break; - } + }*/ pos++; } @@ -538,12 +607,12 @@ public class FrameExporter { Matrix layerMatrix = new Matrix(layer.matrix); Matrix absMat = absoluteTransformation.concatenate(layerMatrix); if (character instanceof DrawableTag) { - printStringsDrawDrawable(existingFonts, g, swf, layerMatrix, transformation, absMat, time, layer.ratio, (DrawableTag) character, unzoom); + printStringsDrawDrawable(existingFonts, g, swf, layerMatrix, transformation, absMat, time, layer.ratio, (DrawableTag) character, unzoom, layer.colorTransForm); } } } - private static void printStringsDrawDrawable(Map existingFonts, Graphics2D g, SWF swf, Matrix layerMatrix, Matrix transformation, Matrix absMat, int time, int ratio, DrawableTag drawable, double unzoom) { + private static void printStringsDrawDrawable(Map existingFonts, Graphics2D g, SWF swf, Matrix layerMatrix, Matrix transformation, Matrix absMat, int time, int ratio, DrawableTag drawable, double unzoom, ColorTransform colorTransform) { int drawableFrameCount = drawable.getNumFrames(); if (drawableFrameCount == 0) { drawableFrameCount = 1; @@ -555,8 +624,7 @@ public class FrameExporter { Matrix m = mat; //mat.preConcatenate(Matrix.getTranslateInstance(-rect.xMin, -rect.yMin)); if (drawable instanceof DefineSpriteTag) { printStringsToImage(existingFonts, g, dframe, swf, ((Timelined) drawable).getTimeline(), m); - } - if (drawable instanceof TextTag) { + } else if (drawable instanceof TextTag) { TextTag textTag = (TextTag) drawable; List textRecords = new ArrayList<>(); @@ -579,7 +647,21 @@ public class FrameExporter { int textHeight = 12; int x = 0; int y = 0; + int textColor = 0; for (TEXTRECORD rec : textRecords) { + + if (rec.styleFlagsHasColor) { + if (!(textTag instanceof DefineTextTag)) { + textColor = rec.textColorA.toInt(); + } else { + textColor = rec.textColor.toInt(); + } + + if (colorTransform != null) { + textColor = colorTransform.apply(textColor); + } + } + if (rec.styleFlagsHasFont) { font = swf.getFont(rec.fontId); textHeight = rec.textHeight; @@ -621,8 +703,12 @@ public class FrameExporter { } g2.setTransform(trans.toTransform()); - g2.drawTransparentString(text.toString(), (float) x, (float) y); + Color textColor2 = new Color(textColor, true); + g2.setColor(textColor2); + g2.drawString(text.toString(), (float) x, (float) y); } + } else { + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 8c483d48b..0694a2ad7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -122,7 +122,7 @@ public class ShapeExporter { } Matrix m = Matrix.getScaleInstance(settings.zoom); m.translate(-rect.Xmin, -rect.Ymin); - st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, m, new CXFORMWITHALPHA(), unzoom); + st.toImage(0, 0, 0, new RenderContext(), img, false, m, m, m, new CXFORMWITHALPHA(), unzoom, false); if (settings.mode == ShapeExportMode.PNG) { ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file); } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index bbcb105c6..b0cee910e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -961,7 +961,7 @@ public class DefineEditTextTag extends TextTag { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { render(TextRenderMode.BITMAP, image, null, null, transformation, colorTransform, 1); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java index 47b18aff5..84eba8963 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSpriteTag.java @@ -368,8 +368,8 @@ public class DefineSpriteTag extends DrawableTag implements Timelined { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { - getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, strokeTransformation, absoluteTransformation, colorTransform, unzoom); + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { + getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, strokeTransformation, absoluteTransformation, colorTransform, unzoom, sameImage); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index cdcaa7f25..133715409 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -97,8 +97,8 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { - getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, strokeTransformation, absoluteTransformation, colorTransform, unzoom); + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { + getTimeline().toImage(frame, time, renderContext, image, isClip, transformation, strokeTransformation, absoluteTransformation, colorTransform, unzoom, sameImage); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java index 5065f64f5..278b94c78 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java @@ -45,7 +45,7 @@ public abstract class DrawableTag extends CharacterTag implements BoundedTag { public abstract Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked); - public abstract void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom); + public abstract void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix prevTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage); public abstract void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index 06b7ed86a..de036432f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -417,7 +417,7 @@ public abstract class FontTag extends DrawableTag implements AloneTag { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index 770d0d611..b92d2aaf1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -230,7 +230,7 @@ public abstract class ImageTag extends DrawableTag { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { BitmapExporter.export(swf, getShape(), null, image, transformation, strokeTransformation, colorTransform); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java index e1608d528..631cf9fc0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/MorphShapeTag.java @@ -313,7 +313,7 @@ public abstract class MorphShapeTag extends DrawableTag { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); // morphShape using shapeNum=3, morphShape2 using shapeNum=4 // todo: Currently the generated image is not cached, because the cache diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index 88747c219..11009eeb0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -171,7 +171,7 @@ public abstract class ShapeTag extends DrawableTag implements LazyObject { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform); if (Configuration._debugMode.get()) { // show control points List paths = PathExporter.export(swf, getShapes()); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java index e62b9c913..c032b23f3 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java @@ -652,7 +652,7 @@ public abstract class StaticTextTag extends TextTag { } @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { staticTextToImage(swf, textRecords, getTextNum(), image, textMatrix, transformation, colorTransform); /*try { TextTag originalTag = (TextTag) getOriginalTag(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 11c0c9ba9..dfe487f50 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -605,7 +605,7 @@ public class Timeline { toImage(frame, time, renderContext, image, isClip, transforms[i], absoluteTransformation, colorTransform, targetRect[i]); } }*/ - private void drawDrawable(Matrix strokeTransform, DepthState layer, Matrix layerMatrix, Graphics2D g, ColorTransform colorTransForm, int blendMode, List clips, Matrix transformation, boolean isClip, int clipDepth, Matrix absMat, int time, int ratio, RenderContext renderContext, SerializableImage image, DrawableTag drawable, List filters, double unzoom, ColorTransform clrTrans) { + private void drawDrawable(Matrix strokeTransform, DepthState layer, Matrix layerMatrix, Graphics2D g, ColorTransform colorTransForm, int blendMode, List clips, Matrix transformation, boolean isClip, int clipDepth, Matrix absMat, int time, int ratio, RenderContext renderContext, SerializableImage image, DrawableTag drawable, List filters, double unzoom, ColorTransform clrTrans, boolean sameImage) { Matrix drawMatrix = new Matrix(); int drawableFrameCount = drawable.getNumFrames(); if (drawableFrameCount == 0) { @@ -670,7 +670,10 @@ public class Timeline { rect.xMin = Math.max(0, rect.xMin); rect.yMin = Math.max(0, rect.yMin); drawMatrix.translate(rect.xMin, rect.yMin); + drawMatrix.translateX /= SWF.unitDivisor; + drawMatrix.translateY /= SWF.unitDivisor; + boolean canUseSameImage = true; if (img == null) { int newWidth = (int) (rect.getWidth() / SWF.unitDivisor); int newHeight = (int) (rect.getHeight() / SWF.unitDivisor); @@ -704,9 +707,25 @@ public class Timeline { } } + + if (filters != null && !filters.isEmpty()) { + canUseSameImage = false; + } + if (blendMode > 1) { + canUseSameImage = false; + } + if (clipDepth > -1) { + canUseSameImage = false; + } img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE); img.fillTransparent(); + if (canUseSameImage && sameImage) { + img = image; + m = mat.clone(); + //m = m.concatenate(drawMatrix); + } + ColorTransform clrTrans2 = clrTrans; if (clipDepth > -1) { //Make transparent colors opaque, mask should be only made by shapes @@ -720,8 +739,9 @@ public class Timeline { clrTrans2 = clrMask; } + if (!(drawable instanceof ImageTag) || (swf.isAS3() && layer.hasImage)) { - drawable.toImage(dframe, time, ratio, renderContext, img, isClip || clipDepth > -1, m, strokeTransform, absMat, clrTrans2, unzoom); + drawable.toImage(dframe, time, ratio, renderContext, img, isClip || clipDepth > -1, m, strokeTransform, absMat, clrTrans2, unzoom, sameImage); } else { // todo: show one time warning } @@ -737,13 +757,11 @@ public class Timeline { } } - if (cacheAsBitmap && renderContext.displayObjectCache != null) { + if (!sameImage && cacheAsBitmap && renderContext.displayObjectCache != null) { renderContext.displayObjectCache.put(layer.placeObjectTag, img); } } - drawMatrix.translateX /= SWF.unitDivisor; - drawMatrix.translateY /= SWF.unitDivisor; AffineTransform trans = drawMatrix.toTransform(); switch (blendMode) { @@ -830,12 +848,14 @@ public class Timeline { g2.draw(shape); } - g.setTransform(trans); - g.drawImage(img.getBufferedImage(), 0, 0, null); + if (!(sameImage && canUseSameImage)) { + g.setTransform(drawMatrix.toTransform()); + g.drawImage(img.getBufferedImage(), 0, 0, null); + } } } - public void toImage(int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom) { + public void toImage(int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform, double unzoom, boolean sameImage) { //double unzoom = SWF.unitDivisor; //unzoom = SWF.unitDivisor; if (getFrameCount() <= frame) { @@ -849,8 +869,10 @@ public class Timeline { // g.setClip(new Rectangle2D.Double(targetRect.xMin, targetRect.yMin, targetRect.getWidth(), targetRect.getHeight())); //} - g.setPaint(frameObj.backgroundColor.toColor()); - g.fill(new Rectangle(image.getWidth(), image.getHeight())); + if (!sameImage) { + g.setPaint(frameObj.backgroundColor.toColor()); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + } g.setTransform(transformation.toTransform()); List clips = new ArrayList<>(); @@ -958,7 +980,7 @@ public class Timeline { Rectangle2D r = new Rectangle2D.Double(p1.xMin, p1.yMin, p1.getWidth(), p1.getHeight()); g.setClip(r); - drawDrawable(strokeTransformation.preConcatenate(layerMatrix), layer, transforms[s], g, colorTransform, layer.blendMode, clips, transformation, isClip, layer.clipDepth, absMat, time, layer.ratio, renderContext, image, (DrawableTag) character, layer.filters, unzoom, clrTrans); + drawDrawable(strokeTransformation.preConcatenate(layerMatrix), layer, transforms[s], g, colorTransform, layer.blendMode, clips, transformation, isClip, layer.clipDepth, absMat, time, layer.ratio, renderContext, image, (DrawableTag) character, layer.filters, unzoom, clrTrans, sameImage); s++; } } @@ -977,7 +999,7 @@ public class Timeline { }*/ g.setTransform(origTransform); } else { - drawDrawable(strokeTransformation, layer, layerMatrix, g, colorTransform, layer.blendMode, clips, transformation, isClip, layer.clipDepth, absMat, time, layer.ratio, renderContext, image, (DrawableTag) character, layer.filters, unzoom, clrTrans); + drawDrawable(strokeTransformation, layer, layerMatrix, g, colorTransform, layer.blendMode, clips, transformation, isClip, layer.clipDepth, absMat, time, layer.ratio, renderContext, image, (DrawableTag) character, layer.filters, unzoom, clrTrans, sameImage); } } else if (character instanceof BoundedTag) { showPlaceholder = true; @@ -1000,8 +1022,7 @@ public class Timeline { } } - g.setTransform( - new AffineTransform()); + g.setTransform(new AffineTransform()); g.setClip(prevClip); } diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java index e8e9a3465..879b9c2c4 100644 --- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java @@ -362,7 +362,7 @@ public class FolderPreviewPanel extends JPanel { image.fillTransparent(); if (imgSrc == null) { DrawableTag drawable = (DrawableTag) treeItem; - drawable.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, null, scale); + drawable.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, null, scale, false); } else { Graphics2D g = (Graphics2D) image.getGraphics(); g.setTransform(m.toTransform()); diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index 3b020a195..90f1a6d9b 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -1507,10 +1507,10 @@ public final class ImagePanel extends JPanel implements MediaDisplay { image.fillTransparent(); Matrix m = Matrix.getTranslateInstance(-rect.Xmin * zoomDouble, -rect.Ymin * zoomDouble); m.scale(zoomDouble); - textTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFFC0C0C0), zoomDouble); + textTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFFC0C0C0), zoomDouble, false); if (newTextTag != null) { - newTextTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFF000000), zoomDouble); + newTextTag.toImage(0, 0, 0, new RenderContext(), image, false, m, m, m, new ConstantColorColorTransform(0xFF000000), zoomDouble, false); } iconPanel.setImg(image); @@ -1646,7 +1646,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { timeline.getFrame(frame).layers.get(freeTransformDepth).matrix = newMatrix; } - timeline.toImage(frame, time, renderContext, image, false, m, new Matrix(), m, null, zoom); + timeline.toImage(frame, time, renderContext, image, false, m, new Matrix(), m, null, zoom, false); Graphics2D gg = (Graphics2D) image.getGraphics(); gg.setStroke(new BasicStroke(3));