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 d8a88cce9..738f7cf2d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -390,6 +390,32 @@ public final class SWF implements SWFContainerItem, Timelined { return null; } + public ImageTag getImage(int imageId) { + CharacterTag characterTag = getCharacters().get(imageId); + if (characterTag instanceof ImageTag) { + return (ImageTag) characterTag; + } + + if (characterTag != null) { + logger.log(Level.SEVERE, "CharacterTag should be an ImageTag. characterId: {0}", imageId); + } + + return null; + } + + public TextTag getText(int textId) { + CharacterTag characterTag = getCharacters().get(textId); + if (characterTag instanceof TextTag) { + return (TextTag) characterTag; + } + + if (characterTag != null) { + logger.log(Level.SEVERE, "CharacterTag should be a TextTag. characterId: {0}", textId); + } + + return null; + } + public List getAbcList() { if (abcList == null) { synchronized (this) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 7c4391cd7..21f9eae51 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -2889,14 +2889,14 @@ public class SWFInputStream implements AutoCloseable { /** * Reads one TEXTRECORD value from the stream * - * @param inDefineText2 + * @param defineTextNum * @param glyphBits * @param advanceBits * @param name * @return TEXTRECORD value * @throws IOException */ - public TEXTRECORD readTEXTRECORD(boolean inDefineText2, int glyphBits, int advanceBits, String name) throws IOException { + public TEXTRECORD readTEXTRECORD(int defineTextNum, int glyphBits, int advanceBits, String name) throws IOException { TEXTRECORD ret = new TEXTRECORD(); newDumpLevel(name, "TEXTRECORD"); int first = (int) readUB(1, "first"); // always 1 @@ -2913,7 +2913,7 @@ public class SWFInputStream implements AutoCloseable { ret.fontId = readUI16("fontId"); } if (ret.styleFlagsHasColor) { - if (inDefineText2) { + if (defineTextNum == 2) { ret.textColorA = readRGBA("textColorA"); } else { ret.textColor = readRGB("textColor"); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index f54336ead..e905bb6b7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -1484,12 +1484,12 @@ public class SWFOutputStream extends OutputStream { * Writes TEXTRECORD value to the stream * * @param value TEXTRECORD value - * @param inDefineText2 + * @param defineTextNum * @param glyphBits * @param advanceBits * @throws IOException */ - public void writeTEXTRECORD(TEXTRECORD value, boolean inDefineText2, int glyphBits, int advanceBits) throws IOException { + public void writeTEXTRECORD(TEXTRECORD value, int defineTextNum, int glyphBits, int advanceBits) throws IOException { writeUB(1, 1); writeUB(3, 0); writeUB(1, value.styleFlagsHasFont ? 1 : 0); @@ -1500,7 +1500,7 @@ public class SWFOutputStream extends OutputStream { writeUI16(value.fontId); } if (value.styleFlagsHasColor) { - if (inDefineText2) { + if (defineTextNum == 2) { writeRGBA(value.textColorA); } else { writeRGB(value.textColor); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java index 8b1a48105..af0484046 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.Point; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -221,22 +220,12 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); - ImageTag image = null; - for (Tag t : swf.tags) { - if (t instanceof ImageTag) { - ImageTag i = (ImageTag) t; - if (i.getCharacterId() == bitmapId) { - image = i; - SerializableImage img = i.getImage(); - fillWidth = img.getWidth(); - fillHeight = img.getHeight(); - break; - } - } - } + ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImage(); if (img != null) { + fillWidth = img.getWidth(); + fillHeight = img.getHeight(); colorTransform.apply(img); if (matrix != null) { fillMatrix = matrix; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java index 0430b5388..7b7707f45 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -107,16 +106,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); - ImageTag image = null; - for (Tag t : swf.tags) { - if (t instanceof ImageTag) { - ImageTag i = (ImageTag) t; - if (i.getCharacterId() == bitmapId) { - image = i; - break; - } - } - } + ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImage(); if (img != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/BitmapExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/BitmapExporter.java index 32aa56a83..74fd20416 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/BitmapExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/BitmapExporter.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.exporters.shape; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -308,10 +307,9 @@ public class BitmapExporter extends ShapeExporterBase { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); - CharacterTag character = swf.getCharacter(bitmapId); - ImageTag image = character instanceof ImageTag ? (ImageTag) character : null; - if (image != null) { - SerializableImage img = image.getImage(); + ImageTag imageTag = swf.getImage(bitmapId); + if (imageTag != null) { + SerializableImage img = imageTag.getImage(); if (img != null) { img = colorTransform.apply(img); fillPaint = new TexturePaint(img.getBufferedImage(), new java.awt.Rectangle(img.getWidth(), img.getHeight())); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java index 86254c8d7..43f09bd4a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.exporters.shape; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.Point; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -252,22 +251,12 @@ public class CanvasShapeExporter extends ShapeExporterBase { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); - ImageTag image = null; - for (Tag t : swf.tags) { - if (t instanceof ImageTag) { - ImageTag i = (ImageTag) t; - if (i.getCharacterId() == bitmapId) { - image = i; - SerializableImage im = i.getImage(); - fillWidth = im.getWidth(); - fillHeight = im.getHeight(); - break; - } - } - } + ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImage(); if (img != null) { + fillWidth = img.getWidth(); + fillHeight = img.getHeight(); colorTransform.apply(img); if (matrix != null) { fillMatrix = matrix; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java index 3efa1dc24..0ece8a283 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java @@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.helpers.ImageHelper; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.FILLSTYLE; @@ -104,16 +103,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); - ImageTag image = null; - for (Tag t : swf.tags) { - if (t instanceof ImageTag) { - ImageTag i = (ImageTag) t; - if (i.getCharacterId() == bitmapId) { - image = i; - break; - } - } - } + ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImage(); if (img != null) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/TextImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/TextImporter.java index 9f3f197e3..6438031ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/TextImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/TextImporter.java @@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.importers; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; -import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler; import com.jpexs.decompiler.flash.tags.base.TextTag; @@ -72,17 +71,12 @@ public class TextImporter { Map records = splitTextRecords(texts); if (records != null) { for (int characterId : records.keySet()) { - for (Tag tag : swf.tags) { - if (tag instanceof TextTag) { - TextTag textTag = (TextTag) tag; - if (textTag.getCharacterId() == characterId) { - String[] currentRecords = records.get(characterId); - String text = textTag.getFormattedText().text; - if (!saveText(textTag, text, currentRecords)) { - return; - } - break; - } + TextTag textTag = swf.getText(characterId); + if (textTag != null) { + String[] currentRecords = records.get(characterId); + String text = textTag.getFormattedText().text; + if (!saveText(textTag, text, currentRecords)) { + return; } } } @@ -94,16 +88,11 @@ public class TextImporter { Map records = splitTextRecords(texts); if (records != null) { for (int characterId : records.keySet()) { - for (Tag tag : swf.tags) { - if (tag instanceof TextTag) { - TextTag textTag = (TextTag) tag; - if (textTag.getCharacterId() == characterId) { - String[] currentRecords = records.get(characterId); - if (!saveText(textTag, currentRecords[0], null)) { - return; - } - break; - } + TextTag textTag = swf.getText(characterId); + if (textTag != null) { + String[] currentRecords = records.get(characterId); + if (!saveText(textTag, currentRecords[0], null)) { + return; } } } @@ -134,28 +123,18 @@ public class TextImporter { boolean formatted = !texts.contains(recordSeparator) && texts.startsWith("[" + Helper.newLine); if (!formatted) { String[] records = texts.split(recordSeparator); - for (Tag tag : swf.tags) { - if (tag instanceof TextTag) { - TextTag textTag = (TextTag) tag; - if (textTag.getCharacterId() == characterId) { - String text = textTag.getFormattedText().text; - if (!saveText(textTag, text, records)) { - return; - } - break; - } + TextTag textTag = swf.getText(characterId); + if (textTag != null) { + String text = textTag.getFormattedText().text; + if (!saveText(textTag, text, records)) { + return; } } } else { - for (Tag tag : swf.tags) { - if (tag instanceof TextTag) { - TextTag textTag = (TextTag) tag; - if (textTag.getCharacterId() == characterId) { - if (!saveText(textTag, texts, null)) { - return; - } - break; - } + TextTag textTag = swf.getText(characterId); + if (textTag != null) { + if (!saveText(textTag, texts, null)) { + return; } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 2d325be8b..da3073441 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -228,7 +228,7 @@ public class DefineEditTextTag extends TextTag { private List getTextWithStyle() { String str = ""; TextStyle style = new TextStyle(); - style.font = getFontTag(); + style.font = swf.getFont(fontId); style.fontHeight = fontHeight; style.fontLeading = leading; if (hasTextColor) { @@ -900,11 +900,26 @@ public class DefineEditTextTag extends TextTag { return false; } + @Override + public int getUsedParameters() { + return 0; + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { render(false, image, transformation, colorTransform); } + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + // todo: implement + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + return render(true, null, new Matrix(), new ColorTransform()); + } + private String render(boolean canvas, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { if (border) { // border is always black, fill color is always white? @@ -1098,28 +1113,11 @@ public class DefineEditTextTag extends TextTag { return ""; } - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - @Override public ExportRectangle calculateTextBounds() { return null; } - private FontTag getFontTag() { - FontTag font = null; - for (Tag tag : swf.tags) { - if (tag instanceof FontTag) { - if (((FontTag) tag).getFontId() == fontId) { - font = (FontTag) tag; - } - } - } - return font; - } - @Override public int getNumFrames() { return 1; @@ -1130,11 +1128,6 @@ public class DefineEditTextTag extends TextTag { return true; } - @Override - public String toHtmlCanvas(double unitDivisor) { - return render(true, null, new Matrix(), new ColorTransform()); - } - @Override public void setCharacterId(int characterId) { this.characterID = characterId; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index f25b8b471..763cdffe8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -377,6 +377,11 @@ public class DefineMorphShape2Tag extends MorphShapeTag { return shape; } + @Override + public int getUsedParameters() { + return PARAMETER_RATIO; + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index ad00592ba..3539fdad2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -353,6 +353,11 @@ public class DefineMorphShapeTag extends MorphShapeTag { return shape; } + @Override + public int getUsedParameters() { + return PARAMETER_RATIO; + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); 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 a2aa8a2b9..11b3fd2ce 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 @@ -321,6 +321,11 @@ public class DefineSpriteTag extends CharacterTag implements DrawableTag, Timeli return modified; } + @Override + public int getUsedParameters() { + return PARAMETER_FRAME | PARAMETER_TIME | PARAMETER_RATIO; // inner tags can contain morphshapes, too + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { SWF.frameToImage(getTimeline(), frame, time, renderContext, image, transformation, colorTransform); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index 021ce7565..5225bec26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -16,519 +16,24 @@ */ package com.jpexs.decompiler.flash.tags; -import com.jpexs.decompiler.flash.AppResources; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -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.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextLexer; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.tags.base.StaticTextTag; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.RGBA; -import com.jpexs.decompiler.flash.types.TEXTRECORD; -import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.StringReader; import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * * * @author JPEXS */ -public class DefineText2Tag extends TextTag { - - @SWFType(BasicType.UI16) - public int characterID; - - private int glyphBits; - - private int advanceBits; - - public RECT textBounds; - - public MATRIX textMatrix; - - public List textRecords; +public class DefineText2Tag extends StaticTextTag { public static final int ID = 33; - @Override - public RECT getBounds() { - return textBounds; - } - - @Override - public MATRIX getTextMatrix() { - return textMatrix; - } - - @Override - public void setBounds(RECT r) { - textBounds = r; - } - - @Override - public List getTexts() { - FontTag fnt = null; - List ret = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - for (Tag t : swf.tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == rec.fontId) { - fnt = ((FontTag) t); - break; - } - } - } - } - if (rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { - /*if (!ret.isEmpty()) { - ret += "\r\n"; - }*/ - } - - if (fnt == null) { - ret.add(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); - } else { - ret.add(rec.getText(fnt)); - } - } - return ret; - } - - @Override - public List getFontIds() { - List ret = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - ret.add(rec.fontId); - } - } - return ret; - } - - @Override - public HighlightedText getFormattedText() { - FontTag fnt = null; - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.append("[").newLine(); - writer.append("xmin " + textBounds.Xmin).newLine(); - writer.append("ymin " + textBounds.Ymin).newLine(); - writer.append("xmax " + textBounds.Xmax).newLine(); - writer.append("ymax " + textBounds.Ymax).newLine(); - if (textMatrix.translateX != 0) { - writer.append("translatex " + textMatrix.translateX).newLine(); - } - if (textMatrix.translateY != 0) { - writer.append("translatey " + textMatrix.translateY).newLine(); - } - if (textMatrix.hasScale) { - writer.append("scalex " + textMatrix.scaleX).newLine(); - writer.append("scaley " + textMatrix.scaleY).newLine(); - } - if (textMatrix.hasRotate) { - writer.append("rotateskew0 " + textMatrix.rotateSkew0).newLine(); - writer.append("rotateskew1 " + textMatrix.rotateSkew1).newLine(); - } - writer.append("]"); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont || rec.styleFlagsHasColor || rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { - writer.append("[").newLine(); - if (rec.styleFlagsHasFont) { - for (Tag t : swf.tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == rec.fontId) { - fnt = ((FontTag) t); - break; - } - } - } - writer.append("font " + rec.fontId).newLine(); - writer.append("height " + rec.textHeight).newLine(); - } - if (rec.styleFlagsHasColor) { - writer.append("color " + rec.textColorA.toHexARGB()).newLine(); - } - if (rec.styleFlagsHasXOffset) { - writer.append("x " + rec.xOffset).newLine(); - } - if (rec.styleFlagsHasYOffset) { - writer.append("y " + rec.yOffset).newLine(); - } - writer.append("]"); - } - - if (fnt == null) { - writer.append(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); - } else { - writer.hilightSpecial(Helper.escapeActionScriptString(rec.getText(fnt)).replace("[", "\\[").replace("]", "\\]"), HighlightSpecialType.TEXT); - } - } - return new HighlightedText(writer); - } - - @Override - public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { - try { - TextLexer lexer = new TextLexer(new StringReader(formattedText)); - ParsedSymbol s = null; - List textRecords = new ArrayList<>(); - RGBA colorA = null; - int fontId = -1; - int textHeight = -1; - FontTag font = null; - String fontName = null; - Integer x = null; - Integer y = null; - int currentX = 0; - int currentY = 0; - int maxX = Integer.MIN_VALUE; - int minX = Integer.MAX_VALUE; - MATRIX textMatrix = new MATRIX(); - textMatrix.hasRotate = false; - textMatrix.hasScale = false; - RECT textBounds = new RECT(); - int textIdx = 0; - while ((s = lexer.yylex()) != null) { - switch (s.type) { - case PARAMETER: - String paramName = (String) s.values[0]; - String paramValue = (String) s.values[1]; - switch (paramName) { - case "color": - Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); - if (m.matches()) { - colorA = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); - } else { - throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); - } - break; - case "font": - try { - fontId = Integer.parseInt(paramValue); - - FontTag ft = swf.getFont(fontId); - if (ft == null) { - throw new TextParseException("Font not found.", lexer.yyline()); - } - - font = (FontTag) ft; - fontName = font.getSystemFontName(); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid font id - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "height": - try { - textHeight = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid font height - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "x": - try { - x = Integer.parseInt(paramValue); - currentX = x; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid x position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "y": - try { - y = Integer.parseInt(paramValue); - currentY = y; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid y position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmin": - try { - textBounds.Xmin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmin position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmax": - try { - textBounds.Xmax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmax position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymin": - try { - textBounds.Ymin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymin position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymax": - try { - textBounds.Ymax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymax position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "scalex": - try { - textMatrix.scaleX = Integer.parseInt(paramValue); - textMatrix.hasScale = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "scaley": - try { - textMatrix.scaleY = Integer.parseInt(paramValue); - textMatrix.hasScale = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rotateskew0": - try { - textMatrix.rotateSkew0 = Integer.parseInt(paramValue); - textMatrix.hasRotate = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid rotateskew0 value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rotateskew1": - try { - textMatrix.rotateSkew1 = Integer.parseInt(paramValue); - textMatrix.hasRotate = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid rotateskew1 value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "translatex": - try { - textMatrix.translateX = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid translatex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "translatey": - try { - textMatrix.translateY = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid translatey value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - default: - throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); - } - break; - case TEXT: - String txt = (texts == null || textIdx >= texts.length) ? (String) s.values[0] : texts[textIdx++]; - if (txt == null || (font == null && txt.isEmpty())) { - continue; - } - - if (font == null) { - throw new TextParseException("Font not defined", lexer.yyline()); - } - - while (txt.charAt(0) == '\r' || txt.charAt(0) == '\n') { - txt = txt.substring(1); - } - - while (txt.charAt(txt.length() - 1) == '\r' || txt.charAt(txt.length() - 1) == '\n') { - txt = txt.substring(0, txt.length() - 1); - } - - StringBuilder txtSb = new StringBuilder(); - for (int i = 0; i < txt.length(); i++) { - char c = txt.charAt(i); - - if (!font.containsChar(c)) { - if (!missingCharHandler.handle(this, font, c)) { - if (!missingCharHandler.getIgnoreMissingCharacters()) { - return false; - } - } else { - return setFormattedText(missingCharHandler, formattedText, texts); - } - } else { - txtSb.append(c); - } - } - - txt = txtSb.toString(); - - TEXTRECORD tr = new TEXTRECORD(); - textRecords.add(tr); - if (fontId > -1) { - tr.fontId = fontId; - tr.textHeight = textHeight; - fontId = -1; - tr.styleFlagsHasFont = true; - } - if (colorA != null) { - tr.textColorA = colorA; - tr.styleFlagsHasColor = true; - colorA = null; - } - if (x != null) { - tr.xOffset = x; - tr.styleFlagsHasXOffset = true; - x = null; - } - if (y != null) { - tr.yOffset = y; - tr.styleFlagsHasYOffset = true; - y = null; - } - tr.glyphEntries = new ArrayList<>(txt.length()); - for (int i = 0; i < txt.length(); i++) { - char c = txt.charAt(i); - Character nextChar = null; - if (i + 1 < txt.length()) { - nextChar = txt.charAt(i + 1); - } - - GLYPHENTRY ge = new GLYPHENTRY(); - ge.glyphIndex = font.charToGlyph(c); - - int advance; - if (font.hasLayout()) { - int kerningAdjustment = 0; - if (nextChar != null) { - kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); - } - advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); - } else { - advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor), c, nextChar)); - } - - ge.glyphAdvance = advance; - tr.glyphEntries.add(ge); - - currentX += advance; - - } - if (currentX > maxX) { - maxX = currentX; - } - if (currentX < minX) { - minX = currentX; - } - break; - } - } - - setModified(true); - this.textRecords = textRecords; - this.textBounds = textBounds; - } catch (IOException ex) { - return false; - } catch (TextParseException ex) { - throw ex; - } - - updateTextBounds(); - return true; - } - - @Override - public void updateTextBounds() { - updateTextBounds(textBounds); - } - - @Override - public boolean alignText(TextAlign textAlign) { - alignText(swf, textRecords, textAlign); - setModified(true); - return true; - } - - @Override - public boolean translateText(int diff) { - textMatrix.translateX += diff; - updateTextBounds(); - setModified(true); - return true; - } - - @Override - public RECT getRect(Set added) { - return textBounds; - } - - @Override - public int getCharacterId() { - return characterID; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeRECT(textBounds); - sos.writeMatrix(textMatrix); - - int glyphBits = 0; - int advanceBits = 0; - for (TEXTRECORD tr : textRecords) { - for (GLYPHENTRY ge : tr.glyphEntries) { - glyphBits = SWFOutputStream.enlargeBitCountU(glyphBits, ge.glyphIndex); - advanceBits = SWFOutputStream.enlargeBitCountS(advanceBits, ge.glyphAdvance); - } - } - - if (Configuration.debugCopy.get()) { - glyphBits = Math.max(glyphBits, this.glyphBits); - advanceBits = Math.max(advanceBits, this.advanceBits); - } - - sos.writeUI8(glyphBits); - sos.writeUI8(advanceBits); - for (TEXTRECORD tr : textRecords) { - sos.writeTEXTRECORD(tr, true, glyphBits, advanceBits); - } - sos.writeUI8(0); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -557,100 +62,7 @@ public class DefineText2Tag extends TextTag { } @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - textBounds = sis.readRECT("textBounds"); - textMatrix = sis.readMatrix("textMatrix"); - glyphBits = sis.readUI8("glyphBits"); - advanceBits = sis.readUI8("advanceBits"); - textRecords = new ArrayList<>(); - TEXTRECORD tr; - while ((tr = sis.readTEXTRECORD(true, glyphBits, advanceBits, "record")) != null) { - textRecords.add(tr); - } - } - - @Override - public void getNeededCharacters(Set needed) { - for (TEXTRECORD tr : textRecords) { - if (tr.styleFlagsHasFont) { - needed.add(tr.fontId); - } - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - for (TEXTRECORD tr : textRecords) { - if (tr.fontId == oldCharacterId) { - tr.fontId = newCharacterId; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - for (TEXTRECORD tr : textRecords) { - if (tr.fontId == characterId) { - tr.styleFlagsHasFont = false; - tr.fontId = 0; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - staticTextToImage(swf, textRecords, 2, image, getTextMatrix(), transformation, colorTransform); - /*try { - DefineText2Tag originalTag = (DefineText2Tag) getOriginalTag(); - if (isModified()) { - originalTag.toImage(frame, time, ratio, stateUnderCursor, mouseButton, image, transformation, new ConstantColorColorTransform(0xFFC0C0C0)); - } - staticTextToImage(swf, textRecords, 2, image, getTextMatrix(), transformation, new ConstantColorColorTransform(0xFF000000)); - } catch (InterruptedException | IOException ex) { - Logger.getLogger(DefineText2Tag.class.getName()).log(Level.SEVERE, null, ex); - }*/ - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - staticTextToSVG(swf, textRecords, 2, exporter, getRect(), getTextMatrix(), colorTransform, zoom); - } - - @Override - public ExportRectangle calculateTextBounds() { - return calculateTextBounds(swf, textRecords, getTextMatrix()); - } - - @Override - public int getNumFrames() { - return 1; - } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - return staticTextToHtmlCanvas(unitDivisor, swf, textRecords, 2, textBounds, textMatrix, new ColorTransform()); - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; + public int getTextNum() { + return 2; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index a077b7afb..1181d8d01 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -16,475 +16,24 @@ */ package com.jpexs.decompiler.flash.tags; -import com.jpexs.decompiler.flash.AppResources; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.configuration.Configuration; -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.helpers.HighlightedText; -import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; -import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.FontTag; -import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.TextTag; -import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; -import com.jpexs.decompiler.flash.tags.text.TextAlign; -import com.jpexs.decompiler.flash.tags.text.TextLexer; -import com.jpexs.decompiler.flash.tags.text.TextParseException; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.tags.base.StaticTextTag; 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.TEXTRECORD; -import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.SerializableImage; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; -import java.io.StringReader; import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * * * @author JPEXS */ -public class DefineTextTag extends TextTag { - - @SWFType(BasicType.UI16) - public int characterID; - - private int glyphBits; - - private int advanceBits; - - public RECT textBounds; - - public MATRIX textMatrix; - - public List textRecords; +public class DefineTextTag extends StaticTextTag { public static final int ID = 11; - @Override - public MATRIX getTextMatrix() { - return textMatrix; - } - - @Override - public RECT getBounds() { - return textBounds; - } - - @Override - public void setBounds(RECT r) { - textBounds = r; - } - - @Override - public List getTexts() { - FontTag fnt = null; - List ret = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - for (Tag t : swf.tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == rec.fontId) { - fnt = ((FontTag) t); - break; - } - } - } - } - if (rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { - /*if (!ret.isEmpty()) { - ret += "\r\n"; - }*/ - } - - if (fnt == null) { - ret.add(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); - } else { - ret.add(rec.getText(fnt)); - } - } - return ret; - } - - @Override - public List getFontIds() { - List ret = new ArrayList<>(); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont) { - ret.add(rec.fontId); - } - } - return ret; - } - - @Override - public HighlightedText getFormattedText() { - FontTag fnt = null; - HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); - writer.append("[").newLine(); - writer.append("xmin " + textBounds.Xmin).newLine(); - writer.append("ymin " + textBounds.Ymin).newLine(); - writer.append("xmax " + textBounds.Xmax).newLine(); - writer.append("ymax " + textBounds.Ymax).newLine(); - if (textMatrix.translateX != 0) { - writer.append("translatex " + textMatrix.translateX).newLine(); - } - if (textMatrix.translateY != 0) { - writer.append("translatey " + textMatrix.translateY).newLine(); - } - if (textMatrix.hasScale) { - writer.append("scalex " + textMatrix.scaleX).newLine(); - writer.append("scaley " + textMatrix.scaleY).newLine(); - } - if (textMatrix.hasRotate) { - writer.append("rotateskew0 " + textMatrix.rotateSkew0).newLine(); - writer.append("rotateskew1 " + textMatrix.rotateSkew1).newLine(); - } - writer.append("]"); - for (TEXTRECORD rec : textRecords) { - if (rec.styleFlagsHasFont || rec.styleFlagsHasColor || rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { - writer.append("[").newLine(); - if (rec.styleFlagsHasFont) { - for (Tag t : swf.tags) { - if (t instanceof FontTag) { - if (((FontTag) t).getFontId() == rec.fontId) { - fnt = ((FontTag) t); - break; - } - } - } - writer.append("font " + rec.fontId).newLine(); - writer.append("height " + rec.textHeight).newLine(); - } - if (rec.styleFlagsHasColor) { - writer.append("color " + rec.textColor.toHexRGB()).newLine(); - } - if (rec.styleFlagsHasXOffset) { - writer.append("x " + rec.xOffset).newLine(); - } - if (rec.styleFlagsHasYOffset) { - writer.append("y " + rec.yOffset).newLine(); - } - writer.append("]"); - } - - if (fnt == null) { - writer.append(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); - } else { - writer.hilightSpecial(Helper.escapeActionScriptString(rec.getText(fnt)).replace("[", "\\[").replace("]", "\\]"), HighlightSpecialType.TEXT); - } - } - return new HighlightedText(writer); - } - - @Override - public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { - try { - TextLexer lexer = new TextLexer(new StringReader(formattedText)); - ParsedSymbol s = null; - List textRecords = new ArrayList<>(); - RGB color = null; - int fontId = -1; - int textHeight = -1; - FontTag font = null; - String fontName = null; - Integer x = null; - Integer y = null; - int currentX = 0; - int currentY = 0; - int maxX = Integer.MIN_VALUE; - int minX = Integer.MAX_VALUE; - MATRIX textMatrix = new MATRIX(); - textMatrix.hasRotate = false; - textMatrix.hasScale = false; - RECT textBounds = new RECT(); - int textIdx = 0; - while ((s = lexer.yylex()) != null) { - switch (s.type) { - case PARAMETER: - String paramName = (String) s.values[0]; - String paramValue = (String) s.values[1]; - switch (paramName) { - case "color": - Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); - if (m.matches()) { - color = new RGB(Integer.parseInt(m.group(1), 16), Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16)); - } else { - throw new TextParseException("Invalid color. Valid format is #rrggbb. Found: " + paramValue, lexer.yyline()); - } - break; - case "font": - try { - fontId = Integer.parseInt(paramValue); - - FontTag ft = swf.getFont(fontId); - if (ft == null) { - throw new TextParseException("Font not found.", lexer.yyline()); - } - - font = (FontTag) ft; - fontName = font.getSystemFontName(); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid font id - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "height": - try { - textHeight = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid font height - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "x": - try { - x = Integer.parseInt(paramValue); - currentX = x; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid x position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "y": - try { - y = Integer.parseInt(paramValue); - currentY = y; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid y position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmin": - try { - textBounds.Xmin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmin position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "xmax": - try { - textBounds.Xmax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid xmax position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymin": - try { - textBounds.Ymin = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymin position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "ymax": - try { - textBounds.Ymax = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid ymax position - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "scalex": - try { - textMatrix.scaleX = Integer.parseInt(paramValue); - textMatrix.hasScale = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "scaley": - try { - textMatrix.scaleY = Integer.parseInt(paramValue); - textMatrix.hasScale = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rotateskew0": - try { - textMatrix.rotateSkew0 = Integer.parseInt(paramValue); - textMatrix.hasRotate = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid rotateskew0 value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "rotateskew1": - try { - textMatrix.rotateSkew1 = Integer.parseInt(paramValue); - textMatrix.hasRotate = true; - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid rotateskew1 value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "translatex": - try { - textMatrix.translateX = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid translatex value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - case "translatey": - try { - textMatrix.translateY = Integer.parseInt(paramValue); - } catch (NumberFormatException nfe) { - throw new TextParseException("Invalid translatey value - number expected. Found: " + paramValue, lexer.yyline()); - } - break; - default: - throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); - } - break; - case TEXT: - String txt = (texts == null || textIdx >= texts.length) ? (String) s.values[0] : texts[textIdx++]; - if (txt == null || (font == null && txt.isEmpty())) { - continue; - } - - if (font == null) { - throw new TextParseException("Font not defined", lexer.yyline()); - } - - while (txt.charAt(0) == '\r' || txt.charAt(0) == '\n') { - txt = txt.substring(1); - } - - while (txt.charAt(txt.length() - 1) == '\r' || txt.charAt(txt.length() - 1) == '\n') { - txt = txt.substring(0, txt.length() - 1); - } - - StringBuilder txtSb = new StringBuilder(); - for (int i = 0; i < txt.length(); i++) { - char c = txt.charAt(i); - - if (!font.containsChar(c)) { - if (!missingCharHandler.handle(this, font, c)) { - if (!missingCharHandler.getIgnoreMissingCharacters()) { - return false; - } - } else { - return setFormattedText(missingCharHandler, formattedText, texts); - } - } else { - txtSb.append(c); - } - } - - txt = txtSb.toString(); - - TEXTRECORD tr = new TEXTRECORD(); - textRecords.add(tr); - if (fontId > -1) { - tr.fontId = fontId; - tr.textHeight = textHeight; - fontId = -1; - tr.styleFlagsHasFont = true; - } - if (color != null) { - tr.textColor = color; - tr.styleFlagsHasColor = true; - color = null; - } - if (x != null) { - tr.xOffset = x; - tr.styleFlagsHasXOffset = true; - x = null; - } - if (y != null) { - tr.yOffset = y; - tr.styleFlagsHasYOffset = true; - y = null; - } - tr.glyphEntries = new ArrayList<>(txt.length()); - for (int i = 0; i < txt.length(); i++) { - char c = txt.charAt(i); - Character nextChar = null; - if (i + 1 < txt.length()) { - nextChar = txt.charAt(i + 1); - } - - GLYPHENTRY ge = new GLYPHENTRY(); - ge.glyphIndex = font.charToGlyph(c); - - int advance; - if (font.hasLayout()) { - int kerningAdjustment = 0; - if (nextChar != null) { - kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); - } - advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); - } else { - advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor), c, nextChar)); - } - - ge.glyphAdvance = advance; - tr.glyphEntries.add(ge); - - currentX += advance; - } - - if (currentX > maxX) { - maxX = currentX; - } - if (currentX < minX) { - minX = currentX; - } - break; - } - - } - - setModified(true); - this.textRecords = textRecords; - this.textMatrix = textMatrix; - this.textBounds = textBounds; - } catch (IOException ex) { - return false; - } catch (TextParseException ex) { - throw ex; - } - - updateTextBounds(); - return true; - } - - @Override - public void updateTextBounds() { - updateTextBounds(textBounds); - } - - @Override - public boolean alignText(TextAlign textAlign) { - alignText(swf, textRecords, textAlign); - setModified(true); - return true; - } - - @Override - public boolean translateText(int diff) { - textMatrix.translateX += diff; - updateTextBounds(); - setModified(true); - return true; - } - - @Override - public int getCharacterId() { - return characterID; - } - /** * Constructor * @@ -500,57 +49,6 @@ public class DefineTextTag extends TextTag { advanceBits = 0; } - public DefineTextTag(SWF swf, int characterID, RECT textBounds, MATRIX textMatrix, List textRecords) { - super(swf, ID, "DefineText", null); - this.characterID = characterID; - this.textBounds = textBounds; - this.textMatrix = textMatrix; - this.textRecords = textRecords; - this.glyphBits = 0; - this.advanceBits = 0; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterID); - sos.writeRECT(textBounds); - sos.writeMatrix(textMatrix); - - int glyphBits = 0; - int advanceBits = 0; - for (TEXTRECORD tr : textRecords) { - for (GLYPHENTRY ge : tr.glyphEntries) { - glyphBits = SWFOutputStream.enlargeBitCountU(glyphBits, ge.glyphIndex); - advanceBits = SWFOutputStream.enlargeBitCountS(advanceBits, ge.glyphAdvance); - } - } - - if (Configuration.debugCopy.get()) { - glyphBits = Math.max(glyphBits, this.glyphBits); - advanceBits = Math.max(advanceBits, this.advanceBits); - } - - sos.writeUI8(glyphBits); - sos.writeUI8(advanceBits); - for (TEXTRECORD tr : textRecords) { - sos.writeTEXTRECORD(tr, false, glyphBits, advanceBits); - } - sos.writeUI8(0); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - /** * Constructor * @@ -564,105 +62,7 @@ public class DefineTextTag extends TextTag { } @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterID = sis.readUI16("characterID"); - textBounds = sis.readRECT("textBounds"); - textMatrix = sis.readMatrix("textMatrix"); - glyphBits = sis.readUI8("glyphBits"); - advanceBits = sis.readUI8("advanceBits"); - textRecords = new ArrayList<>(); - TEXTRECORD tr; - while ((tr = sis.readTEXTRECORD(false, glyphBits, advanceBits, "record")) != null) { - textRecords.add(tr); - } - } - - @Override - public RECT getRect(Set added) { - return textBounds; - } - - @Override - public void getNeededCharacters(Set needed) { - for (TEXTRECORD tr : textRecords) { - if (tr.styleFlagsHasFont) { - needed.add(tr.fontId); - } - } - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - for (TEXTRECORD tr : textRecords) { - if (tr.fontId == oldCharacterId) { - tr.fontId = newCharacterId; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - for (TEXTRECORD tr : textRecords) { - if (tr.fontId == characterId) { - tr.styleFlagsHasFont = false; - tr.fontId = 0; - modified = true; - } - } - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - staticTextToImage(swf, textRecords, 1, image, getTextMatrix(), transformation, colorTransform); - /*try { - DefineTextTag originalTag = (DefineTextTag) getOriginalTag(); - if (isModified()) { - originalTag.toImage(frame, time, ratio, stateUnderCursor, mouseButton, image, transformation, new ConstantColorColorTransform(0xFFC0C0C0)); - } - staticTextToImage(swf, textRecords, 1, image, getTextMatrix(), transformation, new ConstantColorColorTransform(0xFF000000)); - } catch (InterruptedException | IOException ex) { - Logger.getLogger(DefineTextTag.class.getName()).log(Level.SEVERE, null, ex); - }*/ - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - staticTextToSVG(swf, textRecords, 1, exporter, getRect(), getTextMatrix(), colorTransform, zoom); - } - - @Override - public ExportRectangle calculateTextBounds() { - return calculateTextBounds(swf, textRecords, getTextMatrix()); - } - - @Override - public int getNumFrames() { + public int getTextNum() { return 1; } - - @Override - public boolean isSingleFrame() { - return true; - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - return staticTextToHtmlCanvas(unitDivisor, swf, textRecords, 1, textBounds, textMatrix, new ColorTransform()); - } - - @Override - public void setCharacterId(int characterId) { - this.characterID = characterId; - } } 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 f47aa79c3..5837c52b5 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 @@ -60,6 +60,11 @@ public abstract class ButtonTag extends CharacterTag implements DrawableTag, Tim return getRect(new HashSet<>()); } + @Override + public int getUsedParameters() { + return PARAMETER_FRAME | PARAMETER_TIME | PARAMETER_RATIO; // inner tags can contain morphshapes, too + } + @Override public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { return getTimeline().getOutline(frame, time, ratio, renderContext, transformation); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java index ae57f6b3e..5eb64139e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/DrawableTag.java @@ -29,6 +29,14 @@ import java.io.IOException; */ public interface DrawableTag extends BoundedTag { + public static final int PARAMETER_FRAME = 1; + + public static final int PARAMETER_TIME = 2; + + public static final int PARAMETER_RATIO = 4; + + public int getUsedParameters(); + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation); public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index b4c7936d0..41e2c4a1b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -23,8 +23,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.helpers.FontHelper; import com.jpexs.decompiler.flash.tags.DefineFontNameTag; -import com.jpexs.decompiler.flash.tags.DefineText2Tag; -import com.jpexs.decompiler.flash.tags.DefineTextTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.GLYPHENTRY; @@ -196,10 +194,8 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable protected void shiftGlyphIndices(int fontId, int startIndex) { for (Tag t : swf.tags) { List textRecords = null; - if (t instanceof DefineTextTag) { - textRecords = ((DefineTextTag) t).textRecords; - } else if (t instanceof DefineText2Tag) { - textRecords = ((DefineText2Tag) t).textRecords; + if (t instanceof StaticTextTag) { + textRecords = ((StaticTextTag) t).textRecords; } if (textRecords != null) { @@ -298,6 +294,17 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable return defaultFontName; } + @Override + public int getUsedParameters() { + return PARAMETER_FRAME; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + RECT r = getRect(); + return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight())); + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { SHAPERECORD.shapeListToImage(swf, getGlyphShapeTable(), image, frame, Color.black, colorTransform); @@ -307,6 +314,26 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { } + @Override + public String toHtmlCanvas(double unitDivisor) { + List shapes = getGlyphShapeTable(); + StringBuilder sb = new StringBuilder(); + sb.append("\tdefaultFill = textColor;\r\n"); + sb.append("\tswitch(ch){\r\n"); + for (int i = 0; i < shapes.size(); i++) { + char c = glyphToChar(i); + String cs = "" + c; + cs = cs.replace("\\", "\\\\").replace("\"", "\\\""); + sb.append("\t\tcase \"").append(cs).append("\":\r\n"); + CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), new ColorTransform(), 0, 0); + exporter.export(); + sb.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t")); + sb.append("\tbreak;\r\n"); + } + sb.append("\t}\r\n"); + return sb.toString(); + } + @Override public int getNumFrames() { int frameCount = (getGlyphShapeTable().size() - 1) / SHAPERECORD.MAX_CHARACTERS_IN_FONT_PREVIEW + 1; @@ -321,12 +348,6 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable return true; } - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - RECT r = getRect(); - return new Area(new Rectangle(r.Xmin, r.Ymin, r.getWidth(), r.getHeight())); - } - @Override public RECT getRect() { return getRect(null); // parameter not used @@ -362,26 +383,6 @@ public abstract class FontTag extends CharacterTag implements AloneTag, Drawable return dfn.fontCopyright; } - @Override - public String toHtmlCanvas(double unitDivisor) { - List shapes = getGlyphShapeTable(); - StringBuilder sb = new StringBuilder(); - sb.append("\tdefaultFill = textColor;\r\n"); - sb.append("\tswitch(ch){\r\n"); - for (int i = 0; i < shapes.size(); i++) { - char c = glyphToChar(i); - String cs = "" + c; - cs = cs.replace("\\", "\\\\").replace("\"", "\\\""); - sb.append("\t\tcase \"").append(cs).append("\":\r\n"); - CanvasShapeExporter exporter = new CanvasShapeExporter(null, unitDivisor, swf, shapes.get(i), new ColorTransform(), 0, 0); - exporter.export(); - sb.append("\t\t").append(exporter.getShapeData().replaceAll("\r\n", "\r\n\t\t")); - sb.append("\tbreak;\r\n"); - } - sb.append("\t}\r\n"); - return sb.toString(); - } - public RECT getGlyphBounds(int glyphIndex) { return getGlyphShapeTable().get(glyphIndex).getBounds(); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java index 4849aa56d..052acf1ab 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ImageTag.java @@ -182,6 +182,16 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag { return new RECT(0, widthInTwips, 0, heightInTwips); } + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + return transformation.toTransform().createTransformedShape(getShape().getOutline()); + } + @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { BitmapExporter.export(swf, getShape(), null, image, transformation, colorTransform); @@ -210,11 +220,6 @@ public abstract class ImageTag extends CharacterTag implements DrawableTag { return true; } - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - return transformation.toTransform().createTransformedShape(getShape().getOutline()); - } - public void clearCache() { cachedImage = null; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java index ff46822b1..6858a2193 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ShapeTag.java @@ -66,6 +66,11 @@ public abstract class ShapeTag extends CharacterTag implements DrawableTag, Lazy return getRect(null); // parameter not used } + @Override + public int getUsedParameters() { + return 0; + } + @Override public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { return transformation.toTransform().createTransformedShape(getShapes().getOutline()); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java new file mode 100644 index 000000000..c40fe7182 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/StaticTextTag.java @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2010-2015 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.AppResources; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.configuration.Configuration; +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.helpers.HighlightedText; +import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; +import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType; +import com.jpexs.decompiler.flash.tags.text.ParsedSymbol; +import com.jpexs.decompiler.flash.tags.text.TextAlign; +import com.jpexs.decompiler.flash.tags.text.TextLexer; +import com.jpexs.decompiler.flash.tags.text.TextParseException; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.types.MATRIX; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.TEXTRECORD; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.SerializableImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author JPEXS + */ +public abstract class StaticTextTag extends TextTag { + + @SWFType(BasicType.UI16) + public int characterID; + + protected int glyphBits; + + protected int advanceBits; + + public RECT textBounds; + + public MATRIX textMatrix; + + public List textRecords; + + public abstract int getTextNum(); + + public StaticTextTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + @Override + public RECT getBounds() { + return textBounds; + } + + @Override + public MATRIX getTextMatrix() { + return textMatrix; + } + + @Override + public void setBounds(RECT r) { + textBounds = r; + } + + @Override + public List getTexts() { + FontTag fnt = null; + List ret = new ArrayList<>(); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont) { + FontTag fnt2 = swf.getFont(rec.fontId); + if (fnt2 != null) { + fnt = fnt2; + } + } + if (rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { + /*if (!ret.isEmpty()) { + ret += "\r\n"; + }*/ + } + + if (fnt == null) { + ret.add(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); + } else { + ret.add(rec.getText(fnt)); + } + } + return ret; + } + + @Override + public List getFontIds() { + List ret = new ArrayList<>(); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont) { + ret.add(rec.fontId); + } + } + return ret; + } + + @Override + public void updateTextBounds() { + updateTextBounds(textBounds); + } + + @Override + public boolean alignText(TextAlign textAlign) { + alignText(swf, textRecords, textAlign); + setModified(true); + return true; + } + + @Override + public boolean translateText(int diff) { + textMatrix.translateX += diff; + updateTextBounds(); + setModified(true); + return true; + } + + @Override + public RECT getRect(Set added) { + return textBounds; + } + + @Override + public ExportRectangle calculateTextBounds() { + return calculateTextBounds(swf, textRecords, getTextMatrix()); + } + + @Override + public int getNumFrames() { + return 1; + } + + @Override + public boolean isSingleFrame() { + return true; + } + + @Override + public void setCharacterId(int characterId) { + this.characterID = characterId; + } + + @Override + public int getCharacterId() { + return characterID; + } + + @Override + public HighlightedText getFormattedText() { + FontTag fnt = null; + HighlightedTextWriter writer = new HighlightedTextWriter(Configuration.getCodeFormatting(), true); + writer.append("[").newLine(); + writer.append("xmin " + textBounds.Xmin).newLine(); + writer.append("ymin " + textBounds.Ymin).newLine(); + writer.append("xmax " + textBounds.Xmax).newLine(); + writer.append("ymax " + textBounds.Ymax).newLine(); + if (textMatrix.translateX != 0) { + writer.append("translatex " + textMatrix.translateX).newLine(); + } + if (textMatrix.translateY != 0) { + writer.append("translatey " + textMatrix.translateY).newLine(); + } + if (textMatrix.hasScale) { + writer.append("scalex " + textMatrix.scaleX).newLine(); + writer.append("scaley " + textMatrix.scaleY).newLine(); + } + if (textMatrix.hasRotate) { + writer.append("rotateskew0 " + textMatrix.rotateSkew0).newLine(); + writer.append("rotateskew1 " + textMatrix.rotateSkew1).newLine(); + } + writer.append("]"); + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont || rec.styleFlagsHasColor || rec.styleFlagsHasXOffset || rec.styleFlagsHasYOffset) { + writer.append("[").newLine(); + if (rec.styleFlagsHasFont) { + FontTag fnt2 = swf.getFont(rec.fontId); + if (fnt2 != null) { + fnt = fnt2; + } + writer.append("font " + rec.fontId).newLine(); + writer.append("height " + rec.textHeight).newLine(); + } + if (rec.styleFlagsHasColor) { + if (getTextNum() == 1) { + writer.append("color " + rec.textColor.toHexRGB()).newLine(); + } else { + writer.append("color " + rec.textColorA.toHexARGB()).newLine(); + } + } + if (rec.styleFlagsHasXOffset) { + writer.append("x " + rec.xOffset).newLine(); + } + if (rec.styleFlagsHasYOffset) { + writer.append("y " + rec.yOffset).newLine(); + } + writer.append("]"); + } + + if (fnt == null) { + writer.append(AppResources.translate("fontNotFound").replace("%fontId%", Integer.toString(rec.fontId))); + } else { + writer.hilightSpecial(Helper.escapeActionScriptString(rec.getText(fnt)).replace("[", "\\[").replace("]", "\\]"), HighlightSpecialType.TEXT); + } + } + return new HighlightedText(writer); + } + + @Override + public boolean setFormattedText(MissingCharacterHandler missingCharHandler, String formattedText, String[] texts) throws TextParseException { + try { + TextLexer lexer = new TextLexer(new StringReader(formattedText)); + ParsedSymbol s = null; + List textRecords = new ArrayList<>(); + RGB color = null; + RGBA colorA = null; + int fontId = -1; + int textHeight = -1; + FontTag font = null; + String fontName = null; + Integer x = null; + Integer y = null; + int currentX = 0; + int currentY = 0; + int maxX = Integer.MIN_VALUE; + int minX = Integer.MAX_VALUE; + MATRIX textMatrix = new MATRIX(); + textMatrix.hasRotate = false; + textMatrix.hasScale = false; + RECT textBounds = new RECT(); + int textIdx = 0; + while ((s = lexer.yylex()) != null) { + switch (s.type) { + case PARAMETER: + String paramName = (String) s.values[0]; + String paramValue = (String) s.values[1]; + switch (paramName) { + case "color": + if (getTextNum() == 1) { + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + color = new RGB(Integer.parseInt(m.group(1), 16), Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16)); + } else { + throw new TextParseException("Invalid color. Valid format is #rrggbb. Found: " + paramValue, lexer.yyline()); + } + } else { + Matcher m = Pattern.compile("#([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])([0-9a-f][0-9a-f])").matcher(paramValue); + if (m.matches()) { + colorA = new RGBA(Integer.parseInt(m.group(2), 16), Integer.parseInt(m.group(3), 16), Integer.parseInt(m.group(4), 16), Integer.parseInt(m.group(1), 16)); + } else { + throw new TextParseException("Invalid color. Valid format is #aarrggbb. Found: " + paramValue, lexer.yyline()); + } + } + break; + case "font": + try { + fontId = Integer.parseInt(paramValue); + + FontTag ft = swf.getFont(fontId); + if (ft == null) { + throw new TextParseException("Font not found.", lexer.yyline()); + } + + font = (FontTag) ft; + fontName = font.getSystemFontName(); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid font id - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "height": + try { + textHeight = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid font height - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "x": + try { + x = Integer.parseInt(paramValue); + currentX = x; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid x position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "y": + try { + y = Integer.parseInt(paramValue); + currentY = y; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid y position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "xmin": + try { + textBounds.Xmin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmin position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "xmax": + try { + textBounds.Xmax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid xmax position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymin": + try { + textBounds.Ymin = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymin position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "ymax": + try { + textBounds.Ymax = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid ymax position - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "scalex": + try { + textMatrix.scaleX = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "scaley": + try { + textMatrix.scaleY = Integer.parseInt(paramValue); + textMatrix.hasScale = true; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid scalex value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "rotateskew0": + try { + textMatrix.rotateSkew0 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid rotateskew0 value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "rotateskew1": + try { + textMatrix.rotateSkew1 = Integer.parseInt(paramValue); + textMatrix.hasRotate = true; + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid rotateskew1 value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "translatex": + try { + textMatrix.translateX = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid translatex value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + case "translatey": + try { + textMatrix.translateY = Integer.parseInt(paramValue); + } catch (NumberFormatException nfe) { + throw new TextParseException("Invalid translatey value - number expected. Found: " + paramValue, lexer.yyline()); + } + break; + default: + throw new TextParseException("Unrecognized parameter name: " + paramName, lexer.yyline()); + } + break; + case TEXT: + String txt = (texts == null || textIdx >= texts.length) ? (String) s.values[0] : texts[textIdx++]; + if (txt == null || (font == null && txt.isEmpty())) { + continue; + } + + if (font == null) { + throw new TextParseException("Font not defined", lexer.yyline()); + } + + while (txt.charAt(0) == '\r' || txt.charAt(0) == '\n') { + txt = txt.substring(1); + } + + while (txt.charAt(txt.length() - 1) == '\r' || txt.charAt(txt.length() - 1) == '\n') { + txt = txt.substring(0, txt.length() - 1); + } + + StringBuilder txtSb = new StringBuilder(); + for (int i = 0; i < txt.length(); i++) { + char c = txt.charAt(i); + + if (!font.containsChar(c)) { + if (!missingCharHandler.handle(this, font, c)) { + if (!missingCharHandler.getIgnoreMissingCharacters()) { + return false; + } + } else { + return setFormattedText(missingCharHandler, formattedText, texts); + } + } else { + txtSb.append(c); + } + } + + txt = txtSb.toString(); + + TEXTRECORD tr = new TEXTRECORD(); + textRecords.add(tr); + if (fontId > -1) { + tr.fontId = fontId; + tr.textHeight = textHeight; + fontId = -1; + tr.styleFlagsHasFont = true; + } + if (getTextNum() == 1) { + if (color != null) { + tr.textColor = color; + tr.styleFlagsHasColor = true; + color = null; + } + } else { + if (colorA != null) { + tr.textColorA = colorA; + tr.styleFlagsHasColor = true; + colorA = null; + } + } + if (x != null) { + tr.xOffset = x; + tr.styleFlagsHasXOffset = true; + x = null; + } + if (y != null) { + tr.yOffset = y; + tr.styleFlagsHasYOffset = true; + y = null; + } + tr.glyphEntries = new ArrayList<>(txt.length()); + for (int i = 0; i < txt.length(); i++) { + char c = txt.charAt(i); + Character nextChar = null; + if (i + 1 < txt.length()) { + nextChar = txt.charAt(i + 1); + } + + GLYPHENTRY ge = new GLYPHENTRY(); + ge.glyphIndex = font.charToGlyph(c); + + int advance; + if (font.hasLayout()) { + int kerningAdjustment = 0; + if (nextChar != null) { + kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); + } + advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); + } else { + advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor), c, nextChar)); + } + + ge.glyphAdvance = advance; + tr.glyphEntries.add(ge); + + currentX += advance; + } + + if (currentX > maxX) { + maxX = currentX; + } + if (currentX < minX) { + minX = currentX; + } + break; + } + } + + setModified(true); + this.textRecords = textRecords; + this.textMatrix = textMatrix; + this.textBounds = textBounds; + } catch (IOException ex) { + return false; + } catch (TextParseException ex) { + throw ex; + } + + updateTextBounds(); + return true; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterID); + sos.writeRECT(textBounds); + sos.writeMatrix(textMatrix); + + int glyphBits = 0; + int advanceBits = 0; + for (TEXTRECORD tr : textRecords) { + for (GLYPHENTRY ge : tr.glyphEntries) { + glyphBits = SWFOutputStream.enlargeBitCountU(glyphBits, ge.glyphIndex); + advanceBits = SWFOutputStream.enlargeBitCountS(advanceBits, ge.glyphAdvance); + } + } + + if (Configuration.debugCopy.get()) { + glyphBits = Math.max(glyphBits, this.glyphBits); + advanceBits = Math.max(advanceBits, this.advanceBits); + } + + sos.writeUI8(glyphBits); + sos.writeUI8(advanceBits); + for (TEXTRECORD tr : textRecords) { + sos.writeTEXTRECORD(tr, getTextNum(), glyphBits, advanceBits); + } + sos.writeUI8(0); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterID = sis.readUI16("characterID"); + textBounds = sis.readRECT("textBounds"); + textMatrix = sis.readMatrix("textMatrix"); + glyphBits = sis.readUI8("glyphBits"); + advanceBits = sis.readUI8("advanceBits"); + textRecords = new ArrayList<>(); + TEXTRECORD tr; + while ((tr = sis.readTEXTRECORD(getTextNum(), glyphBits, advanceBits, "record")) != null) { + textRecords.add(tr); + } + } + + @Override + public void getNeededCharacters(Set needed) { + for (TEXTRECORD tr : textRecords) { + if (tr.styleFlagsHasFont) { + needed.add(tr.fontId); + } + } + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + for (TEXTRECORD tr : textRecords) { + if (tr.fontId == oldCharacterId) { + tr.fontId = newCharacterId; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + for (TEXTRECORD tr : textRecords) { + if (tr.fontId == characterId) { + tr.styleFlagsHasFont = false; + tr.fontId = 0; + modified = true; + } + } + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public int getUsedParameters() { + return 0; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + staticTextToImage(swf, textRecords, getTextNum(), image, textMatrix, transformation, colorTransform); + /*try { + TextTag originalTag = (TextTag) getOriginalTag(); + if (isModified()) { + originalTag.toImage(frame, time, ratio, renderContext, image, transformation, new ConstantColorColorTransform(0xFFC0C0C0)); + } + staticTextToImage(swf, textRecords, getTextNum(), image, getTextMatrix(), transformation, new ConstantColorColorTransform(0xFF000000)); + } catch (InterruptedException | IOException ex) { + Logger.getLogger(TextTag.class.getName()).log(Level.SEVERE, null, ex); + }*/ + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + staticTextToSVG(swf, textRecords, getTextNum(), exporter, getRect(), textMatrix, colorTransform, zoom); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + return staticTextToHtmlCanvas(unitDivisor, swf, textRecords, getTextNum(), textBounds, textMatrix, new ColorTransform()); + } +} diff --git a/nbproject/project.xml b/nbproject/project.xml index 80a24ea25..b58f2abf8 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -1,319 +1,344 @@ - - - org.netbeans.modules.ant.freeform - - - ffdec - - - - ffdec - - - - - . - UTF-8 - - - - java - src - UTF-8 - - - - java - test - UTF-8 - - - - java - libsrc/ffdec_lib/src - UTF-8 - - - - java - libsrc/ffdec_lib/test - UTF-8 - - - - java - libsrc/ffdec_lib/lexers - UTF-8 - - - - - build - - - clean - - - javadoc - - - run - - - test - - - clean - build - - - - debug-nb - - - - run-selected-file-in-src - - run.class - src - \.java$ - java-name - - - - - - - - run-selected-file-in-test - - run.class - test - \.java$ - java-name - - - - - - - - debug-selected-file-in-src - - debug.class - src - \.java$ - java-name - - - - - - - - test-selected-file - - test.class - test - \.java$ - java-name - - - - - - - - test-selected-method - - test.class - test - \.java$ - java-name - - - - - - - - test-debug-selected-method - - debug.class - test - \.java$ - java-name - - - - - - - - test-debug-selected-file - - debug.class - test - \.java$ - java-name - - - - - - - - profile-nb - - - - profile-selected-file-in-src - - profile.class - src - \.java$ - java-name - - - - - - - - debug-selected-file-in-test - - debug.class - test - \.java$ - java-name - - - - - - - - folder - build/classes - build - - - folder - build/test - build - - - - - - src - - - - test - - - - libsrc/ffdec_lib/src - - - - libsrc/ffdec_lib/test - - - - libsrc/ffdec_lib/lexers - - - build.xml - - - build.properties - - - tools.properties - - - jpexs_website.properties - - - nbproject/project.xml - - - nbproject/ide-file-targets.xml - - - nbproject/ide-targets.xml - - - - - - - - - - - - - - new-version-nightlybuild - - - - installer - - - - exe - - - - locales - - - - archive - - - - - gpl30 - - - - src - lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-6.2.jar;lib/jl1.0.1.jar;lib/nellymoser.jar;lib/gif.jar;lib/avi.jar;lib/ttf.jar;lib/jpacker.jar;lib/sfntly.jar;lib/gnujpdf.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar - build - javadoc - reports - locales - reports - dist - javadoc - 1.8 - - - test - - lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/jsyntaxpane-0.9.5.jar;src;testlib/emma.jar;testlib/emma_ant.jar;testlib/junit-4.8.2.jar;testlib/testng-6.8.jar;lib/ffdec_lib.jar - build/test - 1.8 - - - libsrc/ffdec_lib/src - 1.8 - - - libsrc/ffdec_lib/test - - lib/ffdec_lib.jar;libsrc/ffdec_lib/src;libsrc/ffdec_lib/testlib/emma.jar;libsrc/ffdec_lib/testlib/emma_ant.jar;libsrc/ffdec_lib/testlib/testng-6.8.jar - 1.8 - - - libsrc/ffdec_lib/lexers - 1.8 - - - - + + + org.netbeans.modules.ant.freeform + + + ffdec + + + + ffdec + + + + + . + UTF-8 + + + + java + src + UTF-8 + + + + java + test + UTF-8 + + + + java + libsrc/ffdec_lib/src + UTF-8 + + + + java + libsrc/ffdec_lib/test + UTF-8 + + + + java + libsrc/ffdec_lib/lexers + UTF-8 + + + + + build + + + clean + + + javadoc + + + run + + + test + + + clean + build + + + + debug-nb + + + + run-selected-file-in-src + + run.class + src + \.java$ + java-name + + + + + + + + run-selected-file-in-test + + run.class + test + \.java$ + java-name + + + + + + + + debug-selected-file-in-src + + debug.class + src + \.java$ + java-name + + + + + + + + test-selected-file + + test.class + test + \.java$ + java-name + + + + + + + + test-selected-method + + test.class + test + \.java$ + java-name + + + + + + + + test-debug-selected-method + + debug.class + test + \.java$ + java-name + + + + + + + + test-debug-selected-file + + debug.class + test + \.java$ + java-name + + + + + + + + profile-nb + + + + profile-selected-file-in-src + + profile.class + src + \.java$ + java-name + + + + + + + + debug-selected-file-in-test + + debug.class + test + \.java$ + java-name + + + + + + + + folder + build + build + + + folder + javadoc + build + + + folder + reports + build + + + folder + locales + build + + + folder + reports + build + + + folder + dist + build + + + folder + build/test + build + + + + + + src + + + + test + + + + libsrc/ffdec_lib/src + + + + libsrc/ffdec_lib/test + + + + libsrc/ffdec_lib/lexers + + + build.xml + + + build.properties + + + tools.properties + + + jpexs_website.properties + + + nbproject/project.xml + + + nbproject/ide-file-targets.xml + + + nbproject/ide-targets.xml + + + + + + + + + + + + + + new-version-nightlybuild + + + + installer + + + + exe + + + + locales + + + + archive + + + + + gpl30 + + + + src + lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-6.2.jar;lib/jl1.0.1.jar;lib/nellymoser.jar;lib/gif.jar;lib/avi.jar;lib/ttf.jar;lib/jpacker.jar;lib/sfntly.jar;lib/gnujpdf.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar + build + javadoc + reports + locales + reports + dist + javadoc + 1.8 + + + test + + lib/LZMA.jar;lib/jna-3.5.1.jar;lib/jpproxy.jar;lib/jsyntaxpane-0.9.5.jar;src;testlib/emma.jar;testlib/emma_ant.jar;testlib/junit-4.8.2.jar;testlib/testng-6.8.jar;lib/ffdec_lib.jar + build/test + 1.8 + + + libsrc/ffdec_lib/src + 1.8 + + + libsrc/ffdec_lib/test + + lib/ffdec_lib.jar;libsrc/ffdec_lib/src;libsrc/ffdec_lib/testlib/emma.jar;libsrc/ffdec_lib/testlib/emma_ant.jar;libsrc/ffdec_lib/testlib/testng-6.8.jar + 1.8 + + + libsrc/ffdec_lib/lexers + 1.8 + + + + diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index ddf3e107c..3915da781 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -960,28 +960,30 @@ public final class ImagePanel extends JPanel implements MediaDisplay { @Override public void run() { - try { - synchronized (ImagePanel.class) { - if (timer != thisTimer) { - return; - } - } - - if (isSingleFrame) { - drawFrame(thisTimer); + while (true) { + try { synchronized (ImagePanel.class) { - thisTimer.cancel(); - if (timer == thisTimer) { - timer = null; + if (timer != thisTimer) { + return; } } - fireMediaDisplayStateChanged(); - } else { - nextFrame(thisTimer); + if (isSingleFrame) { + drawFrame(thisTimer); + synchronized (ImagePanel.class) { + thisTimer.cancel(); + if (timer == thisTimer) { + timer = null; + } + } + + fireMediaDisplayStateChanged(); + } else { + nextFrame(thisTimer); + } + } catch (Exception ex) { + Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); } - } catch (Exception ex) { - Logger.getLogger(ImagePanel.class.getName()).log(Level.SEVERE, null, ex); } } }; @@ -989,7 +991,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { if (singleFrame) { timer.schedule(task, 0); } else { - timer.schedule(task, 0, msPerFrame); + timer.schedule(task, 0); } }