From 7fd28291c65f728fe612249ce45a833b145b8b97 Mon Sep 17 00:00:00 2001 From: Honfika Date: Sun, 26 Jan 2014 22:50:17 +0100 Subject: [PATCH] new image rendering algorithm --- trunk/src/com/jpexs/decompiler/flash/SWF.java | 2 + .../flash/exporters/BitmapExporter.java | 371 ++++++++++++++++++ .../flash/exporters/CurvedEdge.java | 2 +- .../exporters/DefaultSVGShapeExporter.java | 6 +- .../flash/exporters/IShapeExporter.java | 6 +- .../decompiler/flash/exporters/Matrix.java | 1 - .../decompiler/flash/exporters/Point.java | 1 + .../decompiler/flash/exporters/Rectangle.java | 1 + .../flash/exporters/SVGShapeExporter.java | 21 +- .../flash/exporters/ShapeExporterBase.java | 33 +- .../flash/tags/DefineShape2Tag.java | 5 +- .../flash/tags/DefineShape3Tag.java | 5 +- .../flash/tags/DefineShape4Tag.java | 5 +- .../decompiler/flash/tags/DefineShapeTag.java | 5 +- .../flash/types/SHAPEWITHSTYLE.java | 1 + .../types/shaperecords/CurvedEdgeRecord.java | 1 - .../flash/types/shaperecords/SHAPERECORD.java | 67 +--- .../types/shaperecords/SerializableImage.java | 56 +++ .../shaperecords/StraightEdgeRecord.java | 1 - .../types/shaperecords/StyleChangeRecord.java | 1 - 20 files changed, 481 insertions(+), 110 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SerializableImage.java diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index 67eacf61c..e6160300f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -52,6 +52,7 @@ import com.jpexs.decompiler.flash.action.swf5.ActionSetMember; import com.jpexs.decompiler.flash.action.swf7.ActionDefineFunction2; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.ecma.Null; +import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.flv.AUDIODATA; import com.jpexs.decompiler.flash.flv.FLVOutputStream; import com.jpexs.decompiler.flash.flv.FLVTAG; @@ -2078,6 +2079,7 @@ public final class SWF implements TreeItem { public void clearImageCache() { cache.clear(); SHAPERECORD.clearShapeCache(); + BitmapExporter.clearShapeCache(); } public static RECT fixRect(RECT rect) { diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java new file mode 100644 index 000000000..ff7e89edc --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/BitmapExporter.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2010-2013 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.SWF; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +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.LINESTYLE2; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.SerializableImage; +import com.jpexs.helpers.Cache; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.LinearGradientPaint; +import java.awt.MultipleGradientPaint; +import java.awt.Paint; +import java.awt.RadialGradientPaint; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class BitmapExporter extends ShapeExporterBase implements IShapeExporter { + + private static final Cache cache = Cache.getInstance(false); + + private BufferedImage image; + private Graphics2D graphics; + private final Color defaultColor; + private double xMin; + private double yMin; + private final SWF swf; + private GeneralPath path; + private Paint fillPathPaint; + private Paint fillPaint; + private AffineTransform fillTransform; + private Color lineColor; + private Stroke lineStroke; + private Stroke defaultStroke; + + public BitmapExporter(SWF swf, ShapeTag tag) { + this(swf, tag, null); + } + + public BitmapExporter(SWF swf, ShapeTag tag, Color defaultColor) { + super(tag); + this.defaultColor = defaultColor; + this.swf = swf; + } + + @Override + public void export() { + List records = tag.getShapes().shapeRecords; + String key = "shape_" + records.hashCode() + "_" + (defaultColor == null ? "null" : defaultColor.hashCode()); + if (cache.contains(key)) { + image = (BufferedImage) ((SerializableImage) cache.get(key)).getImage(); + return; + } + RECT bounds = SHAPERECORD.getBounds(records); + xMin = bounds.Xmin / unitDivisor - 1; + yMin = bounds.Ymin / unitDivisor - 1; + image = new BufferedImage( + (int) (bounds.getWidth() / unitDivisor + 3), (int) (bounds.getHeight() / unitDivisor + 3), BufferedImage.TYPE_INT_ARGB); + graphics = (Graphics2D) image.getGraphics(); + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + defaultStroke = graphics.getStroke(); + super.export(); + cache.put(key, new SerializableImage(image)); + } + + public BufferedImage getImage() { + return image; + } + + public static void clearShapeCache() { + cache.clear(); + } + + @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(); + fillPaint = color.toColor(); + } + + @Override + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + finalizePath(); + switch (type) { + case FILLSTYLE.LINEAR_GRADIENT: { + List colors = new ArrayList<>(); + List ratios = new ArrayList<>(); + for (int i = 0; i < gradientRecords.length; i++) { + if ((i > 0) && (gradientRecords[i - 1].ratio == gradientRecords[i].ratio)) { + continue; + } + ratios.add(gradientRecords[i].getRatioFloat()); + colors.add(gradientRecords[i].color.toColor()); + } + + float[] ratiosArr = new float[ratios.size()]; + for (int i = 0; i < ratios.size(); i++) { + ratiosArr[i] = ratios.get(i); + } + Color[] colorsArr = colors.toArray(new Color[colors.size()]); + + MultipleGradientPaint.CycleMethod cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + if (spreadMethod == GRADIENT.SPREAD_PAD_MODE) { + cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + } else if (spreadMethod == GRADIENT.SPREAD_REFLECT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REFLECT; + } else if (spreadMethod == GRADIENT.SPREAD_REPEAT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REPEAT; + } + + fillPathPaint = null; + fillPaint = new LinearGradientPaint(new java.awt.Point(-16384 / 20, 0), new java.awt.Point(16384 / 20, 0), ratiosArr, colorsArr, cm); + fillTransform = matrixToTransform(matrix); + } + break; + case FILLSTYLE.RADIAL_GRADIENT: { + List colors = new ArrayList<>(); + List ratios = new ArrayList<>(); + for (int i = 0; i < gradientRecords.length; i++) { + if ((i > 0) && (gradientRecords[i - 1].ratio == gradientRecords[i].ratio)) { + continue; + } + ratios.add(gradientRecords[i].getRatioFloat()); + colors.add(gradientRecords[i].color.toColor()); + } + + float[] ratiosArr = new float[ratios.size()]; + for (int i = 0; i < ratios.size(); i++) { + ratiosArr[i] = ratios.get(i); + } + Color[] colorsArr = colors.toArray(new Color[colors.size()]); + + MultipleGradientPaint.CycleMethod cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + if (spreadMethod == GRADIENT.SPREAD_PAD_MODE) { + cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + } else if (spreadMethod == GRADIENT.SPREAD_REFLECT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REFLECT; + } else if (spreadMethod == GRADIENT.SPREAD_REPEAT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REPEAT; + } + + Color endColor = gradientRecords[gradientRecords.length - 1].color.toColor(); + fillPathPaint = endColor; + fillPaint = new RadialGradientPaint(new java.awt.Point(0, 0), 16384 / 20, ratiosArr, colorsArr, cm); + fillTransform = matrixToTransform(matrix); + } + break; + case FILLSTYLE.FOCAL_RADIAL_GRADIENT: { + List colors = new ArrayList<>(); + List ratios = new ArrayList<>(); + for (int i = 0; i < gradientRecords.length; i++) { + if ((i > 0) && (gradientRecords[i - 1].ratio == gradientRecords[i].ratio)) { + continue; + } + ratios.add(gradientRecords[i].getRatioFloat()); + colors.add(gradientRecords[i].color.toColor()); + } + + float[] ratiosArr = new float[ratios.size()]; + for (int i = 0; i < ratios.size(); i++) { + ratiosArr[i] = ratios.get(i); + } + Color[] colorsArr = colors.toArray(new Color[colors.size()]); + + MultipleGradientPaint.CycleMethod cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + if (spreadMethod == GRADIENT.SPREAD_PAD_MODE) { + cm = MultipleGradientPaint.CycleMethod.NO_CYCLE; + } else if (spreadMethod == GRADIENT.SPREAD_REFLECT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REFLECT; + } else if (spreadMethod == GRADIENT.SPREAD_REPEAT_MODE) { + cm = MultipleGradientPaint.CycleMethod.REPEAT; + } + + Color endColor = gradientRecords[gradientRecords.length - 1].color.toColor(); + fillPathPaint = endColor; + fillPaint = new RadialGradientPaint(new java.awt.Point(0, 0), 16384 / 20, new java.awt.Point((int) (focalPointRatio * 16384 / 20), 0), ratiosArr, colorsArr, cm); + fillTransform = matrixToTransform(matrix); + } + break; + } + } + + @Override + public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth) { + finalizePath(); + ImageTag image = null; + for (Tag t : swf.tags) { + if (t instanceof ImageTag) { + ImageTag i = (ImageTag) t; + if (i.getCharacterId() == bitmapId) { + image = i; + break; + } + } + } + if (image != null) { + BufferedImage img = image.getImage(swf.tags); + if (img != null) { + fillPaint = new TexturePaint(img, new java.awt.Rectangle(img.getWidth(), img.getHeight())); + fillTransform = matrixToTransform(matrix); + fillTransform.concatenate(AffineTransform.getScaleInstance(1 / unitDivisor, 1 / unitDivisor)); + } + } + } + + @Override + public void endFill() { + finalizePath(); + fillPaint = null; + } + + @Override + public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { + finalizePath(); + lineColor = color.toColor(); + int capStyle = BasicStroke.CAP_ROUND; + switch (startCaps) { + case LINESTYLE2.NO_CAP: + capStyle = BasicStroke.CAP_BUTT; + break; + case LINESTYLE2.ROUND_CAP: + capStyle = BasicStroke.CAP_ROUND; + break; + case LINESTYLE2.SQUARE_CAP: + capStyle = BasicStroke.CAP_SQUARE; + break; + } + int joinStyle = BasicStroke.JOIN_ROUND; + switch (joints) { + case LINESTYLE2.BEVEL_JOIN: + joinStyle = BasicStroke.JOIN_BEVEL; + break; + case LINESTYLE2.MITER_JOIN: + joinStyle = BasicStroke.JOIN_MITER; + break; + case LINESTYLE2.ROUND_JOIN: + joinStyle = BasicStroke.JOIN_ROUND; + break; + } + if (joinStyle == BasicStroke.JOIN_MITER) { + lineStroke = new BasicStroke((float) thickness, capStyle, joinStyle, miterLimit); + } else { + lineStroke = new BasicStroke((float) thickness, capStyle, joinStyle); + } + } + + @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 - xMin, y - yMin); + } + + @Override + public void lineTo(double x, double y) { + path.lineTo(x - xMin, y - yMin); + } + + @Override + public void curveTo(double controlX, double controlY, double anchorX, double anchorY) { + path.quadTo(controlX - xMin, controlY - yMin, anchorX - xMin, anchorY - yMin); + } + + protected void finalizePath() { + final int maxRepeat = 10; // TODO: better handle gradient repeating + if (path != null) { + if (fillPaint != null) { + if (fillPaint instanceof MultipleGradientPaint) { + AffineTransform oldAf = graphics.getTransform(); + if (fillPathPaint != null) { + graphics.setPaint(fillPathPaint); + } + graphics.fill(path); + graphics.setClip(path); + graphics.setTransform(fillTransform); + + graphics.setPaint(fillPaint); + graphics.fill(new java.awt.Rectangle(-16384 / 20 * maxRepeat, -16384 / 20 * maxRepeat, 16384 / 20 * 2 * maxRepeat, 16384 / 20 * 2 * maxRepeat)); + graphics.setTransform(oldAf); + graphics.setClip(null); + } else if (fillPaint instanceof TexturePaint) { + AffineTransform oldAf = graphics.getTransform(); + graphics.setClip(path); + graphics.setTransform(fillTransform); + + graphics.setPaint(fillPaint); + graphics.fill(new java.awt.Rectangle(-16384 / 20 * maxRepeat, -16384 / 20 * maxRepeat, 16384 / 20 * 2 * maxRepeat, 16384 / 20 * 2 * maxRepeat)); + graphics.setTransform(oldAf); + graphics.setClip(null); + } else { + graphics.setPaint(fillPaint); + graphics.fill(path); + } + } + if (lineColor != null) { + graphics.setColor(lineColor); + graphics.setStroke(lineStroke == null ? defaultStroke : lineStroke); + graphics.draw(path); + } + } + path = new GeneralPath(); + } + + public static AffineTransform matrixToTransform(Matrix mat) { + return new AffineTransform(mat.scaleX, mat.rotateSkew0, + mat.rotateSkew1, mat.scaleY, + mat.translateX, mat.translateY); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java b/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java index a5de4833f..7a5830ce1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java @@ -22,7 +22,7 @@ package com.jpexs.decompiler.flash.exporters; */ public class CurvedEdge extends StraightEdge implements IEdge { - private Point control; + private final Point control; CurvedEdge(Point from, Point control, Point to, int lineStyleIdx, int fillStyleIdx) { super(from, to, lineStyleIdx, fillStyleIdx); diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java index b01222346..fed863e8d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java @@ -17,8 +17,8 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.GRADRECORD; import com.jpexs.decompiler.flash.types.RGB; -import java.util.List; /** * @@ -67,7 +67,7 @@ public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShape } @Override - public void beginGradientFill(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { finalizePath(); } @@ -87,7 +87,7 @@ public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShape } @Override - public void lineGradientStyle(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java index b3683700b..b16e57aa4 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java @@ -16,8 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters; +import com.jpexs.decompiler.flash.types.GRADRECORD; import com.jpexs.decompiler.flash.types.RGB; -import java.util.List; /** * @@ -39,7 +39,7 @@ public interface IShapeExporter { public void beginFill(RGB color); - public void beginGradientFill(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio); + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio); public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth); @@ -47,7 +47,7 @@ public interface IShapeExporter { public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit); - public void lineGradientStyle(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio); + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio); public void moveTo(double x, double y); diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/Matrix.java b/trunk/src/com/jpexs/decompiler/flash/exporters/Matrix.java index f6926e00c..41840690b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/Matrix.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/Matrix.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.exporters; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.types.MATRIX; /** diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java b/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java index e903a4d74..b1c646430 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java @@ -30,6 +30,7 @@ public class Point { this.y = y; } + @Override public int hashCode() { long bits = Double.doubleToLongBits(x); bits ^= Double.doubleToLongBits(y) * 31; diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java b/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java index 95944ce3c..667ea262d 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java @@ -34,6 +34,7 @@ public class Rectangle { this.yMax = yMax; } + @Override public int hashCode() { long bits = Double.doubleToLongBits(xMin); bits += Double.doubleToLongBits(yMin) * 37; diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java index 7c50b0aad..4dc14eeba 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java @@ -22,8 +22,8 @@ import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; 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.LINESTYLE2; -import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.helpers.Helper; @@ -68,7 +68,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { protected Element path; protected List gradients; protected int lastPatternId; - private SWF swf; + private final SWF swf; public SVGShapeExporter(SWF swf, ShapeTag tag) { super(tag); @@ -132,12 +132,12 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { } @Override - public void beginGradientFill(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + public void beginGradientFill(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { finalizePath(); Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) ? _svg.createElement("linearGradient") : _svg.createElement("radialGradient"); - populateGradientElement(gradient, type, colors, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio); + populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); int id = gradients.indexOf(gradient); if (id < 0) { // todo: filter same gradients @@ -252,12 +252,12 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { } @Override - public void lineGradientStyle(int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { path.removeAttribute("stroke-opacity"); Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT) ? _svg.createElement("linearGradient") : _svg.createElement("radialGradient"); - populateGradientElement(gradient, type, colors, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio); + populateGradientElement(gradient, type, gradientRecords, matrix, spreadMethod, interpolationMethod, focalPointRatio); int id = gradients.indexOf(gradient); if (id < 0) { // todo: filter same gradients @@ -280,7 +280,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { super.finalizePath(); } - protected void populateGradientElement(Element gradient, int type, List colors, List ratios, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { + protected void populateGradientElement(Element gradient, int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { gradient.setAttribute("gradientUnits", "userSpaceOnUse"); if (type == FILLSTYLE.LINEAR_GRADIENT) { gradient.setAttribute("x1", "-819.2"); @@ -318,10 +318,11 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { gradient.setAttribute("gradientTransform", "matrix(" + scaleX + ", " + rotateSkew0 + ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")"); } - for (int i = 0; i < colors.size(); i++) { + for (int i = 0; i < gradientRecords.length; i++) { + GRADRECORD record = gradientRecords[i]; Element gradientEntry = _svg.createElement("stop"); - gradientEntry.setAttribute("offset", Double.toString(ratios.get(i) / 255)); - RGB color = colors.get(i); + gradientEntry.setAttribute("offset", Double.toString(record.ratio / 255)); + RGB color = record.color; //if(colors.get(i) != 0) { gradientEntry.setAttribute("stop-color", color.toHexRGB()); //} diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java b/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java index 3f7d345a9..337bd1114 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java @@ -19,11 +19,8 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.FOCALGRADIENT; -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.MATRIX; -import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; @@ -44,9 +41,9 @@ import java.util.Map; */ public abstract class ShapeExporterBase implements IShapeExporter { - private final ShapeTag tag; + protected final ShapeTag tag; - private static final double unitDivisor = 20; + protected static final double unitDivisor = 20; protected List _fillStyles; protected List _lineStyles; @@ -57,7 +54,7 @@ public abstract class ShapeExporterBase implements IShapeExporter { protected Map> currentLineEdgeMap; private int numGroups; protected Map> coordMap; - private Rectangle bounds = new Rectangle(Double.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); + private final Rectangle bounds = new Rectangle(Double.MAX_VALUE, Double.MAX_VALUE, Double.MIN_VALUE, Double.MIN_VALUE); private boolean edgeMapsCreated; @@ -270,18 +267,11 @@ public abstract class ShapeExporterBase implements IShapeExporter { case FILLSTYLE.RADIAL_GRADIENT: case FILLSTYLE.FOCAL_RADIAL_GRADIENT: // Gradient fill - List colors = new ArrayList<>(); - List ratios = new ArrayList<>(); - GRADRECORD gradientRecord; matrix = new Matrix(fillStyle.gradientMatrix); - for (int gri = 0; gri < fillStyle.gradient.gradientRecords.length; gri++) { - gradientRecord = fillStyle.gradient.gradientRecords[gri]; - colors.add(gradientRecord.color); - ratios.add(gradientRecord.ratio); - } beginGradientFill( fillStyle.fillStyleType, - colors, ratios, matrix, + fillStyle.gradient.gradientRecords, + matrix, fillStyle.gradient.spreadMode, fillStyle.gradient.interpolationMode, (fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0 @@ -369,7 +359,7 @@ public abstract class ShapeExporterBase implements IShapeExporter { hasFillFlag = lineStyle2.hasFillFlag; } lineStyle( - lineStyle.width / 20.0, + lineStyle.width / unitDivisor, lineStyle.color, pixelHintingFlag, scaleMode, @@ -386,18 +376,11 @@ public abstract class ShapeExporterBase implements IShapeExporter { case FILLSTYLE.RADIAL_GRADIENT: case FILLSTYLE.FOCAL_RADIAL_GRADIENT: // Gradient fill - List colors = new ArrayList<>(); - List ratios = new ArrayList<>(); - GRADRECORD gradientRecord; Matrix matrix = new Matrix(fillStyle.gradientMatrix); - for (int gri = 0; gri < fillStyle.gradient.gradientRecords.length; gri++) { - gradientRecord = fillStyle.gradient.gradientRecords[gri]; - colors.add(gradientRecord.color); - ratios.add(gradientRecord.ratio); - } lineGradientStyle( fillStyle.fillStyleType, - colors, ratios, matrix, + fillStyle.gradient.gradientRecords, + matrix, fillStyle.gradient.spreadMode, fillStyle.gradient.interpolationMode, (fillStyle.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyle.gradient).focalPoint : 0 diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java index cecd9857e..8ff12dfb1 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape2Tag.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.SVGShapeExporter; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -71,7 +72,9 @@ public class DefineShape2Tag extends CharacterTag implements BoundedTag, ShapeTa @Override public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { - return shapes.toImage(2, tags); + BitmapExporter exporter = new BitmapExporter(swf, this); + exporter.export(); + return exporter.getImage(); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java index 68b0ae7bd..94e2833aa 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape3Tag.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.SVGShapeExporter; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -76,7 +77,9 @@ public class DefineShape3Tag extends CharacterTag implements BoundedTag, ShapeTa @Override public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { - return shapes.toImage(3, tags); + BitmapExporter exporter = new BitmapExporter(swf, this); + exporter.export(); + return exporter.getImage(); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java index d308e65e5..bd5944b30 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShape4Tag.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.SVGShapeExporter; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -75,7 +76,9 @@ public class DefineShape4Tag extends CharacterTag implements BoundedTag, ShapeTa @Override public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { - return shapes.toImage(4, tags); + BitmapExporter exporter = new BitmapExporter(swf, this); + exporter.export(); + return exporter.getImage(); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java index da4bcecb0..f342852db 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineShapeTag.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.exporters.BitmapExporter; import com.jpexs.decompiler.flash.exporters.SVGShapeExporter; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -105,7 +106,9 @@ public class DefineShapeTag extends CharacterTag implements BoundedTag, ShapeTag @Override public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { - return shapes.toImage(1, tags); + BitmapExporter exporter = new BitmapExporter(swf, this); + exporter.export(); + return exporter.getImage(); } @Override diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java index cb58e96f9..c02281a85 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPEWITHSTYLE.java @@ -47,6 +47,7 @@ public class SHAPEWITHSTYLE implements NeedsCharacters { } public BufferedImage toImage(int shapeNum, List tags) { + // todo: honfika: remove this method return SHAPERECORD.shapeToImage(tags, shapeNum, fillStyles, lineStyles, /*numFillBits, numLineBits,*/ shapeRecords); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java index db344deb4..12b80e494 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/CurvedEdgeRecord.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.types.shaperecords; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; /** 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 9a869a0dc..0f1aa6ff5 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -29,7 +29,6 @@ import com.jpexs.decompiler.flash.types.GRADIENT; import com.jpexs.decompiler.flash.types.LINESTYLE; import com.jpexs.decompiler.flash.types.LINESTYLE2; import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; @@ -56,24 +55,16 @@ import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javax.imageio.ImageIO; import javax.swing.JPanel; -import javax.xml.bind.DatatypeConverter; /** * @@ -95,8 +86,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali public boolean used = false; public LINESTYLE lineStyle; - public LINESTYLE2 lineStyle2; - public boolean useLineStyle2; public FILLSTYLE fillStyle0; public FILLSTYLE fillStyle1; public List edges = new ArrayList<>(); @@ -108,6 +97,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali AffineTransform trans20 = AffineTransform.getScaleInstance(1 / DESCALE, 1 / DESCALE); boolean ok = false; if (shapeNum == 4) { + LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle; if (lineStyle2 == null) { ok = false; } else if (!lineStyle2.hasFillFlag) { @@ -148,11 +138,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali if (lineStyle == null) { ok = false; } else { - if (shapeNum == 1 || shapeNum == 2) { - g.setPaint(lineStyle.color.toColor()); - } else /*shapeNum == 3*/ { - g.setPaint(lineStyle.color.toColor()); - } + g.setPaint(lineStyle.color.toColor()); g.setStroke(new BasicStroke(lineStyle.width / DESCALE, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); ok = true; } @@ -352,7 +338,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali g.fill(new Rectangle(-16384 * maxRepeat, -16384 * maxRepeat, 16384 * 2 * maxRepeat, 16384 * 2 * maxRepeat)); g.setTransform(oldAf); g.setClip(null); - ok = true; return; case FILLSTYLE.SOLID: Color c = null; @@ -423,7 +408,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali } public boolean sameStyle(Path p) { - return fillStyle0 == p.fillStyle0 && ((useLineStyle2 && (p.lineStyle2 == lineStyle2)) || ((!useLineStyle2) && (p.lineStyle == lineStyle))); + return fillStyle0 == p.fillStyle0 && p.lineStyle == lineStyle; } } @@ -479,7 +464,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali FILLSTYLE lastFillStyle0 = null; FILLSTYLE lastFillStyle1 = null; LINESTYLE lastLineStyle = null; - LINESTYLE2 lastLineStyle2 = null; for (SHAPERECORD r : records) { if (r instanceof StyleChangeRecord) { StyleChangeRecord scr = (StyleChangeRecord) r; @@ -518,14 +502,12 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali lastFillStyle1 = path.fillStyle1; if (scr.stateLineStyle) { if (shapeNum >= 4) { - path.useLineStyle2 = true; if (scr.lineStyle == 0) { - path.lineStyle2 = null; + path.lineStyle = null; } else { - path.lineStyle2 = (LINESTYLE2) lineStylesList.lineStyles[scr.lineStyle - 1]; + path.lineStyle = lineStylesList.lineStyles[scr.lineStyle - 1]; } } else { - path.useLineStyle2 = false; if (scr.lineStyle == 0) { path.lineStyle = null; } else { @@ -533,15 +515,10 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali } } } else { - if (shapeNum >= 4) { - path.lineStyle2 = lastLineStyle2; - } else { - path.lineStyle = lastLineStyle; - } + path.lineStyle = lastLineStyle; } lastLineStyle = path.lineStyle; - lastLineStyle2 = path.lineStyle2; if (started && (!scr.stateMoveTo)) { scr.stateMoveTo = true; scr.moveDeltaX = x; @@ -591,8 +568,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali boolean flip = true; f.fillStyle0 = p.fillStyle1; f.lineStyle = p.lineStyle; - f.lineStyle2 = p.lineStyle2; - f.useLineStyle2 = p.useLineStyle2; f.edges = new ArrayList<>(); f.start = p.end; f.end = p.start; @@ -742,7 +717,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali onepath = new Path(); onepath.fillStyle0 = p.fillStyle0; onepath.lineStyle = p.lineStyle; - onepath.lineStyle2 = p.lineStyle2; } if (onepath.start == null) { onepath.start = p.start; @@ -866,7 +840,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); for (Path p : paths) { - if ((p.fillStyle0 == null) && (p.lineStyle == null) && (p.lineStyle2 == null) && (defaultColor != null)) { + if ((p.fillStyle0 == null) && (p.lineStyle == null) && (defaultColor != null)) { p.fillStyle0 = new FILLSTYLE(); p.fillStyle0.fillStyleType = FILLSTYLE.SOLID; p.fillStyle0.color = new RGB(defaultColor); @@ -1072,33 +1046,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Seriali return new Point2D.Double(x, y); } - private static class SerializableImage implements Serializable { - - transient BufferedImage image; - - public BufferedImage getImage() { - return image; - } - - public void setImage(BufferedImage image) { - this.image = image; - } - - public SerializableImage(BufferedImage image) { - this.image = image; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - ImageIO.write(image, "png", out); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - image = ImageIO.read(in); - } - } - public static SHAPE resizeSHAPE(SHAPE shp, int multiplier) { SHAPE ret = new SHAPE(); ret.numFillBits = shp.numFillBits; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SerializableImage.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SerializableImage.java new file mode 100644 index 000000000..219f7cefc --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SerializableImage.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2010-2013 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.types.shaperecords; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import javax.imageio.ImageIO; + +/** + * + * @author JPEXS + */ +public class SerializableImage implements Serializable { + + transient BufferedImage image; + + public BufferedImage getImage() { + return image; + } + + public void setImage(BufferedImage image) { + this.image = image; + } + + public SerializableImage(BufferedImage image) { + this.image = image; + } + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + ImageIO.write(image, "png", out); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + image = ImageIO.read(in); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java index 2524445fc..1ca7b1547 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StraightEdgeRecord.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.types.shaperecords; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; /** diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java index a373e43db..f27d4bb95 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/StyleChangeRecord.java @@ -16,7 +16,6 @@ */ package com.jpexs.decompiler.flash.types.shaperecords; -import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;