Issue #250 Export FLA: Static text spacing and marigins

Better text viewer
code formatting
This commit is contained in:
Jindra Petk
2013-07-29 07:22:26 +02:00
parent e2e9e94779
commit a02164197e
21 changed files with 298 additions and 140 deletions

View File

@@ -50,7 +50,6 @@ import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictEqAVM2Item;
import com.jpexs.decompiler.flash.abc.avm2.model.operations.StrictNeqAVM2Item;
import com.jpexs.decompiler.flash.abc.types.ABCException;
import com.jpexs.decompiler.flash.abc.types.MethodBody;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.graph.Graph;
import com.jpexs.decompiler.graph.GraphPart;
import com.jpexs.decompiler.graph.GraphPartMulti;

View File

@@ -59,33 +59,33 @@ public class ExportDialog extends AppDialog {
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
JPanel comboPanel=new JPanel(null);
JPanel comboPanel = new JPanel(null);
combos = new JComboBox[optionNames.length];
JLabel labels[]=new JLabel[optionNames.length];
int labWidth=0;
JLabel labels[] = new JLabel[optionNames.length];
int labWidth = 0;
for (int i = 0; i < optionNames.length; i++) {
labels[i] = new JLabel(optionNames[i]);
if(labels[i].getPreferredSize().width>labWidth){
if (labels[i].getPreferredSize().width > labWidth) {
labWidth = labels[i].getPreferredSize().width;
}
}
int comboWidth=200;
int comboWidth = 200;
int top = 10;
for (int i = 0; i < optionNames.length; i++) {
JLabel lab = new JLabel(optionNames[i]);
lab.setBounds(10, top, lab.getPreferredSize().width, lab.getPreferredSize().height);
comboPanel.add(lab);
combos[i] = new JComboBox<>(options[i]);
combos[i].setBounds(10+labWidth+10, top, comboWidth, combos[i].getPreferredSize().height);
combos[i].setBounds(10 + labWidth + 10, top, comboWidth, combos[i].getPreferredSize().height);
comboPanel.add(combos[i]);
top += combos[i].getHeight();
}
Dimension dim=new Dimension(10+labWidth+10+comboWidth+10,top+10);
Dimension dim = new Dimension(10 + labWidth + 10 + comboWidth + 10, top + 10);
comboPanel.setMinimumSize(dim);
comboPanel.setPreferredSize(dim);
cnt.add(comboPanel,BorderLayout.CENTER);
cnt.add(comboPanel, BorderLayout.CENTER);
JPanel buttonsPanel=new JPanel(new FlowLayout());
JPanel buttonsPanel = new JPanel(new FlowLayout());
JButton okButton = new JButton(translate("button.ok"));
okButton.addActionListener(new ActionListener() {
@Override
@@ -93,7 +93,7 @@ public class ExportDialog extends AppDialog {
setVisible(false);
}
});
JButton cancelButton = new JButton(translate("button.cancel"));
cancelButton.addActionListener(new ActionListener() {
@Override
@@ -102,11 +102,11 @@ public class ExportDialog extends AppDialog {
setVisible(false);
}
});
buttonsPanel.add(okButton);
buttonsPanel.add(cancelButton);
cnt.add(buttonsPanel,BorderLayout.SOUTH);
cnt.add(buttonsPanel, BorderLayout.SOUTH);
pack();
//setSize(245, top + getInsets().top);
View.centerScreen(this);

View File

@@ -36,36 +36,22 @@ import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.gui.proxy.ProxyFrame;
import com.jpexs.decompiler.flash.helpers.Cache;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.types.ZONERECORD;
import com.sun.jna.Platform;
import com.sun.jna.WString;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.awt.geom.QuadCurve2D;
import java.io.*;
import java.net.Socket;
import java.net.URLDecoder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.AttributedCharacterIterator.Attribute;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import java.util.logging.ConsoleHandler;
@@ -77,12 +63,9 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import static javax.swing.WindowConstants.HIDE_ON_CLOSE;
import javax.swing.filechooser.FileFilter;
/**
@@ -523,7 +506,7 @@ public class Main {
}
public static void initLang() {
if (Configuration.containsConfig("locale")) {
if (Configuration.containsConfig("locale")) {
Locale.setDefault(Locale.forLanguageTag((String) Configuration.getConfig("locale", "en")));
}
UIManager.put("OptionPane.okButtonText", AppStrings.translate("button.ok"));
@@ -630,7 +613,7 @@ public class Main {
initLang();
View.setLookAndFeel();
if ((Boolean) Configuration.getConfig("cacheOnDisk", Boolean.TRUE)) {
Cache.setStorageType(Cache.STORAGE_FILES);
} else {

View File

@@ -1162,8 +1162,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
fontParams1.add(fontAddCharsPanel);
JPanel fontSelectionPanel = new JPanel(new FlowLayout());
fontSelectionPanel.add(new JLabel(translate("font.source")));
String fontNames[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
fontSelection = new JComboBox<>(fontNames);
fontSelection = new JComboBox<>(FontTag.fontNames.toArray(new String[FontTag.fontNames.size()]));
fontSelection.setSelectedIndex(0);
fontSelection.setSelectedItem("Times New Roman");
fontSelection.setSelectedItem("Arial");
@@ -2382,16 +2381,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
if (fontName == null) {
fontName = font.getFontName(tags);
}
//
if (!fontNames.contains(fontName)) {
fontName = "Times New Roman";
}
if (!fontNames.contains(fontName)) {
fontName = "Arial";
}
if (!fontNames.contains(fontName)) {
fontName = fontSelection.getItemAt(0);
}
fontName = FontTag.findInstalledFontName(fontName);
Font f = new Font(fontName, font.getFontStyle(), 18);
if (!f.canDisplay(character)) {
View.showMessageDialog(null, translate("error.font.nocharacter").replace("%char%", "" + character), translate("error"), JOptionPane.ERROR_MESSAGE);
@@ -3105,10 +3095,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
if (sourceFontsMap.containsKey(ft.getFontId())) {
fontSelection.setSelectedItem(sourceFontsMap.get(ft.getFontId()));
} else {
fontSelection.setSelectedIndex(0);
fontSelection.setSelectedItem("Times New Roman");
fontSelection.setSelectedItem("Arial");
fontSelection.setSelectedItem(ft.getFontName(swf.tags));
fontSelection.setSelectedItem(FontTag.findInstalledFontName(ft.getFontName(swf.tags)));
}
fontChangeList.componentResized(null);
showDetailWithPreview(CARDFONTPANEL);

View File

@@ -33,7 +33,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import javax.swing.JOptionPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

View File

@@ -27,16 +27,12 @@ import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
import static com.jpexs.decompiler.flash.gui.AppStrings.translate;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.helpers.Cache;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.helpers.Highlighting;
import com.jpexs.decompiler.flash.tags.ABCContainerTag;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

View File

@@ -25,7 +25,6 @@ import static com.jpexs.decompiler.flash.gui.AppStrings.translate;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.helpers.Helper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.*;

View File

@@ -24,11 +24,7 @@ import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
import com.jpexs.decompiler.flash.types.ARGB;
import com.jpexs.decompiler.flash.types.RGBA;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

View File

@@ -19,7 +19,6 @@ package com.jpexs.decompiler.flash.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
import com.jpexs.decompiler.flash.tags.base.TextTag;
@@ -50,7 +49,7 @@ import java.util.regex.Pattern;
*
* @author JPEXS
*/
public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextTag {
public class DefineEditTextTag extends TextTag {
public int characterID;
public RECT bounds;

View File

@@ -26,7 +26,6 @@ import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import java.awt.Font;
import java.awt.font.GlyphVector;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -78,7 +77,7 @@ public class DefineFont2Tag extends FontTag {
if (fontFlagsHasLayout) {
return fontAdvanceTable.get(glyphIndex);
} else {
return getGlyphWidth(glyphIndex) + 20;
return -1;
}
}
@@ -348,4 +347,9 @@ public class DefineFont2Tag extends FontTag {
}
return ret;
}
@Override
public boolean hasLayout() {
return fontFlagsHasLayout;
}
}

View File

@@ -32,11 +32,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
public class DefineFont3Tag extends FontTag {
@@ -71,7 +68,7 @@ public class DefineFont3Tag extends FontTag {
@Override
public int getGlyphWidth(int glyphIndex) {
return glyphShapeTable.get(glyphIndex).getBounds().getWidth() / 20;
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
}
@Override
@@ -79,7 +76,7 @@ public class DefineFont3Tag extends FontTag {
if (fontFlagsHasLayout) {
return fontAdvanceTable.get(glyphIndex) / 20;
} else {
return getGlyphWidth(glyphIndex) + 20;
return -1;
}
}
@@ -349,4 +346,9 @@ public class DefineFont3Tag extends FontTag {
}
return ret;
}
@Override
public boolean hasLayout() {
return fontFlagsHasLayout;
}
}

View File

@@ -49,7 +49,7 @@ public class DefineFontTag extends FontTag {
@Override
public int getGlyphAdvance(int glyphIndex) {
return getGlyphWidth(glyphIndex);
return -1;
}
@Override

View File

@@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
@@ -64,7 +63,7 @@ import java.util.regex.Pattern;
*
* @author JPEXS
*/
public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag, DrawableTag {
public class DefineText2Tag extends TextTag implements DrawableTag {
public int characterID;
public RECT textBounds;
@@ -343,17 +342,15 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
}
tr.glyphEntries[i].glyphIndex = font.charToGlyph(tags, c);
/*if (tr.glyphEntries[i].glyphIndex == -1) {
throw new ParseException("Font does not contain glyph for character '" + c + "'", lexer.yyline());
}*/
tr.glyphEntries[i].glyphAdvance = textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / 1024;
int gw = textHeight * font.getGlyphWidth(tr.glyphEntries[i].glyphIndex) / 1024;
if (i == 0) {
currentX += gw;
int advance;
if (font.hasLayout()) {
advance = (int) Math.round((double) textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / (font.getDivider() * 1024.0));
} else {
currentX += tr.glyphEntries[i].glyphAdvance;
advance = 20 * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), textHeight / 20, c);
}
tr.glyphEntries[i].glyphAdvance = advance;
currentX += advance;
if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) {
glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex);
}
@@ -461,6 +458,8 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
@Override
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters, Stack<Integer> visited) {
RECT bound = getBounds();
int fixX = -bound.Xmin;
int fixY = -bound.Ymin;
BufferedImage ret = new BufferedImage(bound.Xmax / 20, bound.Ymax / 20, BufferedImage.TYPE_INT_ARGB);
Color textColor = new Color(0, 0, 0);
FontTag font = null;
@@ -482,10 +481,10 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
textHeight = rec.textHeight;
}
if (rec.styleFlagsHasXOffset) {
x = rec.xOffset * 1024 / textHeight;
x = rec.xOffset;
}
if (rec.styleFlagsHasYOffset) {
y = rec.yOffset * 1024 / textHeight;
y = rec.yOffset;
}
for (GLYPHENTRY entry : rec.glyphEntries) {
@@ -494,14 +493,15 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
rect.Xmin /= font.getDivider();
rect.Ymax /= font.getDivider();
rect.Ymin /= font.getDivider();
BufferedImage img = SHAPERECORD.shapeToImage(tags, 4, null, null, glyphs.get(entry.glyphIndex).shapeRecords, textColor);
BufferedImage img = SHAPERECORD.shapeToImage(tags, 1, null, null, glyphs.get(entry.glyphIndex).shapeRecords, textColor);
AffineTransform tr = new AffineTransform();
tr.setToIdentity();
float rat = textHeight / 1024f;
tr.translate(rat * x / 20, rat * (y + rect.Ymin) / 20);
tr.scale(rat / font.getDivider(), rat / font.getDivider());
tr.scale(1 / 20f, 1 / 20f);
tr.translate(x + fixX, y + rat * rect.Ymin + fixY);
tr.scale(rat, rat);
g.drawImage(img, tr, null);
x += entry.glyphAdvance * 1024 / textHeight;
x += entry.glyphAdvance;
}
}
return ret;

View File

@@ -20,7 +20,6 @@ import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.Helper;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
@@ -64,7 +63,7 @@ import java.util.regex.Pattern;
*
* @author JPEXS
*/
public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag, DrawableTag {
public class DefineTextTag extends TextTag implements DrawableTag {
public int characterID;
public RECT textBounds;
@@ -342,19 +341,15 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
}
tr.glyphEntries[i].glyphIndex = font.charToGlyph(tags, c);
/*if (tr.glyphEntries[i].glyphIndex == -1) {
throw new ParseException("Font does not contain glyph for character '" + c + "'", lexer.yyline());
}*/
tr.glyphEntries[i].glyphAdvance = textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / 1024;
int gw = textHeight * font.getGlyphWidth(tr.glyphEntries[i].glyphIndex) / 1024;
if (i == 0) {
currentX += gw;
int advance;
if (font.hasLayout()) {
advance = (int) Math.round((double) textHeight * font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) / (font.getDivider() * 1024.0));
} else {
currentX += tr.glyphEntries[i].glyphAdvance;
advance = 20 * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), textHeight / 20, c);
}
tr.glyphEntries[i].glyphAdvance = advance;
currentX += advance;
if (SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex) > glyphBits) {
glyphBits = SWFOutputStream.getNeededBitsU(tr.glyphEntries[i].glyphIndex);
}
@@ -497,10 +492,10 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
textHeight = rec.textHeight;
}
if (rec.styleFlagsHasXOffset) {
x = rec.xOffset * 1024 / textHeight;
x = rec.xOffset;
}
if (rec.styleFlagsHasYOffset) {
y = rec.yOffset * 1024 / textHeight;
y = rec.yOffset;
}
for (GLYPHENTRY entry : rec.glyphEntries) {
@@ -513,11 +508,11 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
AffineTransform tr = new AffineTransform();
tr.setToIdentity();
float rat = textHeight / 1024f;
tr.translate(rat * x / 20, rat * (y + rect.Ymin) / 20);
tr.scale(rat / font.getDivider(), rat / font.getDivider());
tr.translate(fixX, fixY);
tr.scale(1 / 20f, 1 / 20f);
tr.translate(x + fixX, y + rat * rect.Ymin + fixY);
tr.scale(rat, rat);
g.drawImage(img, tr, null);
x += entry.glyphAdvance * 1024 / textHeight;
x += entry.glyphAdvance;
}
}
return ret;

View File

@@ -24,7 +24,12 @@ import com.jpexs.decompiler.flash.types.GLYPHENTRY;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -67,6 +72,10 @@ public abstract class FontTag extends CharacterTag implements AloneTag {
public abstract int getLeading();
public boolean hasLayout() {
return false;
}
public boolean containsChar(List<Tag> tags, char character) {
return charToGlyph(tags, character) > -1;
}
@@ -125,4 +134,36 @@ public abstract class FontTag extends CharacterTag implements AloneTag {
}
}
}
public static int getSystemFontAdvance(String fontName, int fontStyle, int fontSize, char character) {
return getSystemFontAdvance(new Font(fontName, fontStyle, fontSize), character);
}
public static int getSystemFontAdvance(Font aFont, char character) {
GlyphVector gv = aFont.createGlyphVector(new FontRenderContext(aFont.getTransform(), true, true), "" + character);
GlyphMetrics gm = gv.getGlyphMetrics(0);
return Math.round(gm.getAdvanceX());
}
public static List<String> fontNames = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
public static String findInstalledFontName(String fontName) {
if (fontNames.contains(fontName)) {
return fontName;
}
if (fontName.contains("_")) {
String beforeUnderscore = fontName.substring(0, fontName.indexOf("_"));
if (fontNames.contains(beforeUnderscore)) {
return beforeUnderscore;
}
}
fontName = "Times New Roman";
if (fontNames.contains(fontName)) {
return fontName;
}
fontName = "Arial";
if (fontNames.contains(fontName)) {
return fontName;
}
return fontNames.get(0);
}
}

View File

@@ -60,23 +60,24 @@ public abstract class ImageTag extends CharacterTag {
return "unk";
}
protected static int max255(float val){
if(val>255){
protected static int max255(float val) {
if (val > 255) {
return 255;
}
return (int)val;
return (int) val;
}
protected static Color intToColor(int val){
return new Color(val&0xff,(val>>8)&0xff,(val>>16)&0xff,(val>>24)&0xff);
protected static Color intToColor(int val) {
return new Color(val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff);
}
protected static int colorToInt(Color c){
return (c.getAlpha()<<24)|(c.getBlue()<<16)|(c.getGreen()<<8)|c.getRed();
protected static int colorToInt(Color c) {
return (c.getAlpha() << 24) | (c.getBlue() << 16) | (c.getGreen() << 8) | c.getRed();
}
protected static Color multiplyAlpha(Color c){
float multiplier = c.getAlpha()==0?0:255.0f/c.getAlpha();
return new Color(max255(c.getRed()*multiplier), max255(c.getGreen()*multiplier), max255(c.getBlue()*multiplier), c.getAlpha());
protected static Color multiplyAlpha(Color c) {
float multiplier = c.getAlpha() == 0 ? 0 : 255.0f / c.getAlpha();
return new Color(max255(c.getRed() * multiplier), max255(c.getGreen() * multiplier), max255(c.getBlue() * multiplier), c.getAlpha());
}
}

View File

@@ -16,29 +16,177 @@
*/
package com.jpexs.decompiler.flash.tags.base;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.text.ParseException;
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.SHAPE;
import com.jpexs.decompiler.flash.types.TEXTRECORD;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.font.LineMetrics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author JPEXS
*/
public interface TextTag {
public abstract class TextTag extends CharacterTag implements BoundedTag {
public MATRIX getTextMatrix();
public TextTag(SWF swf, int id, String name, byte[] data, long pos) {
super(swf, id, name, data, pos);
}
public String getText(List<Tag> tags);
public abstract MATRIX getTextMatrix();
public String getFormattedText(List<Tag> tags);
public abstract String getText(List<Tag> tags);
public boolean setFormattedText(MissingCharacterHandler missingCharHandler, List<Tag> tags, String text, String fontName) throws ParseException;
public abstract String getFormattedText(List<Tag> tags);
public int getCharacterId();
public abstract boolean setFormattedText(MissingCharacterHandler missingCharHandler, List<Tag> tags, String text, String fontName) throws ParseException;
public RECT getBounds();
@Override
public abstract int getCharacterId();
public void setBounds(RECT r);
public abstract RECT getBounds();
public abstract void setBounds(RECT r);
private static void updateRect(RECT ret, int x, int y) {
if (x < ret.Xmin) {
ret.Xmin = x;
}
if (x > ret.Xmax) {
ret.Xmax = x;
}
if (y < ret.Ymin) {
ret.Ymin = y;
}
if (y > ret.Ymax) {
ret.Ymax = y;
}
}
public static Map<String, Object> getTextRecordsAttributes(List<TEXTRECORD> list, List<Tag> tags) {
Map<String, Object> att = new HashMap<>();
RECT textBounds = new RECT(Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE);
FontTag font = null;
int x = 0;
int y = 0;
int textHeight = 12;
int lineSpacing = 0;
double leading = 0;
double ascent = 0;
double descent = 0;
double lineDistance = 0;
List<String> availableFonts = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
List<SHAPE> glyphs = new ArrayList<>();
boolean firstLine = true;
double top = 0;
List<Integer> allLeftMargins = new ArrayList<>();
List<Integer> allLetterSpacings = new ArrayList<>();
FontMetrics fontMetrics = null;
BufferedImage bi = new BufferedImage(5, 5, BufferedImage.TYPE_INT_RGB);
Font aFont = null;
int currentLeftMargin = 0;
for (int r = 0; r < list.size(); r++) {
TEXTRECORD rec = list.get(r);
if (rec.styleFlagsHasFont) {
for (Tag t : tags) {
if (t instanceof FontTag) {
FontTag ft = (FontTag) t;
if (ft.getFontId() == rec.fontId) {
font = ft;
}
}
}
textHeight = rec.textHeight;
glyphs = font.getGlyphShapeTable();
if (font.getLeading() == -1) {
String fontName = font.getFontName(tags);
if (!availableFonts.contains(fontName)) {
fontName = "Times New Roman";
}
if (!availableFonts.contains(fontName)) {
fontName = "Arial";
}
aFont = new Font(fontName, font.getFontStyle(), textHeight / 20);
fontMetrics = bi.getGraphics().getFontMetrics(aFont);
LineMetrics lm = fontMetrics.getLineMetrics("A", bi.getGraphics());
ascent = lm.getAscent();
descent = lm.getDescent();
leading = lm.getLeading();
lineDistance = ascent + descent;
} else {
leading = ((double) font.getLeading() * textHeight / 1024.0 / font.getDivider() / 20.0);
ascent = ((double) font.getAscent() * textHeight / 1024.0 / font.getDivider() / 20.0);
descent = ((double) font.getDescent() * textHeight / 1024.0 / font.getDivider() / 20.0);
lineDistance = ascent + descent;
}
}
currentLeftMargin = 0;
if (rec.styleFlagsHasXOffset) {
x = rec.xOffset;
currentLeftMargin = x;
}
if (rec.styleFlagsHasYOffset) {
if (!firstLine) {
top += lineDistance;
int topint = 20 * (int) Math.round(top);
lineSpacing = rec.yOffset - topint;
top += ((double) lineSpacing) / 20;
} else {
top = ascent - 2.0; //I don't know why, but there are always 2 pixels
}
y = rec.yOffset;
}
firstLine = false;
String lineStr = "";
allLeftMargins.add(currentLeftMargin);
int letterSpacing = 0;
for (int e = 0; e < rec.glyphEntries.length; e++) {
GLYPHENTRY entry = rec.glyphEntries[e];
GLYPHENTRY nextEntry = null;
if (e < rec.glyphEntries.length - 1) {
nextEntry = rec.glyphEntries[e + 1];
}
RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords);
rect.Xmax = (int) Math.round(((double) rect.Xmax * textHeight) / (font.getDivider() * 1024));
rect.Xmin = (int) Math.round(((double) rect.Xmin * textHeight) / (font.getDivider() * 1024));
rect.Ymax = (int) Math.round(((double) rect.Ymax * textHeight) / (font.getDivider() * 1024));
rect.Ymin = (int) Math.round(((double) rect.Ymin * textHeight) / (font.getDivider() * 1024));
updateRect(textBounds, x + rect.Xmin, y + rect.Ymin);
updateRect(textBounds, x + rect.Xmax, y + rect.Ymax);
int adv = entry.glyphAdvance;
int defaultAdvance = 20 * FontTag.getSystemFontAdvance(aFont, font.glyphToChar(tags, entry.glyphIndex));
letterSpacing = adv - defaultAdvance;
x += adv;
}
allLetterSpacings.add(letterSpacing);
}
att.put("indent", 0); //?
att.put("rightMargin", 0); //?
att.put("lineSpacing", lineSpacing);
att.put("textBounds", textBounds);
att.put("allLeftMargins", allLeftMargins);
att.put("allLetterSpacings", allLetterSpacings);
return att;
}
}

View File

@@ -19,6 +19,8 @@ package com.jpexs.decompiler.flash.types;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.util.HashSet;
import java.util.List;

View File

@@ -16,14 +16,6 @@
*/
package com.jpexs.decompiler.flash.types;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.LineMetrics;
import javax.swing.JFrame;
/**
* Represents 32-bit alpha, red, green and blue value
*

View File

@@ -35,7 +35,6 @@ import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsEnvironment;
import java.awt.LinearGradientPaint;
@@ -49,10 +48,8 @@ import java.awt.TexturePaint;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,7 +60,6 @@ import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**

View File

@@ -2277,6 +2277,8 @@ public class XFLConverter {
ret += " instanceName=\"" + xmlString(instanceName) + "\"";
}
ret += antiAlias;
Map<String, Object> attrs = TextTag.getTextRecordsAttributes(textRecords, tags);
ret += " width=\"" + tag.getBounds().getWidth() / 2 + "\" height=\"" + tag.getBounds().getHeight() + "\" autoExpand=\"true\" isSelectable=\"false\">";
ret += matStr;
@@ -2289,7 +2291,14 @@ public class XFLConverter {
int textHeight = -1;
RGB textColor = null;
RGBA textColorA = null;
for (TEXTRECORD rec : textRecords) {
boolean newline = false;
boolean firstRun = true;
@SuppressWarnings("unchecked")
List<Integer> leftMargins = (List<Integer>) attrs.get("allLeftMargins");
@SuppressWarnings("unchecked")
List<Integer> letterSpacings = (List<Integer>) attrs.get("allLetterSpacings");
for (int r = 0; r < textRecords.size(); r++) {
TEXTRECORD rec = textRecords.get(r);
if (rec.styleFlagsHasColor) {
if (tag instanceof DefineTextTag) {
textColor = rec.textColor;
@@ -2327,13 +2336,23 @@ public class XFLConverter {
}
}
}
newline = false;
if (!firstRun && rec.styleFlagsHasYOffset) {
newline = true;
}
firstRun = false;
if (font != null) {
ret += "<DOMTextRun>";
ret += "<characters>" + xmlString(rec.getText(tags, font)) + "</characters>";
ret += "<characters>" + xmlString((newline ? "\r" : "") + rec.getText(tags, font)) + "</characters>";
ret += "<textAttrs>";
ret += "<DOMTextAttrs aliasText=\"false\" rotation=\"true\" size=\"" + twipToPixel(textHeight) + "\" bitmapSize=\"" + textHeight + "\"";
//indent=\"5\" leftMargin=\"2\" letterSpacing=\"1\" lineSpacing=\"6\" rightMargin=\"3\"
ret += " letterSpacing=\"" + doubleToString(twipToPixel(letterSpacings.get(r))) + "\"";
ret += " indent=\"" + doubleToString(twipToPixel((int) attrs.get("indent"))) + "\"";
ret += " leftMargin=\"" + doubleToString(twipToPixel(leftMargins.get(r))) + "\"";
ret += " lineSpacing=\"" + doubleToString(twipToPixel((int) attrs.get("lineSpacing"))) + "\"";
ret += " rightMargin=\"" + doubleToString(twipToPixel((int) attrs.get("rightMargin"))) + "\"";
if (textColor != null) {
ret += " fillColor=\"" + textColor.toHexRGB() + "\"";
} else if (textColorA != null) {