mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-29 23:25:51 +00:00
Base class for DefineXTags, getting the images, fonts, text from the characterMap instead of iterating over all tags
This commit is contained in:
@@ -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<ABCContainerTag> getAbcList() {
|
||||
if (abcList == null) {
|
||||
synchronized (this) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<Integer, String[]> 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<Integer, String[]> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ public class DefineEditTextTag extends TextTag {
|
||||
private List<CharacterWithStyle> 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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<TEXTRECORD> 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<String> getTexts() {
|
||||
FontTag fnt = null;
|
||||
List<String> 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<Integer> getFontIds() {
|
||||
List<Integer> 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<TEXTRECORD> 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<BoundedTag> 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<Integer> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<TEXTRECORD> 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<String> getTexts() {
|
||||
FontTag fnt = null;
|
||||
List<String> 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<Integer> getFontIds() {
|
||||
List<Integer> 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<TEXTRECORD> 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<TEXTRECORD> 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<BoundedTag> added) {
|
||||
return textBounds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNeededCharacters(Set<Integer> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<TEXTRECORD> 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<SHAPE> 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<SHAPE> 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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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<TEXTRECORD> 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<String> getTexts() {
|
||||
FontTag fnt = null;
|
||||
List<String> 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<Integer> getFontIds() {
|
||||
List<Integer> 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<BoundedTag> 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<TEXTRECORD> 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<Integer> 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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user