mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-08 12:33:48 +00:00
Issue #220 Improved font changing
This commit is contained in:
@@ -3020,9 +3020,9 @@ public class SWFInputStream extends InputStream {
|
||||
for (int i = 0; i < numZoneData; i++) {
|
||||
ret.zonedata[i] = readZONEDATA();
|
||||
}
|
||||
readUB(6);
|
||||
ret.zoneMaskX = readUB(1) == 1;
|
||||
readUB(6);
|
||||
ret.zoneMaskY = readUB(1) == 1;
|
||||
ret.zoneMaskX = readUB(1) == 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1592,8 +1592,8 @@ public class SWFOutputStream extends OutputStream {
|
||||
writeZONEDATA(value.zonedata[i]);
|
||||
}
|
||||
writeUB(6, 0);
|
||||
writeUB(1, value.zoneMaskX ? 1 : 0);
|
||||
writeUB(1, value.zoneMaskY ? 1 : 0);
|
||||
writeUB(1, value.zoneMaskX ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,22 +36,36 @@ 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;
|
||||
@@ -63,9 +77,12 @@ 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;
|
||||
|
||||
/**
|
||||
@@ -598,6 +615,7 @@ public class Main {
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
loadProperties();
|
||||
Configuration.loadFromFile(getConfigFile(), getReplacementsFile());
|
||||
int pos = 0;
|
||||
@@ -613,6 +631,102 @@ public class Main {
|
||||
|
||||
View.setLookAndFeel();
|
||||
|
||||
/*View.execInEventDispatch(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new JFrame() {
|
||||
private int size = 15*1024;
|
||||
@Override
|
||||
public void setVisible(boolean b) {
|
||||
addKeyListener(new KeyAdapter() {
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
size+=10;
|
||||
repaint();
|
||||
}
|
||||
|
||||
});
|
||||
addWindowListener(new WindowAdapter(){
|
||||
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
super.windowClosing(e);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
});
|
||||
getContentPane().add(new JPanel() {
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
AffineTransform t = AffineTransform.getTranslateInstance(0, 0);
|
||||
t.translate(200, 400);
|
||||
t.scale((((float)size)/1024)/(2000),(((float)size)/1024)/2000);
|
||||
|
||||
g2d.setTransform(t);
|
||||
|
||||
Font f = new Font("Cordia New", 0, size);
|
||||
GlyphVector v = f.createGlyphVector((new JPanel()).getFontMetrics(f).getFontRenderContext(), "C");
|
||||
Shape shp = v.getOutline();
|
||||
g2d.setPaint(Color.black);
|
||||
g.setColor(Color.black);
|
||||
double points[] = new double[6];
|
||||
double lastX = 0;
|
||||
double lastY = 0;
|
||||
double startX = 0;
|
||||
double startY = 0;
|
||||
GeneralPath path=new GeneralPath();
|
||||
for (PathIterator it = shp.getPathIterator(null); !it.isDone(); it.next()) {
|
||||
int type = it.currentSegment(points);
|
||||
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
|
||||
lastX = (points[0]);
|
||||
lastY = (points[1]);
|
||||
startX = lastX;
|
||||
startY = lastY;
|
||||
path.moveTo(lastX, lastY);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
//g2d.drawLine((int) lastX, (int) lastY, (int) points[0], (int) points[1]);
|
||||
lastX = (points[0]);
|
||||
lastY = (points[1]);
|
||||
path.lineTo(lastX, lastY);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
throw new RuntimeException("NOCUBIC");
|
||||
case PathIterator.SEG_QUADTO:
|
||||
//g2d.draw(new QuadCurve2D.Double(lastX, lastY, points[0], points[1], points[2], points[3]));
|
||||
path.quadTo(points[0], points[1], points[2], points[3]);
|
||||
lastX = (points[2]);
|
||||
lastY = (points[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE: //Closing line back to last SEG_MOVETO
|
||||
if ((startX == lastX) && (startY == lastY)) {
|
||||
break;
|
||||
}
|
||||
//g2d.drawLine((int) lastX, (int) lastY, (int) points[0], (int) points[1]);
|
||||
path.lineTo(startX, startY);
|
||||
lastX = startX;
|
||||
lastY = startY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g2d.draw(path);
|
||||
}
|
||||
});
|
||||
setDefaultCloseOperation(HIDE_ON_CLOSE);
|
||||
setSize(500, 500);
|
||||
super.setVisible(b);
|
||||
}
|
||||
}.setVisible(true);
|
||||
}
|
||||
});
|
||||
if (true) {
|
||||
return;
|
||||
}//*/
|
||||
if ((Boolean) Configuration.getConfig("cacheOnDisk", Boolean.TRUE)) {
|
||||
Cache.setStorageType(Cache.STORAGE_FILES);
|
||||
} else {
|
||||
@@ -1234,7 +1348,7 @@ public class Main {
|
||||
if ((!exists) && add) { //add
|
||||
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec");
|
||||
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec", "", "Open with FFDec");
|
||||
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec\\command");
|
||||
Advapi32Util.registryCreateKey(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec\\ ");
|
||||
Advapi32Util.registrySetStringValue(REG_CLASSES_HKEY, REG_CLASSES_PATH + clsName + "\\shell\\ffdec\\command", "", "\"" + appDir + exeName + "\" \"%1\"");
|
||||
}
|
||||
if (exists && (!add)) { //remove
|
||||
|
||||
@@ -82,6 +82,7 @@ import com.jpexs.decompiler.flash.tags.base.Container;
|
||||
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
@@ -122,6 +123,8 @@ import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentAdapter;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
@@ -139,6 +142,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
@@ -276,6 +280,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
private ErrorLogFrame errorLogFrame;
|
||||
private ComponentListener fontChangeList;
|
||||
private JComboBox<String> fontSelection;
|
||||
private Map<Integer, String> sourceFontsMap = new HashMap<>();
|
||||
private AbortRetryIgnoreHandler errorHandler = new AbortRetryIgnoreHandler() {
|
||||
@Override
|
||||
public int handle(Throwable thrown) {
|
||||
@@ -1162,6 +1167,15 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
fontSelection.setSelectedIndex(0);
|
||||
fontSelection.setSelectedItem("Times New Roman");
|
||||
fontSelection.setSelectedItem("Arial");
|
||||
fontSelection.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent e) {
|
||||
if (oldValue instanceof FontTag) {
|
||||
FontTag f = (FontTag) oldValue;
|
||||
sourceFontsMap.put(f.getFontId(), (String) fontSelection.getSelectedItem());
|
||||
}
|
||||
}
|
||||
});
|
||||
fontSelectionPanel.add(fontSelection);
|
||||
|
||||
JPanel fontCharPanel = new JPanel();
|
||||
@@ -2147,6 +2161,18 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
if (oldValue instanceof FontTag) {
|
||||
FontTag f = (FontTag) oldValue;
|
||||
String oldchars = f.getCharacters(swf.tags);
|
||||
|
||||
for (int i = 0; i < newchars.length(); i++) {
|
||||
char c = newchars.charAt(i);
|
||||
if (oldchars.indexOf((int) c) == -1) {
|
||||
Font font=new Font(fontSelection.getSelectedItem().toString(),f.getFontStyle(),1024);
|
||||
if(!font.canDisplay(c)){
|
||||
JOptionPane.showMessageDialog(null, translate("error.font.nocharacter").replace("%char%", ""+c), translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < newchars.length(); i++) {
|
||||
char c = newchars.charAt(i);
|
||||
if (oldchars.indexOf((int) c) == -1) {
|
||||
@@ -2331,8 +2357,35 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
case "SAVETEXT":
|
||||
if (oldValue instanceof TextTag) {
|
||||
try {
|
||||
((TextTag) oldValue).setFormattedText(swf.tags, textValue.getText(), fontSelection.getSelectedItem().toString());
|
||||
setEditText(false);
|
||||
if (((TextTag) oldValue).setFormattedText(new MissingCharacterHandler() {
|
||||
@Override
|
||||
public boolean handle(FontTag font, List<Tag> tags, char character) {
|
||||
String fontName = sourceFontsMap.get(font.getFontId());
|
||||
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);
|
||||
}
|
||||
Font f = new Font(fontName, font.getFontStyle(), 18);
|
||||
if (!f.canDisplay(character)) {
|
||||
JOptionPane.showMessageDialog(null, translate("error.font.nocharacter").replace("%char%", ""+character), translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
return false;
|
||||
}
|
||||
font.addCharacter(tags, character, fontName);
|
||||
return true;
|
||||
|
||||
}
|
||||
}, swf.tags, textValue.getText(), fontSelection.getSelectedItem().toString())) {
|
||||
setEditText(false);
|
||||
}
|
||||
} catch (ParseException ex) {
|
||||
JOptionPane.showMessageDialog(null, translate("error.text.invalid").replace("%text%", ex.text).replace("%line%", "" + ex.line), translate("error"), JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
@@ -3026,10 +3079,14 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
|
||||
fontLeadingLabel.setText(ft.getLeading() == -1 ? translate("value.unknown") : "" + ft.getLeading());
|
||||
String chars = ft.getCharacters(swf.tags);
|
||||
fontCharactersTextArea.setText(chars);
|
||||
fontSelection.setSelectedIndex(0);
|
||||
fontSelection.setSelectedItem("Times New Roman");
|
||||
fontSelection.setSelectedItem("Arial");
|
||||
fontSelection.setSelectedItem(ft.getFontName(swf.tags));
|
||||
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));
|
||||
}
|
||||
fontChangeList.componentResized(null);
|
||||
showDetailWithPreview(CARDFONTPANEL);
|
||||
} else {
|
||||
|
||||
@@ -331,4 +331,6 @@ menu.general = General
|
||||
menu.language = Language
|
||||
|
||||
startup.welcometo = Welcome to
|
||||
startup.selectopen = Click open icon on the top panel or drag SWF file to this window to start.
|
||||
startup.selectopen = Click open icon on the top panel or drag SWF file to this window to start.
|
||||
|
||||
error.font.nocharacter = Selected source font does not contain character "%char%".
|
||||
@@ -329,4 +329,6 @@ menu.general = Hlavn\u00ed
|
||||
menu.language = Jazyk
|
||||
|
||||
startup.welcometo = V\u00edtejte v programu
|
||||
startup.selectopen = Pro za\u010d\u00e1tek klikn\u011bte na otev\u0159\u00edt v horn\u00edm panelu nebo p\u0159et\u00e1hn\u011bte SWF soubor p\u0159\u00edmo do tohoto okna.
|
||||
startup.selectopen = Pro za\u010d\u00e1tek klikn\u011bte na otev\u0159\u00edt v horn\u00edm panelu nebo p\u0159et\u00e1hn\u011bte SWF soubor p\u0159\u00edmo do tohoto okna.
|
||||
|
||||
error.font.nocharacter = Vybran\u00e9 zdrojov\u00e9 p\u00edsmo neobsahuje znak "%char%".
|
||||
@@ -21,6 +21,7 @@ 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;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
|
||||
@@ -163,7 +164,7 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFormattedText(List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
public boolean setFormattedText(MissingCharacterHandler missingCharHandler, List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
try {
|
||||
TextLexer lexer = new TextLexer(new InputStreamReader(new ByteArrayInputStream(text.getBytes("UTF-8")), "UTF-8"));
|
||||
ParsedSymbol s = null;
|
||||
@@ -336,6 +337,7 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT
|
||||
}
|
||||
}
|
||||
|
||||
this.bounds = bounds;
|
||||
if (text.length() > 0) {
|
||||
initialText = text;
|
||||
this.hasText = true;
|
||||
@@ -384,8 +386,9 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT
|
||||
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(DefineEditTextTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -464,6 +467,7 @@ public class DefineEditTextTag extends CharacterTag implements BoundedTag, TextT
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
* @param data Data bytes
|
||||
* @param version SWF version
|
||||
* @param pos
|
||||
|
||||
@@ -26,6 +26,7 @@ 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;
|
||||
@@ -313,13 +314,28 @@ public class DefineFont2Tag extends FontTag {
|
||||
int fontStyle = getFontStyle();
|
||||
|
||||
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fontName, fontStyle, getDivider() * 1024, character);
|
||||
glyphShapeTable.add(shp);
|
||||
codeTable.add((int) character);
|
||||
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
for (int i = 0; i < codeTable.size(); i++) {
|
||||
if (codeTable.get(i) > code) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == -1) {
|
||||
pos = codeTable.size();
|
||||
}
|
||||
|
||||
FontTag.shiftGlyphIndices(fontId, pos, tags);
|
||||
|
||||
glyphShapeTable.add(pos, shp);
|
||||
codeTable.add(pos, (int) character);
|
||||
|
||||
if (fontFlagsHasLayout) {
|
||||
fontBoundsTable.add(shp.getBounds());
|
||||
fontBoundsTable.add(pos, shp.getBounds());
|
||||
Font fnt = new Font(fontName, fontStyle, getDivider() * 1024);
|
||||
fontAdvanceTable.add((new JPanel()).getFontMetrics(fnt).charWidth(character));
|
||||
fontAdvanceTable.add(pos, (int) Math.round(fnt.createGlyphVector((new JPanel()).getFontMetrics(fnt).getFontRenderContext(), "" + character).getGlyphMetrics(0).getAdvanceX()));
|
||||
}
|
||||
numGlyphs++;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,11 @@ 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 {
|
||||
@@ -301,14 +304,39 @@ public class DefineFont3Tag extends FontTag {
|
||||
|
||||
@Override
|
||||
public void addCharacter(List<Tag> tags, char character, String fontName) {
|
||||
|
||||
//Font Align Zones will be removed as adding new character zones is not supported:-(
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
Tag t = tags.get(i);
|
||||
if (t instanceof DefineFontAlignZonesTag) {
|
||||
DefineFontAlignZonesTag fa = (DefineFontAlignZonesTag) t;
|
||||
if (fa.fontID == fontId) {
|
||||
tags.remove(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
int fontStyle = getFontStyle();
|
||||
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fontName, fontStyle, getDivider() * 1024, character);
|
||||
glyphShapeTable.add(shp);
|
||||
codeTable.add((int) character);
|
||||
int code = (int) character;
|
||||
int pos = -1;
|
||||
for (int i = 0; i < codeTable.size(); i++) {
|
||||
if (codeTable.get(i) > code) {
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == -1) {
|
||||
pos = codeTable.size();
|
||||
}
|
||||
|
||||
FontTag.shiftGlyphIndices(fontId, pos, tags);
|
||||
glyphShapeTable.add(pos, shp);
|
||||
codeTable.add(pos, (int) character);
|
||||
if (fontFlagsHasLayout) {
|
||||
fontBoundsTable.add(shp.getBounds());
|
||||
fontBoundsTable.add(pos, shp.getBounds());
|
||||
Font fnt = new Font(fontName, fontStyle, getDivider() * 1024);
|
||||
fontAdvanceTable.add((new JPanel()).getFontMetrics(fnt).charWidth(character));
|
||||
fontAdvanceTable.add(pos, (int) Math.round(fnt.createGlyphVector((new JPanel()).getFontMetrics(fnt).getFontRenderContext(), "" + character).getGlyphMetrics(0).getAdvanceX()));
|
||||
}
|
||||
numGlyphs++;
|
||||
}
|
||||
|
||||
@@ -225,14 +225,30 @@ public class DefineFontTag extends FontTag {
|
||||
|
||||
@Override
|
||||
public void addCharacter(List<Tag> tags, char character, String fontName) {
|
||||
glyphShapeTable.add(SHAPERECORD.systemFontCharacterToSHAPE(fontName, getFontStyle(), getDivider() * 1024, character));
|
||||
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fontName, getFontStyle(), getDivider() * 1024, character);
|
||||
List<Integer> codeTable=new ArrayList<>();
|
||||
ensureFontInfo(tags);
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.codeTable.add((int) character);
|
||||
codeTable =fontInfoTag.codeTable;
|
||||
}
|
||||
if (fontInfo2Tag != null) {
|
||||
fontInfo2Tag.codeTable.add((int) character);
|
||||
codeTable =fontInfo2Tag.codeTable;
|
||||
}
|
||||
int code=(int)character;
|
||||
int pos=-1;
|
||||
for(int i=0;i<codeTable.size();i++){
|
||||
if(codeTable.get(i)>code){
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pos==-1){
|
||||
pos = codeTable.size();
|
||||
}
|
||||
FontTag.shiftGlyphIndices(fontId, pos, tags);
|
||||
glyphShapeTable.add(pos,shp);
|
||||
codeTable.add(pos,(int)character);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,6 +24,7 @@ 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;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
|
||||
@@ -164,7 +165,7 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFormattedText(List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
public boolean setFormattedText(MissingCharacterHandler missingCharHandler,List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
try {
|
||||
TextLexer lexer = new TextLexer(new InputStreamReader(new ByteArrayInputStream(text.getBytes("UTF-8")), "UTF-8"));
|
||||
ParsedSymbol s = null;
|
||||
@@ -336,12 +337,12 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
char c = txt.charAt(i);
|
||||
tr.glyphEntries[i] = new GLYPHENTRY();
|
||||
if (!font.containsChar(tags, c)) {
|
||||
font.addCharacter(tags, c, fontName);
|
||||
if(!missingCharHandler.handle(font, tags, c)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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());
|
||||
}*/
|
||||
@@ -381,7 +382,9 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(DefineText2Tag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -423,6 +426,7 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param swf
|
||||
* @param data Data bytes
|
||||
* @param version SWF version
|
||||
* @param pos
|
||||
|
||||
@@ -24,6 +24,7 @@ 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;
|
||||
import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParsedSymbol;
|
||||
@@ -164,7 +165,7 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFormattedText(List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
public boolean setFormattedText(MissingCharacterHandler missingCharHandler,List<Tag> tags, String text, String fontName) throws ParseException {
|
||||
try {
|
||||
TextLexer lexer = new TextLexer(new InputStreamReader(new ByteArrayInputStream(text.getBytes("UTF-8")), "UTF-8"));
|
||||
ParsedSymbol s = null;
|
||||
@@ -335,7 +336,9 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
char c = txt.charAt(i);
|
||||
tr.glyphEntries[i] = new GLYPHENTRY();
|
||||
if (!font.containsChar(tags, c)) {
|
||||
font.addCharacter(tags, c, fontName);
|
||||
if(!missingCharHandler.handle(font, tags, c)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
tr.glyphEntries[i].glyphIndex = font.charToGlyph(tags, c);
|
||||
|
||||
@@ -381,7 +384,9 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
Logger.getLogger(DefineTextTag.class.getName()).log(Level.SEVERE, null, ex);
|
||||
} catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -17,9 +17,14 @@
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
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.GLYPHENTRY;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import java.awt.Font;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -94,4 +99,30 @@ public abstract class FontTag extends CharacterTag implements AloneTag {
|
||||
}
|
||||
return name + " (" + getCharacterId() + nameAppend + ")";
|
||||
}
|
||||
|
||||
public static void shiftGlyphIndices(int fontId,int startIndex, List<Tag> tags) {
|
||||
List<TEXTRECORD> textRecords = new ArrayList<>();
|
||||
for (Tag t : tags) {
|
||||
if (t instanceof DefineTextTag) {
|
||||
textRecords.addAll(((DefineTextTag) t).textRecords);
|
||||
}
|
||||
if (t instanceof DefineText2Tag) {
|
||||
textRecords.addAll(((DefineTextTag) t).textRecords);
|
||||
}
|
||||
}
|
||||
int curFontId=0;
|
||||
for (TEXTRECORD tr : textRecords) {
|
||||
if(tr.styleFlagsHasFont){
|
||||
curFontId = tr.fontId;
|
||||
}
|
||||
if(curFontId!=fontId){
|
||||
continue;
|
||||
}
|
||||
for (GLYPHENTRY en : tr.glyphEntries) {
|
||||
if (en.glyphIndex >= startIndex) {
|
||||
en.glyphIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2013 JPEXS
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class MissingCharacterHandler {
|
||||
protected static List<String> fontNames = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
|
||||
|
||||
public boolean handle(FontTag font,List<Tag> tags,char character){
|
||||
String fontName = font.getFontName(tags);
|
||||
if(!fontNames.contains(fontName)){
|
||||
return false;
|
||||
}
|
||||
Font f=new Font(fontName,font.getFontStyle(),18);
|
||||
if(!f.canDisplay(character)){
|
||||
return false;
|
||||
}
|
||||
font.addCharacter(tags, character, fontName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public interface TextTag {
|
||||
|
||||
public String getFormattedText(List<Tag> tags);
|
||||
|
||||
public void setFormattedText(List<Tag> tags, String text, String fontName) throws ParseException;
|
||||
public boolean setFormattedText(MissingCharacterHandler missingCharHandler,List<Tag> tags, String text, String fontName) throws ParseException;
|
||||
|
||||
public int getCharacterId();
|
||||
|
||||
|
||||
@@ -16,6 +16,14 @@
|
||||
*/
|
||||
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
|
||||
*
|
||||
@@ -26,7 +34,7 @@ public class ZONERECORD {
|
||||
public ZONEDATA zonedata[] = new ZONEDATA[0];
|
||||
public boolean zoneMaskX;
|
||||
public boolean zoneMaskY;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String ret = "[ZONERECORD data:";
|
||||
|
||||
@@ -35,6 +35,7 @@ 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;
|
||||
@@ -48,8 +49,10 @@ 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;
|
||||
@@ -60,6 +63,7 @@ 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;
|
||||
|
||||
/**
|
||||
@@ -366,7 +370,7 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
GeneralPath ret = new GeneralPath();
|
||||
int x = startX;
|
||||
int y = startY;
|
||||
boolean wasMoveTo = false;
|
||||
boolean wasMoveTo = false;
|
||||
for (SHAPERECORD rec : edges) {
|
||||
int nx = rec.changeX(x);
|
||||
int ny = rec.changeY(y);
|
||||
@@ -870,7 +874,12 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
}
|
||||
private static List<String> existingFonts = Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
|
||||
|
||||
public static SHAPE systemFontCharacterToSHAPE(String fontName, int fontStyle, int fontSize, char character) {
|
||||
public static SHAPE systemFontCharacterToSHAPE(final String fontName, final int fontStyle, int fontSize, char character) {
|
||||
int multiplier = 1;
|
||||
if(fontSize>1024){
|
||||
multiplier = fontSize/1024;
|
||||
fontSize = 1024;
|
||||
}
|
||||
List<SHAPERECORD> retList = new ArrayList<>();
|
||||
String defaultFonts[] = new String[]{"Times New Roman", "Arial"};
|
||||
Font f = null;
|
||||
@@ -887,7 +896,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
if (f == null) {
|
||||
f = new Font("Dialog", fontStyle, fontSize); //Fallback to DIALOG
|
||||
}
|
||||
|
||||
GlyphVector v = f.createGlyphVector((new JPanel()).getFontMetrics(f).getFontRenderContext(), "" + character);
|
||||
Shape shp = v.getOutline();
|
||||
double points[] = new double[6];
|
||||
@@ -896,13 +904,13 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
int startX = 0;
|
||||
int startY = 0;
|
||||
for (PathIterator it = shp.getPathIterator(null); !it.isDone(); it.next()) {
|
||||
int type = it.currentSegment(points);
|
||||
int type = it.currentSegment(points);
|
||||
switch (type) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
scr.stateMoveTo = true;
|
||||
scr.moveDeltaX = (int) Math.round(points[0]);
|
||||
scr.moveDeltaY = (int) Math.round(points[1]);
|
||||
scr.moveDeltaX = multiplier*(int) Math.round(points[0]);
|
||||
scr.moveDeltaY = multiplier*(int) Math.round(points[1]);
|
||||
scr.moveBits = SWFOutputStream.getNeededBitsS(scr.moveDeltaX, scr.moveDeltaY);
|
||||
retList.add(scr);
|
||||
lastX = (int) Math.round(points[0]);
|
||||
@@ -911,10 +919,14 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
startY = lastY;
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.generalLineFlag = true;
|
||||
ser.deltaX = ((int) Math.round(points[0])) - lastX;
|
||||
ser.deltaY = ((int) Math.round(points[1])) - lastY;
|
||||
StraightEdgeRecord ser = new StraightEdgeRecord();
|
||||
ser.deltaX = multiplier*(((int) Math.round(points[0])) - lastX);
|
||||
ser.deltaY = multiplier*(((int) Math.round(points[1])) - lastY);
|
||||
|
||||
ser.generalLineFlag = ser.deltaX!=0 && ser.deltaY!=0;
|
||||
if(ser.deltaX == 0){
|
||||
ser.vertLineFlag = true;
|
||||
}
|
||||
ser.numBits = SWFOutputStream.getNeededBitsS(ser.deltaX, ser.deltaY) - 2;
|
||||
if (ser.numBits < 0) {
|
||||
ser.numBits = 0;
|
||||
@@ -933,11 +945,11 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
double quadCoords[][] = approximateCubic(cubicCoords);
|
||||
for (int i = 0; i < quadCoords.length; i++) {
|
||||
CurvedEdgeRecord cer = new CurvedEdgeRecord();
|
||||
cer.controlDeltaX = ((int) Math.round(quadCoords[i][0])) - lastX;
|
||||
cer.controlDeltaY = ((int) Math.round(quadCoords[i][1])) - lastY;
|
||||
cer.anchorDeltaX = ((int) Math.round(quadCoords[i][2])) - ((int) Math.round(quadCoords[i][0]));
|
||||
cer.anchorDeltaY = ((int) Math.round(quadCoords[i][3])) - ((int) Math.round(quadCoords[i][1]));
|
||||
cer.numBits = SWFOutputStream.getNeededBitsS(cer.controlDeltaX, cer.controlDeltaY, cer.anchorDeltaX, cer.anchorDeltaY) - 2;
|
||||
cer.controlDeltaX = multiplier*(((int) Math.round(quadCoords[i][0])) - lastX);
|
||||
cer.controlDeltaY = multiplier*(((int) Math.round(quadCoords[i][1])) - lastY);
|
||||
cer.anchorDeltaX = multiplier*(((int) Math.round(quadCoords[i][2])) - ((int) Math.round(quadCoords[i][0])));
|
||||
cer.anchorDeltaY = multiplier*(((int) Math.round(quadCoords[i][3])) - ((int) Math.round(quadCoords[i][1])));
|
||||
cer.numBits = SWFOutputStream.getNeededBitsS(cer.controlDeltaX, cer.controlDeltaY, cer.anchorDeltaX, cer.anchorDeltaY) - 2;
|
||||
if (cer.numBits < 0) {
|
||||
cer.numBits = 0;
|
||||
}
|
||||
@@ -948,17 +960,17 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
CurvedEdgeRecord cer = new CurvedEdgeRecord();
|
||||
cer.controlDeltaX = ((int) Math.round(points[0])) - lastX;
|
||||
cer.controlDeltaY = ((int) Math.round(points[1])) - lastY;
|
||||
cer.anchorDeltaX = ((int) Math.round(points[2])) - (int) Math.round(points[0]);
|
||||
cer.anchorDeltaY = ((int) Math.round(points[3])) - (int) Math.round(points[1]);
|
||||
cer.controlDeltaX = multiplier*(((int) Math.round(points[0])) - lastX);
|
||||
cer.controlDeltaY = multiplier*(((int) Math.round(points[1])) - lastY);
|
||||
cer.anchorDeltaX = multiplier*(((int) Math.round(points[2])) - (int) Math.round(points[0]));
|
||||
cer.anchorDeltaY = multiplier*(((int) Math.round(points[3])) - (int) Math.round(points[1]));
|
||||
cer.numBits = SWFOutputStream.getNeededBitsS(cer.controlDeltaX, cer.controlDeltaY, cer.anchorDeltaX, cer.anchorDeltaY) - 2;
|
||||
if (cer.numBits < 0) {
|
||||
cer.numBits = 0;
|
||||
}
|
||||
retList.add(cer);
|
||||
retList.add(cer);
|
||||
lastX = (int) Math.round(points[2]);
|
||||
lastY = (int) Math.round(points[3]);
|
||||
lastY = (int) Math.round(points[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE: //Closing line back to last SEG_MOVETO
|
||||
if ((startX == lastX) && (startY == lastY)) {
|
||||
@@ -966,8 +978,8 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
}
|
||||
StraightEdgeRecord closeSer = new StraightEdgeRecord();
|
||||
closeSer.generalLineFlag = true;
|
||||
closeSer.deltaX = (int) Math.round((startX - lastX));
|
||||
closeSer.deltaY = (int) Math.round((startY - lastY));
|
||||
closeSer.deltaX = multiplier*((int) Math.round((startX - lastX)));
|
||||
closeSer.deltaY = multiplier*((int) Math.round((startY - lastY)));
|
||||
closeSer.numBits = SWFOutputStream.getNeededBitsS(closeSer.deltaX, closeSer.deltaY) - 2;
|
||||
if (closeSer.numBits < 0) {
|
||||
closeSer.numBits = 0;
|
||||
|
||||
Reference in New Issue
Block a user