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 660a89675..a16771274 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -75,9 +75,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; import com.jpexs.decompiler.flash.ecma.Null; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; @@ -129,11 +127,8 @@ import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.timeline.AS2Package; -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.FrameScript; -import com.jpexs.decompiler.flash.timeline.SvgClip; import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.timeline.Timelined; @@ -145,8 +140,6 @@ import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFField; -import com.jpexs.decompiler.flash.types.filters.BlendComposite; -import com.jpexs.decompiler.flash.types.filters.FILTER; import com.jpexs.decompiler.flash.xfl.FLAVersion; import com.jpexs.decompiler.flash.xfl.XFLConverter; import com.jpexs.decompiler.graph.DottedChain; @@ -166,15 +159,11 @@ import com.jpexs.helpers.ProgressListener; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; import java.awt.AlphaComposite; -import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -195,7 +184,6 @@ import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; -import java.util.Stack; import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -2661,114 +2649,13 @@ public final class SWF implements SWFContainerItem, Timelined { return ret; } - public static void frameToSvg(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException { - if (timeline.getFrameCount() <= frame) { - return; - } - Frame frameObj = timeline.getFrame(frame); - List clips = new ArrayList<>(); - List prevClips = new ArrayList<>(); - - int maxDepth = timeline.getMaxDepth(); - for (int i = 1; i <= maxDepth; i++) { - for (int c = 0; c < clips.size(); c++) { - if (clips.get(c).depth == i) { - exporter.setClip(prevClips.get(c)); - prevClips.remove(c); - clips.remove(c); - } - } - if (!frameObj.layers.containsKey(i)) { - continue; - } - DepthState layer = frameObj.layers.get(i); - if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { - continue; - } - if (!layer.isVisible) { - continue; - } - - CharacterTag character = timeline.swf.getCharacter(layer.characterId); - - ColorTransform clrTrans = colorTransform; - if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode - clrTrans = clrTrans == null ? layer.colorTransForm : colorTransform.merge(layer.colorTransForm); - } - - if (character instanceof DrawableTag) { - DrawableTag drawable = (DrawableTag) character; - - String assetName; - Tag drawableTag = (Tag) drawable; - RECT boundRect = drawable.getRect(); - if (exporter.exportedTags.containsKey(drawableTag)) { - assetName = exporter.exportedTags.get(drawableTag); - } else { - assetName = getTagIdPrefix(drawableTag, exporter); - exporter.exportedTags.put(drawableTag, assetName); - exporter.createDefGroup(new ExportRectangle(boundRect), assetName); - drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, zoom); - exporter.endGroup(); - } - ExportRectangle rect = new ExportRectangle(boundRect); - - // TODO: if (layer.filters != null) - // TODO: if (layer.blendMode > 1) - if (layer.clipDepth > -1) { - String clipName = exporter.getUniqueId("clipPath"); - exporter.createClipPath(new Matrix(), clipName); - SvgClip clip = new SvgClip(clipName, layer.clipDepth); - clips.add(clip); - prevClips.add(exporter.getClip()); - Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName, layer.instanceName); - exporter.setClip(clip.shape); - exporter.endGroup(); - } else { - Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName, layer.instanceName); - } - } - } - } - - private static String getTagIdPrefix(Tag tag, SVGExporter exporter) { - if (tag instanceof ShapeTag) { - return exporter.getUniqueId("shape"); - } - if (tag instanceof MorphShapeTag) { - return exporter.getUniqueId("morphshape"); - } - if (tag instanceof DefineSpriteTag) { - return exporter.getUniqueId("sprite"); - } - if (tag instanceof TextTag) { - return exporter.getUniqueId("text"); - } - if (tag instanceof ButtonTag) { - return exporter.getUniqueId("button"); - } - return exporter.getUniqueId("tag"); - } - - public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, Point cursorPosition, int mouseButton, RECT displayRect, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, Color backGroundColor, boolean useCache, double zoom) { - SWF swf = timeline.swf; - String key = "frame_" + frame + "_" + time + "_" + timeline.id + "_" + swf.hashCode() + "_" + zoom; - SerializableImage image; - if (useCache) { - image = swf.getFromCache(key); - if (image != null) { - return image; - } - } - + public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, Point cursorPosition, int mouseButton, RECT displayRect, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, Color backGroundColor, double zoom) { if (timeline.getFrameCount() == 0) { return new SerializableImage(1, 1, SerializableImage.TYPE_INT_ARGB); } RECT rect = displayRect; - image = new SerializableImage((int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1, + SerializableImage image = new SerializableImage((int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1, (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); if (backGroundColor == null) { image.fillTransparent(); @@ -2785,303 +2672,11 @@ public final class SWF implements SWFContainerItem, Timelined { RenderContext renderContext = new RenderContext(); renderContext.cursorPosition = cursorPosition; renderContext.mouseButton = mouseButton; - frameToImage(timeline, frame, time, renderContext, image, false, m, absoluteTransformation, colorTransform); - if (useCache) { - swf.putToCache(key, image); - } + timeline.toImage(frame, time, 0, renderContext, image, false, m, absoluteTransformation, colorTransform); return image; } - public static void framesToImage(Timeline timeline, List ret, int startFrame, int stopFrame, RenderContext renderContext, RECT displayRect, int totalFrameCount, Stack visited, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform, double zoom) { - RECT rect = displayRect; - for (int f = 0; f < timeline.getFrameCount(); f++) { - SerializableImage image = new SerializableImage((int) (rect.getWidth() / SWF.unitDivisor) + 1, - (int) (rect.getHeight() / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB); - image.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin, -rect.Ymin); - frameToImage(timeline, f, 0, renderContext, image, false, m, absoluteTransformation, colorTransform); - ret.add(image); - } - } - - public static void frameToImage(Timeline timeline, int frame, int time, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - double unzoom = SWF.unitDivisor; - if (timeline.getFrameCount() <= frame) { - return; - } - Frame frameObj = timeline.getFrame(frame); - Graphics2D g = (Graphics2D) image.getGraphics(); - g.setPaint(frameObj.backgroundColor.toColor()); - g.fill(new Rectangle(image.getWidth(), image.getHeight())); - g.setTransform(transformation.toTransform()); - List clips = new ArrayList<>(); - List prevClips = new ArrayList<>(); - - int maxDepth = timeline.getMaxDepth(); - for (int i = 1; i <= maxDepth; i++) { - for (int c = 0; c < clips.size(); c++) { - if (clips.get(c).depth == i) { - g.setClip(prevClips.get(c)); - prevClips.remove(c); - clips.remove(c); - } - } - if (!frameObj.layers.containsKey(i)) { - continue; - } - DepthState layer = frameObj.layers.get(i); - if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { - continue; - } - if (!layer.isVisible) { - continue; - } - - CharacterTag character = timeline.swf.getCharacter(layer.characterId); - Matrix layerMatrix = new Matrix(layer.matrix); - Matrix mat = transformation.concatenate(layerMatrix); - Matrix absMat = absoluteTransformation.concatenate(layerMatrix); - - ColorTransform clrTrans = colorTransform; - if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode - clrTrans = clrTrans == null ? layer.colorTransForm : colorTransform.merge(layer.colorTransForm); - } - - boolean showPlaceholder = false; - if (character instanceof DrawableTag) { - DrawableTag drawable = (DrawableTag) character; - Matrix drawMatrix = new Matrix(); - int drawableFrameCount = drawable.getNumFrames(); - if (drawableFrameCount == 0) { - drawableFrameCount = 1; - } - - RECT boundRect = drawable.getRect(); - ExportRectangle rect = new ExportRectangle(boundRect); - rect = mat.transform(rect); - Matrix m = mat.clone(); - if (layer.filters != null && layer.filters.size() > 0) { - // 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 * unzoom; - rect.xMax += deltaXMax * unzoom; - rect.yMin -= deltaYMax * unzoom; - rect.yMax += deltaYMax * unzoom; - } - - rect.xMin -= 1 * unzoom; - rect.yMin -= 1 * unzoom; - rect.xMin = Math.max(0, rect.xMin); - rect.yMin = Math.max(0, rect.yMin); - - int newWidth = (int) (rect.getWidth() / unzoom); - int newHeight = (int) (rect.getHeight() / unzoom); - int deltaX = (int) (rect.xMin / unzoom); - int deltaY = (int) (rect.yMin / unzoom); - newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; - newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; - - if (newWidth <= 0 || newHeight <= 0) { - continue; - } - - m.translate(-rect.xMin, -rect.yMin); - drawMatrix.translate(rect.xMin, rect.yMin); - - SerializableImage img = null; - String cacheKey = null; - if (drawable instanceof ShapeTag) { - cacheKey = ((ShapeTag) drawable).getCharacterId() + m.toString() + (clrTrans == null ? "" : clrTrans.toString()); - img = renderContext.shapeCache.get(cacheKey); - } - - int dframe; - if (timeline.fontFrameNum != -1) { - dframe = timeline.fontFrameNum; - } else { - dframe = time % drawableFrameCount; - } - - if (character instanceof ButtonTag) { - dframe = ButtonTag.FRAME_UP; - if (renderContext.cursorPosition != null) { - Shape buttonShape = drawable.getOutline(ButtonTag.FRAME_HITTEST, time, layer.ratio, renderContext, absMat); - if (buttonShape.contains(renderContext.cursorPosition)) { - renderContext.mouseOverButton = (ButtonTag) character; - if (renderContext.mouseButton > 0) { - dframe = ButtonTag.FRAME_DOWN; - } else { - dframe = ButtonTag.FRAME_OVER; - } - } - } - } - - int stateCount = renderContext.stateUnderCursor == null ? 0 : renderContext.stateUnderCursor.size(); - if (img == null) { - img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); - img.fillTransparent(); - - drawable.toImage(dframe, time, layer.ratio, renderContext, img, isClip || layer.clipDepth > -1, m, absMat, clrTrans); - - if (cacheKey != null) { - renderContext.shapeCache.put(cacheKey, img); - } - } - - /*//if (renderContext.stateUnderCursor == layer) { - if (true) { - BufferedImage bi = img.getBufferedImage(); - ColorModel cm = bi.getColorModel(); - boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); - WritableRaster raster = bi.copyData(null); - img = new SerializableImage(new BufferedImage(cm, raster, isAlphaPremultiplied, null)); - 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(dframe, layer.time + time, layer.ratio, renderContext, m))); - }*/ - if (layer.filters != null) { - for (FILTER filter : layer.filters) { - img = filter.apply(img); - } - } - if (layer.blendMode > 1) { - if (layer.colorTransForm != null) { - img = layer.colorTransForm.apply(img); - } - } - - drawMatrix.translateX /= unzoom; - drawMatrix.translateY /= unzoom; - AffineTransform trans = drawMatrix.toTransform(); - - switch (layer.blendMode) { - case 0: - case 1: - g.setComposite(AlphaComposite.SrcOver); - break; - case 2: // Layer - g.setComposite(AlphaComposite.SrcOver); - break; - case 3: - g.setComposite(BlendComposite.Multiply); - break; - case 4: - g.setComposite(BlendComposite.Screen); - break; - case 5: - g.setComposite(BlendComposite.Lighten); - break; - case 6: - g.setComposite(BlendComposite.Darken); - break; - case 7: - g.setComposite(BlendComposite.Difference); - break; - case 8: - g.setComposite(BlendComposite.Add); - break; - case 9: - g.setComposite(BlendComposite.Subtract); - break; - case 10: - g.setComposite(BlendComposite.Invert); - break; - case 11: - g.setComposite(BlendComposite.Alpha); - break; - case 12: - g.setComposite(BlendComposite.Erase); - break; - case 13: - g.setComposite(BlendComposite.Overlay); - break; - case 14: - g.setComposite(BlendComposite.HardLight); - break; - default: // Not implemented - g.setComposite(AlphaComposite.SrcOver); - break; - } - - if (layer.clipDepth > -1) { - BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType()); - Graphics2D gm = (Graphics2D) mask.getGraphics(); - gm.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); - gm.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - gm.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - gm.setComposite(AlphaComposite.Src); - gm.setColor(new Color(0, 0, 0, 0f)); - gm.fillRect(0, 0, image.getWidth(), image.getHeight()); - gm.setTransform(trans); - gm.drawImage(img.getBufferedImage(), 0, 0, null); - Clip clip = new Clip(Helper.imageToShape(mask), layer.clipDepth); // Maybe we can get current outline instead converting from image (?) - clips.add(clip); - prevClips.add(g.getClip()); - g.setTransform(AffineTransform.getTranslateInstance(0, 0)); - g.setClip(clip.shape); - } else { - if (renderContext.cursorPosition != null) { - if (drawable instanceof DefineSpriteTag) { - if (renderContext.stateUnderCursor.size() > stateCount) { - renderContext.stateUnderCursor.add(layer); - } - } else if (absMat.transform(new ExportRectangle(boundRect)).contains(renderContext.cursorPosition)) { - Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat); - if (shape.contains(renderContext.cursorPosition)) { - renderContext.stateUnderCursor.add(layer); - } - } - } - - if (renderContext.borderImage != null) { - Graphics2D g2 = (Graphics2D) renderContext.borderImage.getGraphics(); - g2.setPaint(Color.red); - g2.setStroke(new BasicStroke(2)); - Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor))); - g2.draw(shape); - } - - g.setTransform(trans); - g.drawImage(img.getBufferedImage(), 0, 0, null); - } - } else if (character instanceof BoundedTag) { - showPlaceholder = true; - } - - if (showPlaceholder) { - Matrix mat2 = mat.clone(); - mat2.translateX /= unzoom; - mat2.translateY /= unzoom; - AffineTransform trans = mat2.toTransform(); - g.setTransform(trans); - BoundedTag b = (BoundedTag) character; - g.setPaint(new Color(255, 255, 255, 128)); - g.setComposite(BlendComposite.Invert); - RECT r = b.getRect(); - int div = (int) unzoom; - g.drawString(character.toString(), r.Xmin / div + 3, r.Ymin / div + 15); - g.draw(new Rectangle(r.Xmin / div, r.Ymin / div, r.getWidth() / div, r.getHeight() / div)); - g.drawLine(r.Xmin / div, r.Ymin / div, r.Xmax / div, r.Ymax / div); - g.drawLine(r.Xmax / div, r.Ymin / div, r.Xmin / div, r.Ymax / div); - g.setComposite(AlphaComposite.Dst); - } - } - - g.setTransform(AffineTransform.getScaleInstance(1, 1)); - } - private void removeTagWithDependenciesFromTimeline(Tag toRemove, Timeline timeline) { Map stage = new HashMap<>(); Set dependingChars = new HashSet<>(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java index 5b856dbfc..27862d198 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/abc/ABC.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.abc; +import com.jpexs.decompiler.flash.EndOfStreamException; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.abc.avm2.AVM2Code; @@ -54,6 +55,7 @@ import com.jpexs.decompiler.flash.abc.usages.MethodParamsMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MethodReturnTypeMultinameUsage; import com.jpexs.decompiler.flash.abc.usages.MultinameUsage; import com.jpexs.decompiler.flash.abc.usages.TypeNameMultinameUsage; +import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.Tag; @@ -543,29 +545,36 @@ public class ABC { int bodies_count = ais.readU30("bodies_count"); bodies = new ArrayList<>(bodies_count); for (int i = 0; i < bodies_count; i++) { + DumpInfo di = ais.dumpInfo; ais.newDumpLevel("method_body", "method_body_info"); MethodBody mb = new MethodBody(this, null, null, null); // do not create Traits in constructor - mb.method_info = ais.readU30("method_info"); - mb.max_stack = ais.readU30("max_stack"); - mb.max_regs = ais.readU30("max_regs"); - mb.init_scope_depth = ais.readU30("init_scope_depth"); - mb.max_scope_depth = ais.readU30("max_scope_depth"); - int code_length = ais.readU30("code_length"); - mb.setCodeBytes(ais.readBytes(code_length, "code")); - int ex_count = ais.readU30("ex_count"); - mb.exceptions = new ABCException[ex_count]; - for (int j = 0; j < ex_count; j++) { - ABCException abce = new ABCException(); - abce.start = ais.readU30("start"); - abce.end = ais.readU30("end"); - abce.target = ais.readU30("target"); - abce.type_index = ais.readU30("type_index"); - abce.name_index = ais.readU30("name_index"); - mb.exceptions[j] = abce; + try { + mb.method_info = ais.readU30("method_info"); + mb.max_stack = ais.readU30("max_stack"); + mb.max_regs = ais.readU30("max_regs"); + mb.init_scope_depth = ais.readU30("init_scope_depth"); + mb.max_scope_depth = ais.readU30("max_scope_depth"); + int code_length = ais.readU30("code_length"); + mb.setCodeBytes(ais.readBytes(code_length, "code")); + int ex_count = ais.readU30("ex_count"); + mb.exceptions = new ABCException[ex_count]; + for (int j = 0; j < ex_count; j++) { + ABCException abce = new ABCException(); + abce.start = ais.readU30("start"); + abce.end = ais.readU30("end"); + abce.target = ais.readU30("target"); + abce.type_index = ais.readU30("type_index"); + abce.name_index = ais.readU30("name_index"); + mb.exceptions[j] = abce; + } + mb.traits = ais.readTraits("traits"); + bodies.add(mb); + ais.endDumpLevel(); + } catch (EndOfStreamException ex) { + logger.log(Level.SEVERE, "MethodBody reading: End of stream", ex); + ais.endDumpLevelUntil(di); + break; } - mb.traits = ais.readTraits("traits"); - bodies.add(mb); - ais.endDumpLevel(); SWFDecompilerPlugin.fireMethodBodyParsed(mb, swf); } 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 826d6645b..0faab1a9e 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 @@ -200,7 +200,8 @@ public class FrameExporter { if (fbackgroundColor != null) { exporter.setBackGroundColor(fbackgroundColor); } - SWF.frameToSvg(tim, frame, 0, null, 0, exporter, null, 0, settings.zoom); + + tim.toSVG(frame, 0, null, 0, exporter, null, 0, settings.zoom); fos.write(Utf8Helper.getBytes(exporter.getSVG())); } ret.add(f); @@ -359,7 +360,7 @@ public class FrameExporter { } int fframe = fframes.get(pos++); - BufferedImage result = SWF.frameToImageGet(ftim, fframe, fframe, null, 0, ftim.displayRect, new Matrix(), new Matrix(), null, fbackgroundColor, false, settings.zoom).getBufferedImage(); + BufferedImage result = SWF.frameToImageGet(ftim, fframe, fframe, null, 0, ftim.displayRect, new Matrix(), new Matrix(), null, fbackgroundColor, settings.zoom).getBufferedImage(); if (evl != null) { evl.handleExportedEvent("frame", pos, fframes.size(), tagName); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index b74d3679f..927324cb8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -50,7 +50,7 @@ public class DefineFont2Tag extends FontTag { public static final String NAME = "DefineFont2"; @SWFType(BasicType.UI16) - public int fontId; + public int fontID; public boolean fontFlagsHasLayout; @@ -106,7 +106,7 @@ public class DefineFont2Tag extends FontTag { */ public DefineFont2Tag(SWF swf) { super(swf, ID, NAME, null); - fontId = swf.getNextCharacterId(); + fontID = swf.getNextCharacterId(); languageCode = new LANGCODE(); fontName = "New font"; glyphShapeTable = new ArrayList<>(); @@ -127,7 +127,7 @@ public class DefineFont2Tag extends FontTag { @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); + fontID = sis.readUI16("fontId"); fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; @@ -246,7 +246,7 @@ public class DefineFont2Tag extends FontTag { @Override public void getData(SWFOutputStream sos) throws IOException { checkWideParameters(); - sos.writeUI16(fontId); + sos.writeUI16(fontID); sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); sos.writeUB(1, fontFlagsSmallText ? 1 : 0); @@ -348,12 +348,12 @@ public class DefineFont2Tag extends FontTag { @Override public int getCharacterId() { - return fontId; + return fontID; } @Override public void setCharacterId(int characterId) { - this.fontId = characterId; + this.fontID = characterId; } @Override @@ -467,7 +467,7 @@ public class DefineFont2Tag extends FontTag { } if (!exists) { - shiftGlyphIndices(fontId, pos); + shiftGlyphIndices(fontID, pos); glyphShapeTable.add(pos, shp); codeTable.add(pos, (int) character); } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index 6ce6a01d6..435954903 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -50,7 +50,7 @@ public class DefineFont3Tag extends FontTag { public static final String NAME = "DefineFont3"; @SWFType(BasicType.UI16) - public int fontId; + public int fontID; public boolean fontFlagsHasLayout; @@ -106,7 +106,7 @@ public class DefineFont3Tag extends FontTag { */ public DefineFont3Tag(SWF swf) { super(swf, ID, NAME, null); - fontId = swf.getNextCharacterId(); + fontID = swf.getNextCharacterId(); languageCode = new LANGCODE(); fontName = "New font"; glyphShapeTable = new ArrayList<>(); @@ -120,7 +120,7 @@ public class DefineFont3Tag extends FontTag { @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); + fontID = sis.readUI16("fontId"); fontFlagsHasLayout = sis.readUB(1, "fontFlagsHasLayout") == 1; fontFlagsShiftJIS = sis.readUB(1, "fontFlagsShiftJIS") == 1; fontFlagsSmallText = sis.readUB(1, "fontFlagsSmallText") == 1; @@ -246,7 +246,7 @@ public class DefineFont3Tag extends FontTag { } byte[] baGlyphShapes = baosGlyphShapes.toByteArray(); - sos.writeUI16(fontId); + sos.writeUI16(fontID); sos.writeUB(1, fontFlagsHasLayout ? 1 : 0); sos.writeUB(1, fontFlagsShiftJIS ? 1 : 0); sos.writeUB(1, fontFlagsSmallText ? 1 : 0); @@ -341,12 +341,12 @@ public class DefineFont3Tag extends FontTag { @Override public int getCharacterId() { - return fontId; + return fontID; } @Override public void setCharacterId(int characterId) { - this.fontId = characterId; + this.fontID = characterId; } @Override @@ -435,7 +435,7 @@ public class DefineFont3Tag extends FontTag { Tag t = swf.getTags().get(i); if (t instanceof DefineFontAlignZonesTag) { DefineFontAlignZonesTag fa = (DefineFontAlignZonesTag) t; - if (fa.fontID == fontId) { + if (fa.fontID == fontID) { swf.removeTag(t); i--; } @@ -460,7 +460,7 @@ public class DefineFont3Tag extends FontTag { } if (!exists) { - shiftGlyphIndices(fontId, pos); + shiftGlyphIndices(fontID, pos); glyphShapeTable.add(pos, shp); codeTable.add(pos, (int) character); } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index dd24064ac..e1dff7a29 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -19,7 +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.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.FontInfoTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.LANGCODE; import com.jpexs.decompiler.flash.types.annotations.Reserved; @@ -36,15 +36,12 @@ import java.util.List; * @author JPEXS */ @SWFVersion(from = 6) -public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { +public class DefineFontInfo2Tag extends FontInfoTag { public static final int ID = 62; public static final String NAME = "DefineFontInfo2"; - @SWFType(BasicType.UI16) - public int fontID; - public String fontName; @Reserved @@ -143,12 +140,38 @@ public class DefineFontInfo2Tag extends Tag implements CharacterIdTag { } @Override - public int getCharacterId() { - return fontID; + public List getCodeTable() { + return codeTable; } @Override - public void setCharacterId(int characterId) { - this.fontID = characterId; + public void addCharacter(int index, int character) { + codeTable.add(index, character); + setModified(true); + } + + @Override + public String getFontName() { + return fontName; + } + + @Override + public boolean getFontFlagsBold() { + return fontFlagsBold; + } + + @Override + public void setFontFlagsBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public boolean getFontFlagsItalic() { + return fontFlagsItalic; + } + + @Override + public void setFontFlagsItalic(boolean value) { + fontFlagsItalic = value; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java index b732f76f9..396dd4c8d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontInfoTag.java @@ -19,7 +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.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.FontInfoTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -35,15 +35,12 @@ import java.util.List; * @author JPEXS */ @SWFVersion(from = 1) -public class DefineFontInfoTag extends Tag implements CharacterIdTag { +public class DefineFontInfoTag extends FontInfoTag { public static final int ID = 13; public static final String NAME = "DefineFontInfo"; - @SWFType(BasicType.UI16) - public int fontId; - public String fontName; @Reserved @@ -90,7 +87,7 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - fontId = sis.readUI16("fontId"); + fontID = sis.readUI16("fontId"); if (swf.version >= 6) { fontName = sis.readNetString("fontName", Utf8Helper.charset); } else { @@ -121,7 +118,7 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { */ @Override public void getData(SWFOutputStream sos) throws IOException { - sos.writeUI16(fontId); + sos.writeUI16(fontID); if (swf.version >= 6) { sos.writeNetString(fontName, Utf8Helper.charset); } else { @@ -144,12 +141,38 @@ public class DefineFontInfoTag extends Tag implements CharacterIdTag { } @Override - public int getCharacterId() { - return fontId; + public List getCodeTable() { + return codeTable; } @Override - public void setCharacterId(int characterId) { - this.fontId = characterId; + public void addCharacter(int index, int character) { + codeTable.add(index, character); + setModified(true); + } + + @Override + public String getFontName() { + return fontName; + } + + @Override + public boolean getFontFlagsBold() { + return fontFlagsBold; + } + + @Override + public void setFontFlagsBold(boolean value) { + fontFlagsBold = value; + } + + @Override + public boolean getFontFlagsItalic() { + return fontFlagsItalic; + } + + @Override + public void setFontFlagsItalic(boolean value) { + fontFlagsItalic = value; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index e53fb6949..bdb9a3f8a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -19,6 +19,8 @@ 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.tags.base.CharacterIdTag; +import com.jpexs.decompiler.flash.tags.base.FontInfoTag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.SHAPE; @@ -50,10 +52,7 @@ public class DefineFontTag extends FontTag { public List glyphShapeTable; @Internal - private DefineFontInfoTag fontInfoTag = null; - - @Internal - private DefineFontInfo2Tag fontInfo2Tag = null; + private FontInfoTag fontInfoTag = null; /** * Constructor @@ -139,17 +138,14 @@ public class DefineFontTag extends FontTag { private void ensureFontInfo() { if (fontInfoTag == null) { - for (Tag t : swf.getTags()) { - if (t instanceof DefineFontInfoTag) { - if (((DefineFontInfoTag) t).fontId == fontId) { - fontInfoTag = (DefineFontInfoTag) t; - break; - } - } - if (t instanceof DefineFontInfo2Tag) { - if (((DefineFontInfo2Tag) t).fontID == fontId) { - fontInfo2Tag = (DefineFontInfo2Tag) t; - break; + List characterIdTags = swf.getCharacterIdTags(fontId); + if (characterIdTags != null) { + for (CharacterIdTag t : characterIdTags) { + if (t instanceof FontInfoTag) { + if (((FontInfoTag) t).fontID == fontId) { + fontInfoTag = (FontInfoTag) t; + break; + } } } } @@ -159,10 +155,8 @@ public class DefineFontTag extends FontTag { @Override public char glyphToChar(int glyphIndex) { ensureFontInfo(); - if (fontInfo2Tag != null) { - return (char) (int) fontInfo2Tag.codeTable.get(glyphIndex); - } else if (fontInfoTag != null) { - return (char) (int) fontInfoTag.codeTable.get(glyphIndex); + if (fontInfoTag != null) { + return (char) (int) fontInfoTag.getCodeTable().get(glyphIndex); } else { return '?'; } @@ -171,10 +165,8 @@ public class DefineFontTag extends FontTag { @Override public int charToGlyph(char c) { ensureFontInfo(); - if (fontInfo2Tag != null) { - return fontInfo2Tag.codeTable.indexOf((int) c); - } else if (fontInfoTag != null) { - return fontInfoTag.codeTable.indexOf((int) c); + if (fontInfoTag != null) { + return fontInfoTag.getCodeTable().indexOf((int) c); } return -1; @@ -198,33 +190,24 @@ public class DefineFontTag extends FontTag { @Override public String getFontNameIntag() { ensureFontInfo(); - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontName; - } if (fontInfoTag != null) { - return fontInfoTag.fontName; + return fontInfoTag.getFontName(); } return null; } @Override public boolean isBold() { - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontFlagsBold; - } if (fontInfoTag != null) { - return fontInfoTag.fontFlagsBold; + return fontInfoTag.getFontFlagsBold(); } return false; } @Override public boolean isItalic() { - if (fontInfo2Tag != null) { - return fontInfo2Tag.fontFlagsItalic; - } if (fontInfoTag != null) { - return fontInfoTag.fontFlagsItalic; + return fontInfoTag.getFontFlagsItalic(); } return false; } @@ -236,12 +219,12 @@ public class DefineFontTag extends FontTag { @Override public boolean isBoldEditable() { - return fontInfo2Tag != null || fontInfoTag != null; + return fontInfoTag != null; } @Override public boolean isItalicEditable() { - return fontInfo2Tag != null || fontInfoTag != null; + return fontInfoTag != null; } @Override @@ -250,21 +233,15 @@ public class DefineFontTag extends FontTag { @Override public void setBold(boolean value) { - if (fontInfo2Tag != null) { - fontInfo2Tag.fontFlagsBold = value; - } if (fontInfoTag != null) { - fontInfoTag.fontFlagsBold = value; + fontInfoTag.setFontFlagsBold(value); } } @Override public void setItalic(boolean value) { - if (fontInfo2Tag != null) { - fontInfo2Tag.fontFlagsItalic = value; - } if (fontInfoTag != null) { - fontInfoTag.fontFlagsItalic = value; + fontInfoTag.setFontFlagsItalic(value); } } @@ -291,33 +268,36 @@ public class DefineFontTag extends FontTag { @Override public void addCharacter(char character, Font font) { SHAPE shp = SHAPERECORD.fontCharacterToSHAPE(font, (int) Math.round(getDivider() * 1024), character); - List codeTable = new ArrayList<>(); ensureFontInfo(); - if (fontInfoTag != null) { - codeTable = fontInfoTag.codeTable; - } - if (fontInfo2Tag != null) { - codeTable = fontInfo2Tag.codeTable; - } int code = (int) character; int pos = -1; boolean exists = false; - for (int i = 0; i < codeTable.size(); i++) { - if (codeTable.get(i) >= code) { - if (codeTable.get(i) == code) { - exists = true; + if (fontInfoTag != null) { + List codeTable = fontInfoTag.getCodeTable(); + for (int i = 0; i < codeTable.size(); i++) { + if (codeTable.get(i) >= code) { + if (codeTable.get(i) == code) { + exists = true; + } + + pos = i; + break; } - pos = i; - break; } + + if (pos == -1) { + pos = codeTable.size(); + } + } else { + pos = 0; } - if (pos == -1) { - pos = codeTable.size(); - } + if (!exists) { shiftGlyphIndices(fontId, pos); glyphShapeTable.add(pos, shp); - codeTable.add(pos, (int) character); + if (fontInfoTag != null) { + fontInfoTag.addCharacter(pos, (int) character); + } } else { glyphShapeTable.set(pos, shp); } @@ -335,12 +315,7 @@ public class DefineFontTag extends FontTag { StringBuilder ret = new StringBuilder(); ensureFontInfo(); if (fontInfoTag != null) { - for (int i : fontInfoTag.codeTable) { - ret.append((char) i); - } - } - if (fontInfo2Tag != null) { - for (int i : fontInfo2Tag.codeTable) { + for (int i : fontInfoTag.getCodeTable()) { ret.append((char) i); } } 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 fe7eb7c77..f97134552 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 @@ -367,12 +367,12 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - SWF.frameToImage(getTimeline(), frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform); + getTimeline().toImage(frame, time, ratio, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform); } @Override public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { - SWF.frameToSvg(getTimeline(), 0, 0, null, 0, exporter, colorTransform, level + 1, zoom); + getTimeline().toSVG(0, 0, null, 0, exporter, colorTransform, level + 1, zoom); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABC2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABC2Tag.java index 896773111..67245e787 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABC2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DoABC2Tag.java @@ -92,6 +92,7 @@ public class DoABC2Tag extends Tag implements ABCContainerTag { name = sis.readString("name"); ABCInputStream ais = new ABCInputStream(sis.getBaseStream()); + // put it to the dumpview: sis.readByteRangeEx(sis.available(), "abcBytes"); abc = new ABC(ais, swf, this); 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 93db4e8ab..702997a61 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 @@ -93,12 +93,12 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - SWF.frameToImage(getTimeline(), frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform); + getTimeline().toImage(frame, time, ratio, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform); } @Override public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) throws IOException { - SWF.frameToSvg(getTimeline(), 0, 0, null, 0, exporter, colorTransform, level + 1, zoom); + getTimeline().toSVG(0, 0, null, 0, exporter, colorTransform, level + 1, zoom); } public DefineButtonSoundTag getSounds() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontInfoTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontInfoTag.java new file mode 100644 index 000000000..5662d20ba --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontInfoTag.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2010-2016 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.base; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import java.util.List; + +/** + * + * @author JPEXS + */ +public abstract class FontInfoTag extends Tag implements CharacterIdTag { + + @SWFType(BasicType.UI16) + public int fontID; + + public FontInfoTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + public abstract List getCodeTable(); + + public abstract void addCharacter(int index, int character); + + @Override + public int getCharacterId() { + return fontID; + } + + @Override + public void setCharacterId(int characterId) { + this.fontID = characterId; + } + + public abstract String getFontName(); + + public abstract boolean getFontFlagsBold(); + + public abstract void setFontFlagsBold(boolean value); + + public abstract boolean getFontFlagsItalic(); + + public abstract void setFontFlagsItalic(boolean value); +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java index d3aeaa25e..746f7537c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineCompactedFont.java @@ -371,7 +371,7 @@ public final class DefineCompactedFont extends FontTag { @Override public FontTag toClassicFont() { DefineFont2Tag ret = new DefineFont2Tag(swf); - ret.fontId = getFontId(); + ret.fontID = getFontId(); ret.fontFlagsBold = isBold(); ret.fontFlagsItalic = isItalic(); ret.fontFlagsWideOffsets = true; 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 48d3fedf0..5de944708 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 @@ -18,7 +18,9 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.FrameExporter; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.DoInitActionTag; @@ -31,24 +33,38 @@ import com.jpexs.decompiler.flash.tags.StartSoundTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ASMSource; import com.jpexs.decompiler.flash.tags.base.ASMSourceContainer; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.DrawableTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.base.RemoveTag; import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; +import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.types.CLIPACTIONS; 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.filters.BlendComposite; import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.helpers.Helper; import com.jpexs.helpers.SerializableImage; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; +import java.awt.RenderingHints; import java.awt.Shape; +import java.awt.geom.AffineTransform; import java.awt.geom.Area; +import java.awt.image.BufferedImage; +import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -531,7 +547,385 @@ public class Timeline { } public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix absoluteTransformation, ColorTransform colorTransform) { - SWF.frameToImage(this, frame, time, renderContext, image, isClip, transformation, absoluteTransformation, colorTransform); + double unzoom = SWF.unitDivisor; + if (getFrameCount() <= frame) { + return; + } + + Frame frameObj = getFrame(frame); + Graphics2D g = (Graphics2D) image.getGraphics(); + g.setPaint(frameObj.backgroundColor.toColor()); + g.fill(new Rectangle(image.getWidth(), image.getHeight())); + g.setTransform(transformation.toTransform()); + List clips = new ArrayList<>(); + List prevClips = new ArrayList<>(); + + int maxDepth = getMaxDepth(); + for (int i = 1; i <= maxDepth; i++) { + for (int c = 0; c < clips.size(); c++) { + if (clips.get(c).depth == i) { + g.setClip(prevClips.get(c)); + prevClips.remove(c); + clips.remove(c); + } + } + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!swf.getCharacters().containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + + CharacterTag character = swf.getCharacter(layer.characterId); + Matrix layerMatrix = new Matrix(layer.matrix); + Matrix mat = transformation.concatenate(layerMatrix); + Matrix absMat = absoluteTransformation.concatenate(layerMatrix); + + ColorTransform clrTrans = colorTransform; + if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode + clrTrans = clrTrans == null ? layer.colorTransForm : colorTransform.merge(layer.colorTransForm); + } + + boolean showPlaceholder = false; + if (character instanceof DrawableTag) { + DrawableTag drawable = (DrawableTag) character; + Matrix drawMatrix = new Matrix(); + int drawableFrameCount = drawable.getNumFrames(); + if (drawableFrameCount == 0) { + drawableFrameCount = 1; + } + + RECT boundRect = drawable.getRect(); + ExportRectangle rect = new ExportRectangle(boundRect); + rect = mat.transform(rect); + Matrix m = mat.clone(); + if (layer.filters != null && layer.filters.size() > 0) { + // 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 * unzoom; + rect.xMax += deltaXMax * unzoom; + rect.yMin -= deltaYMax * unzoom; + rect.yMax += deltaYMax * unzoom; + } + + rect.xMin -= 1 * unzoom; + rect.yMin -= 1 * unzoom; + rect.xMin = Math.max(0, rect.xMin); + rect.yMin = Math.max(0, rect.yMin); + + int newWidth = (int) (rect.getWidth() / unzoom); + int newHeight = (int) (rect.getHeight() / unzoom); + int deltaX = (int) (rect.xMin / unzoom); + int deltaY = (int) (rect.yMin / unzoom); + newWidth = Math.min(image.getWidth() - deltaX, newWidth) + 1; + newHeight = Math.min(image.getHeight() - deltaY, newHeight) + 1; + + if (newWidth <= 0 || newHeight <= 0) { + continue; + } + + m.translate(-rect.xMin, -rect.yMin); + drawMatrix.translate(rect.xMin, rect.yMin); + + SerializableImage img = null; + String cacheKey = null; + if (drawable instanceof ShapeTag) { + cacheKey = ((ShapeTag) drawable).getCharacterId() + m.toString() + (clrTrans == null ? "" : clrTrans.toString()); + img = renderContext.shapeCache.get(cacheKey); + } + + int dframe; + if (fontFrameNum != -1) { + dframe = fontFrameNum; + } else { + dframe = time % drawableFrameCount; + } + + if (character instanceof ButtonTag) { + dframe = ButtonTag.FRAME_UP; + if (renderContext.cursorPosition != null) { + Shape buttonShape = drawable.getOutline(ButtonTag.FRAME_HITTEST, time, layer.ratio, renderContext, absMat); + if (buttonShape.contains(renderContext.cursorPosition)) { + renderContext.mouseOverButton = (ButtonTag) character; + if (renderContext.mouseButton > 0) { + dframe = ButtonTag.FRAME_DOWN; + } else { + dframe = ButtonTag.FRAME_OVER; + } + } + } + } + + int stateCount = renderContext.stateUnderCursor == null ? 0 : renderContext.stateUnderCursor.size(); + if (img == null) { + img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); + img.fillTransparent(); + + drawable.toImage(dframe, time, layer.ratio, renderContext, img, isClip || layer.clipDepth > -1, m, absMat, clrTrans); + + if (cacheKey != null) { + renderContext.shapeCache.put(cacheKey, img); + } + } + + /*//if (renderContext.stateUnderCursor == layer) { + if (true) { + BufferedImage bi = img.getBufferedImage(); + ColorModel cm = bi.getColorModel(); + boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); + WritableRaster raster = bi.copyData(null); + img = new SerializableImage(new BufferedImage(cm, raster, isAlphaPremultiplied, null)); + 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(dframe, layer.time + time, layer.ratio, renderContext, m))); + }*/ + if (layer.filters != null) { + for (FILTER filter : layer.filters) { + img = filter.apply(img); + } + } + if (layer.blendMode > 1) { + if (layer.colorTransForm != null) { + img = layer.colorTransForm.apply(img); + } + } + + drawMatrix.translateX /= unzoom; + drawMatrix.translateY /= unzoom; + AffineTransform trans = drawMatrix.toTransform(); + + switch (layer.blendMode) { + case 0: + case 1: + g.setComposite(AlphaComposite.SrcOver); + break; + case 2: // Layer + g.setComposite(AlphaComposite.SrcOver); + break; + case 3: + g.setComposite(BlendComposite.Multiply); + break; + case 4: + g.setComposite(BlendComposite.Screen); + break; + case 5: + g.setComposite(BlendComposite.Lighten); + break; + case 6: + g.setComposite(BlendComposite.Darken); + break; + case 7: + g.setComposite(BlendComposite.Difference); + break; + case 8: + g.setComposite(BlendComposite.Add); + break; + case 9: + g.setComposite(BlendComposite.Subtract); + break; + case 10: + g.setComposite(BlendComposite.Invert); + break; + case 11: + g.setComposite(BlendComposite.Alpha); + break; + case 12: + g.setComposite(BlendComposite.Erase); + break; + case 13: + g.setComposite(BlendComposite.Overlay); + break; + case 14: + g.setComposite(BlendComposite.HardLight); + break; + default: // Not implemented + g.setComposite(AlphaComposite.SrcOver); + break; + } + + if (layer.clipDepth > -1) { + BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType()); + Graphics2D gm = (Graphics2D) mask.getGraphics(); + gm.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + gm.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + gm.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + gm.setComposite(AlphaComposite.Src); + gm.setColor(new Color(0, 0, 0, 0f)); + gm.fillRect(0, 0, image.getWidth(), image.getHeight()); + gm.setTransform(trans); + gm.drawImage(img.getBufferedImage(), 0, 0, null); + Clip clip = new Clip(Helper.imageToShape(mask), layer.clipDepth); // Maybe we can get current outline instead converting from image (?) + clips.add(clip); + prevClips.add(g.getClip()); + g.setTransform(AffineTransform.getTranslateInstance(0, 0)); + g.setClip(clip.shape); + } else { + if (renderContext.cursorPosition != null) { + if (drawable instanceof DefineSpriteTag) { + if (renderContext.stateUnderCursor.size() > stateCount) { + renderContext.stateUnderCursor.add(layer); + } + } else if (absMat.transform(new ExportRectangle(boundRect)).contains(renderContext.cursorPosition)) { + Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat); + if (shape.contains(renderContext.cursorPosition)) { + renderContext.stateUnderCursor.add(layer); + } + } + } + + if (renderContext.borderImage != null) { + Graphics2D g2 = (Graphics2D) renderContext.borderImage.getGraphics(); + g2.setPaint(Color.red); + g2.setStroke(new BasicStroke(2)); + Shape shape = drawable.getOutline(dframe, time, layer.ratio, renderContext, absMat.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor))); + g2.draw(shape); + } + + g.setTransform(trans); + g.drawImage(img.getBufferedImage(), 0, 0, null); + } + } else if (character instanceof BoundedTag) { + showPlaceholder = true; + } + + if (showPlaceholder) { + AffineTransform trans = mat.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).toTransform(); + g.setTransform(trans); + BoundedTag b = (BoundedTag) character; + g.setPaint(new Color(255, 255, 255, 128)); + g.setComposite(BlendComposite.Invert); + g.setStroke(new BasicStroke((int) SWF.unitDivisor)); + RECT r = b.getRect(); + g.setFont(g.getFont().deriveFont((float) (12 * SWF.unitDivisor))); + g.drawString(character.toString(), r.Xmin + (int) (3 * SWF.unitDivisor), r.Ymin + (int) (15 * SWF.unitDivisor)); + g.draw(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight())); + g.drawLine(r.Xmin, r.Ymin, r.Xmax, r.Ymax); + g.drawLine(r.Xmax, r.Ymin, r.Xmin, r.Ymax); + g.setComposite(AlphaComposite.Dst); + /*Matrix mat2 = mat.clone(); + mat2.translateX /= unzoom; + mat2.translateY /= unzoom; + AffineTransform trans = mat2.toTransform(); + g.setTransform(trans); + BoundedTag b = (BoundedTag) character; + g.setPaint(new Color(255, 255, 255, 128)); + g.setComposite(BlendComposite.Invert); + RECT r = b.getRect(); + int div = (int) unzoom; + g.drawString(character.toString(), r.Xmin / div + 3, r.Ymin / div + 15); + g.draw(new Rectangle(r.Xmin / div, r.Ymin / div, r.getWidth() / div, r.getHeight() / div)); + g.drawLine(r.Xmin / div, r.Ymin / div, r.Xmax / div, r.Ymax / div); + g.drawLine(r.Xmax / div, r.Ymin / div, r.Xmin / div, r.Ymax / div); + g.setComposite(AlphaComposite.Dst);*/ + } + } + + g.setTransform(AffineTransform.getScaleInstance(1, 1)); + } + + public void toSVG(int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException { + if (getFrameCount() <= frame) { + return; + } + + Frame frameObj = getFrame(frame); + List clips = new ArrayList<>(); + List prevClips = new ArrayList<>(); + + int maxDepth = getMaxDepth(); + for (int i = 1; i <= maxDepth; i++) { + for (int c = 0; c < clips.size(); c++) { + if (clips.get(c).depth == i) { + exporter.setClip(prevClips.get(c)); + prevClips.remove(c); + clips.remove(c); + } + } + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!swf.getCharacters().containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + + CharacterTag character = swf.getCharacter(layer.characterId); + + ColorTransform clrTrans = colorTransform; + if (layer.colorTransForm != null && layer.blendMode <= 1) { // Normal blend mode + clrTrans = clrTrans == null ? layer.colorTransForm : colorTransform.merge(layer.colorTransForm); + } + + if (character instanceof DrawableTag) { + DrawableTag drawable = (DrawableTag) character; + + String assetName; + Tag drawableTag = (Tag) drawable; + RECT boundRect = drawable.getRect(); + if (exporter.exportedTags.containsKey(drawableTag)) { + assetName = exporter.exportedTags.get(drawableTag); + } else { + assetName = getTagIdPrefix(drawableTag, exporter); + exporter.exportedTags.put(drawableTag, assetName); + exporter.createDefGroup(new ExportRectangle(boundRect), assetName); + drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, zoom); + exporter.endGroup(); + } + ExportRectangle rect = new ExportRectangle(boundRect); + + // TODO: if (layer.filters != null) + // TODO: if (layer.blendMode > 1) + if (layer.clipDepth > -1) { + String clipName = exporter.getUniqueId("clipPath"); + exporter.createClipPath(new Matrix(), clipName); + SvgClip clip = new SvgClip(clipName, layer.clipDepth); + clips.add(clip); + prevClips.add(exporter.getClip()); + Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); + exporter.addUse(mat, boundRect, assetName, layer.instanceName); + exporter.setClip(clip.shape); + exporter.endGroup(); + } else { + Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); + exporter.addUse(mat, boundRect, assetName, layer.instanceName); + } + } + } + } + + private static String getTagIdPrefix(Tag tag, SVGExporter exporter) { + if (tag instanceof ShapeTag) { + return exporter.getUniqueId("shape"); + } + if (tag instanceof MorphShapeTag) { + return exporter.getUniqueId("morphshape"); + } + if (tag instanceof DefineSpriteTag) { + return exporter.getUniqueId("sprite"); + } + if (tag instanceof TextTag) { + return exporter.getUniqueId("text"); + } + if (tag instanceof ButtonTag) { + return exporter.getUniqueId("button"); + } + return exporter.getUniqueId("tag"); } public void toHtmlCanvas(StringBuilder result, double unitDivisor, List frames) { @@ -665,8 +1059,7 @@ public class Timeline { CharacterTag character = swf.getCharacter(layer.characterId); if (character instanceof DrawableTag) { DrawableTag drawable = (DrawableTag) character; - Matrix m = new Matrix(layer.matrix); - m = m.preConcatenate(transformation); + Matrix m = transformation.concatenate(new Matrix(layer.matrix)); int drawableFrameCount = drawable.getNumFrames(); if (drawableFrameCount == 0) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index c65322161..901467054 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -418,8 +418,10 @@ public class XFLConverter { private static String convertShape(HashMap characters, MATRIX mat, int shapeNum, List shapeRecords, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStyles, boolean morphshape, boolean useLayers) { StringBuilder ret = new StringBuilder(); List layers = getShapeLayers(characters, mat, shapeNum, shapeRecords, fillStyles, lineStyles, morphshape); - if (layers.size() == 1 && !useLayers) { - ret.append(layers.get(0)); + if (!useLayers) { + for (int l = layers.size() - 1; l >= 0; l--) { + ret.append(layers.get(l)); + } } else { int layer = 1; for (int l = layers.size() - 1; l >= 0; l--) { diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 938dcfd0e..394e09cac 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -1930,7 +1930,7 @@ public class CommandLineArgumentParser { //displayRect.Ymax *= zoom; Matrix m = new Matrix(); //m.scale(zoom); - BufferedImage img = SWF.frameToImageGet(ds.getTimeline(), 0, 0, null, 0, displayRect, m, m, null, Color.white, false, zoom).getBufferedImage(); + BufferedImage img = SWF.frameToImageGet(ds.getTimeline(), 0, 0, null, 0, displayRect, m, m, null, Color.white, zoom).getBufferedImage(); PageFormat pf = new PageFormat(); pf.setOrientation(PageFormat.PORTRAIT); Paper p = new Paper(); diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java index 10d39caf4..3a602a19b 100644 --- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.helpers.Cache; @@ -307,7 +308,15 @@ public class FolderPreviewPanel extends JPanel { zoom = ratio; } } - imgSrc = SWF.frameToImageGet(swf.getTimeline(), fn.frame, fn.frame, null, 0, rect, new Matrix(), new Matrix(), null, null, true, zoom); + + Timeline timeline = swf.getTimeline(); + String key = "frame_" + fn.frame + "_" + timeline.id + "_" + zoom; + imgSrc = swf.getFromCache(key); + if (imgSrc == null) { + imgSrc = SWF.frameToImageGet(timeline, fn.frame, fn.frame, null, 0, rect, new Matrix(), new Matrix(), null, null, zoom); + swf.putToCache(key, imgSrc); + } + width = imgSrc.getWidth(); height = imgSrc.getHeight(); } else if (treeItem instanceof ImageTag) { diff --git a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java index e2dbbeb80..105e18910 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/MainFrameMenu.java @@ -414,6 +414,10 @@ public abstract class MainFrameMenu implements MenuBuilder { mainFrame.getPanel().removeNonScripts(swf); } + protected void removeExceptSelected() { + mainFrame.getPanel().removeExceptSelected(swf); + } + protected void refreshDecompiled() { mainFrame.getPanel().refreshDecompiled(); } @@ -981,6 +985,7 @@ public abstract class MainFrameMenu implements MenuBuilder { addMenuItem("/debug", "Debug", null, null, 0, null, false, null, false); addMenuItem("/debug/removeNonScripts", "Remove non scripts", "update16", e -> removeNonScripts(), PRIORITY_MEDIUM, null, true, null, false); + addMenuItem("/debug/removeExceptSelected", "Remove except selected", "update16", e -> removeExceptSelected(), PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/debug/refreshDecompiled", "Refresh decompiled script", "update16", e -> refreshDecompiled(), PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/debug/checkResources", "Check resources", "update16", e -> checkResources(), PRIORITY_MEDIUM, null, true, null, false); addMenuItem("/debug/callGc", "Call System.gc()", "update16", e -> System.gc(), PRIORITY_MEDIUM, null, true, null, false); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index dfaee53a5..9affdc614 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -2414,6 +2414,35 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se refreshTree(swf); } + public void removeExceptSelected(SWF swf) { + if (swf == null) { + return; + } + + List sel = tagTree.getAllSelected(); + Set needed = new HashSet<>(); + for (TreeItem item : sel) { + if (item instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) item; + characterTag.getNeededCharactersDeep(needed); + needed.add(characterTag.getCharacterId()); + } + } + + List tagsToRemove = new ArrayList<>(); + for (Tag tag : swf.getTags()) { + if (tag instanceof CharacterTag) { + CharacterTag characterTag = (CharacterTag) tag; + if (!needed.contains(characterTag.getCharacterId())) { + tagsToRemove.add(tag); + } + } + } + + swf.removeTags(tagsToRemove, true); + refreshTree(swf); + } + private void clear() { dumpViewPanel.clear(); previewPanel.clear(); diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java index 42324f2ee..741a0524d 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTree.java @@ -181,7 +181,7 @@ public class TagTree extends JTree { boolean hasFocus) { TreeItem val = (TreeItem) value; - if (!(val instanceof SWFList) && val.getSwf() == null) { + if (val != null && !(val instanceof SWFList) && val.getSwf() == null) { // SWF was closed value = null; } @@ -190,6 +190,11 @@ public class TagTree extends JTree { tree, value, sel, expanded, leaf, row, hasFocus); + + if (val == null) { + return this; + } + TreeNodeType type = getTreeNodeType(val); if (type == TreeNodeType.FOLDER && expanded) {