mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-05-31 11:24:51 +00:00
@@ -431,9 +431,6 @@ public class SWFOutputStream extends OutputStream {
|
||||
* @return Number of bits
|
||||
*/
|
||||
public static int getNeededBitsS(int v) {
|
||||
/*if (v == 0) {
|
||||
//return 0;
|
||||
}*/
|
||||
int counter = 32;
|
||||
int mask = 0x80000000;
|
||||
final int val = (v < 0) ? -v : v;
|
||||
@@ -444,6 +441,22 @@ public class SWFOutputStream extends OutputStream {
|
||||
return counter + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates number of bits needed for representing signed values
|
||||
*
|
||||
* @param first First Signed value
|
||||
* @param params Next Signed values
|
||||
* @return Number of bits
|
||||
*/
|
||||
public static int getNeededBitsS(int first, int... params) {
|
||||
int nBits = 0;
|
||||
nBits = enlargeBitCountS(nBits, first);
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
nBits = enlargeBitCountS(nBits, params[i]);
|
||||
}
|
||||
return nBits;
|
||||
}
|
||||
|
||||
private static long getIntPart(double value) {
|
||||
if (value < 0) {
|
||||
return (long) Math.ceil(value);
|
||||
@@ -478,7 +491,7 @@ public class SWFOutputStream extends OutputStream {
|
||||
return getNeededBitsS(k) + 16;
|
||||
}
|
||||
|
||||
private int enlargeBitCountS(int currentBitCount, int value) {
|
||||
private static int enlargeBitCountS(int currentBitCount, int value) {
|
||||
int neededNew = getNeededBitsS(value);
|
||||
if (neededNew > currentBitCount) {
|
||||
return neededNew;
|
||||
|
||||
@@ -55,7 +55,6 @@ import com.jpexs.decompiler.flash.abc.types.traits.Trait;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.TraitSlotConst;
|
||||
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
|
||||
import com.jpexs.decompiler.flash.ecma.EcmaScript;
|
||||
import com.jpexs.decompiler.flash.graph.DuplicateItem;
|
||||
import com.jpexs.decompiler.flash.graph.Graph;
|
||||
import com.jpexs.decompiler.flash.graph.GraphPart;
|
||||
import com.jpexs.decompiler.flash.graph.GraphSourceItem;
|
||||
|
||||
@@ -25,7 +25,6 @@ import com.jpexs.decompiler.flash.graph.ContinueItem;
|
||||
import com.jpexs.decompiler.flash.graph.GraphTargetItem;
|
||||
import com.jpexs.decompiler.flash.helpers.Helper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ClassTreeItem extends TreeItem implements Block {
|
||||
|
||||
@@ -76,14 +76,12 @@ import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ASMSource;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterIdTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
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.PlaceObjectTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.RemoveTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.TextTag;
|
||||
import com.jpexs.decompiler.flash.tags.text.ParseException;
|
||||
@@ -132,9 +130,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
@@ -205,6 +201,7 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
final static String DETAILCARDAS3NAVIGATOR = "Traits list";
|
||||
final static String DETAILCARDEMPTYPANEL = "Empty card";
|
||||
final static String CARDTEXTPANEL = "Text card";
|
||||
final static String CARDFONTPANEL = "Font card";
|
||||
private LineMarkedEditorPane textValue;
|
||||
private JPEGTablesTag jtt;
|
||||
private HashMap<Integer, CharacterTag> characters;
|
||||
@@ -230,6 +227,14 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
private JCheckBoxMenuItem miDecompile;
|
||||
private JCheckBoxMenuItem miCacheDisk;
|
||||
private JCheckBoxMenuItem miGotoMainClassOnStartup;
|
||||
private JLabel fontNameLabel;
|
||||
private JLabel fontIsBoldLabel;
|
||||
private JLabel fontIsItalicLabel;
|
||||
private JLabel fontAscentLabel;
|
||||
private JLabel fontDescentLabel;
|
||||
private JLabel fontLeadingLabel;
|
||||
private JLabel fontCharactersLabel;
|
||||
private JTextField fontAddCharactersField;
|
||||
|
||||
public void setPercent(int percent) {
|
||||
progressBar.setValue(percent);
|
||||
@@ -777,8 +782,8 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
|
||||
|
||||
|
||||
JPanel buttonsPanel = new JPanel();
|
||||
buttonsPanel.setLayout(new FlowLayout());
|
||||
JPanel textButtonsPanel = new JPanel();
|
||||
textButtonsPanel.setLayout(new FlowLayout());
|
||||
|
||||
|
||||
textSaveButton = new JButton(translate("button.save"), View.getIcon("save16"));
|
||||
@@ -796,26 +801,65 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
textCancelButton.setActionCommand("CANCELTEXT");
|
||||
textCancelButton.addActionListener(this);
|
||||
|
||||
buttonsPanel.add(textEditButton);
|
||||
buttonsPanel.add(textSaveButton);
|
||||
buttonsPanel.add(textCancelButton);
|
||||
textButtonsPanel.add(textEditButton);
|
||||
textButtonsPanel.add(textSaveButton);
|
||||
textButtonsPanel.add(textCancelButton);
|
||||
|
||||
textSaveButton.setVisible(false);
|
||||
textCancelButton.setVisible(false);
|
||||
|
||||
textTopPanel.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
textTopPanel.add(textButtonsPanel, BorderLayout.SOUTH);
|
||||
|
||||
displayWithPreview = new JPanel(new CardLayout());
|
||||
|
||||
displayWithPreview.add(textTopPanel, CARDTEXTPANEL);
|
||||
|
||||
JPanel textPanel = new JPanel();
|
||||
textPanel.setLayout(new BoxLayout(textPanel, BoxLayout.Y_AXIS));
|
||||
textPanel.add(textTopPanel);
|
||||
//textPanel.add(textBottomPanel);
|
||||
|
||||
displayWithPreview.add(textPanel, CARDTEXTPANEL);
|
||||
//displayWithPreview.setVisible(false);
|
||||
JPanel fontPanel = new JPanel();
|
||||
JPanel fontParams2 = new JPanel();
|
||||
fontParams2.setLayout(null);
|
||||
Component ctable[][] = new Component[][]{
|
||||
{new JLabel(translate("font.name")), fontNameLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.isbold")), fontIsBoldLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.isitalic")), fontIsItalicLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.ascent")), fontAscentLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.descent")), fontDescentLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.leading")), fontLeadingLabel = new JLabel(translate("value.unknown"))},
|
||||
{new JLabel(translate("font.characters")), fontCharactersLabel = new JLabel("")}
|
||||
};
|
||||
|
||||
int headerWidth = 100;
|
||||
int borderLeft = 10;
|
||||
|
||||
for (int i = 0; i < ctable.length; i++) {
|
||||
ctable[i][0].setBounds(borderLeft, 25 * i, headerWidth, 25);
|
||||
ctable[i][1].setBounds(borderLeft + headerWidth + borderLeft, 25 * i, 400, 25);
|
||||
fontParams2.add(ctable[i][0]);
|
||||
fontParams2.add(ctable[i][1]);
|
||||
}
|
||||
fontParams2.setPreferredSize(new Dimension(600, ctable.length * 25));
|
||||
|
||||
|
||||
JPanel fontParams1 = new JPanel();
|
||||
|
||||
fontParams1.setLayout(new BoxLayout(fontParams1, BoxLayout.Y_AXIS));
|
||||
fontParams1.add(fontParams2);
|
||||
|
||||
JPanel fontAddCharsPanel = new JPanel(new FlowLayout());
|
||||
fontAddCharsPanel.add(new JLabel(translate("font.characters.add")));
|
||||
fontAddCharactersField = new JTextField();
|
||||
fontAddCharactersField.setPreferredSize(new Dimension(100, 25));
|
||||
fontAddCharsPanel.add(fontAddCharactersField);
|
||||
JButton fontAddCharsButton = new JButton(translate("button.ok"));
|
||||
fontAddCharsButton.setActionCommand("FONTADDCHARS");
|
||||
fontAddCharsButton.addActionListener(this);
|
||||
fontAddCharsPanel.add(fontAddCharsButton);
|
||||
|
||||
fontParams1.add(fontAddCharsPanel);
|
||||
fontPanel.setLayout(new BorderLayout());
|
||||
fontPanel.add(fontParams1, BorderLayout.NORTH);
|
||||
|
||||
displayWithPreview.add(fontPanel, CARDFONTPANEL);
|
||||
|
||||
|
||||
Component leftComponent = null;
|
||||
@@ -1618,6 +1662,21 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
switch (e.getActionCommand()) {
|
||||
case "FONTADDCHARS":
|
||||
String newchars = fontAddCharactersField.getText();
|
||||
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) {
|
||||
f.addCharacter(swf.tags, c);
|
||||
}
|
||||
}
|
||||
fontAddCharactersField.setText("");
|
||||
reload(true);
|
||||
}
|
||||
break;
|
||||
case "GOTODOCUMENTCLASSONSTARTUP":
|
||||
Configuration.setConfig("gotoMainClassOnStartup", miGotoMainClassOnStartup.isSelected());
|
||||
break;
|
||||
@@ -2276,7 +2335,7 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
imagePanel.setImage(((ImageTag) tagObj).getImage(swf.tags));
|
||||
} else if ((tagObj instanceof DrawableTag) && (!(tagObj instanceof TextTag)) && (miInternalViewer.isSelected())) {
|
||||
showCard(CARDDRAWPREVIEWPANEL);
|
||||
previewImagePanel.setDrawable((DrawableTag) tagObj, swf, characters);//.setImage(((DrawableTag) tagObj).toImage(1, swf.tags, swf.displayRect, characters));
|
||||
previewImagePanel.setDrawable((DrawableTag) tagObj, swf, characters);
|
||||
} else if (tagObj instanceof FrameNode && ((FrameNode) tagObj).isDisplayed() && (miInternalViewer.isSelected())) {
|
||||
showCard(CARDDRAWPREVIEWPANEL);
|
||||
FrameNode fn = (FrameNode) tagObj;
|
||||
@@ -2410,7 +2469,7 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
}
|
||||
if (tagObj instanceof FontTag) {
|
||||
|
||||
int countGlyphs = ((FontTag) tagObj).getGlyphShapeTable().length;
|
||||
int countGlyphs = ((FontTag) tagObj).getGlyphShapeTable().size();
|
||||
int fontId = ((FontTag) tagObj).getFontId();
|
||||
int sloupcu = (int) Math.ceil(Math.sqrt(countGlyphs));
|
||||
int radku = (int) Math.ceil(((float) countGlyphs) / ((float) sloupcu));
|
||||
@@ -2477,6 +2536,18 @@ public class MainFrame extends AppFrame implements ActionListener, TreeSelection
|
||||
previewSplitPane.setDividerLocation(previewSplitPane.getWidth() / 2);
|
||||
showDetailWithPreview(CARDTEXTPANEL);
|
||||
textValue.setText(((TextTag) tagObj).getFormattedText(swf.tags));
|
||||
} else if (tagObj instanceof FontTag) {
|
||||
parametersPanel.setVisible(true);
|
||||
previewSplitPane.setDividerLocation(previewSplitPane.getWidth() / 2);
|
||||
FontTag ft = (FontTag) tagObj;
|
||||
fontNameLabel.setText(ft.getFontName(swf.tags));
|
||||
fontIsBoldLabel.setText(ft.isBold() ? translate("yes") : translate("no"));
|
||||
fontIsItalicLabel.setText(ft.isItalic() ? translate("yes") : translate("no"));
|
||||
fontDescentLabel.setText("" + ft.getDescent());
|
||||
fontAscentLabel.setText("" + ft.getDescent());
|
||||
fontLeadingLabel.setText("" + ft.getDescent());
|
||||
fontCharactersLabel.setText("" + ft.getCharacters(swf.tags));
|
||||
showDetailWithPreview(CARDFONTPANEL);
|
||||
} else {
|
||||
parametersPanel.setVisible(false);
|
||||
}
|
||||
|
||||
@@ -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.helpers.Helper;
|
||||
import com.jpexs.decompiler.flash.tags.base.AloneTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.types.BITMAPDATA;
|
||||
@@ -33,7 +32,6 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
@@ -18,24 +18,26 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LANGCODE;
|
||||
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.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
public class DefineFont2Tag extends FontTag {
|
||||
|
||||
public int fontId;
|
||||
public boolean fontFlagsHasLayout;
|
||||
@@ -49,14 +51,13 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
public LANGCODE languageCode;
|
||||
public String fontName;
|
||||
public int numGlyphs;
|
||||
public long offsetTable[];
|
||||
public SHAPE glyphShapeTable[];
|
||||
public List<SHAPE> glyphShapeTable;
|
||||
public List<Integer> codeTable;
|
||||
public int fontAscent;
|
||||
public int fontDescent;
|
||||
public int fontLeading;
|
||||
public int fontAdvanceTable[];
|
||||
public RECT fontBoundsTable[];
|
||||
public List<Integer> fontAdvanceTable;
|
||||
public List<RECT> fontBoundsTable;
|
||||
public KERNINGRECORD fontKerningTable[];
|
||||
public static final int ID = 48;
|
||||
|
||||
@@ -67,13 +68,13 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
|
||||
@Override
|
||||
public int getGlyphWidth(int glyphIndex) {
|
||||
return glyphShapeTable[glyphIndex].getBounds().getWidth();
|
||||
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphAdvance(int glyphIndex) {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontAdvanceTable[glyphIndex];
|
||||
return fontAdvanceTable.get(glyphIndex);
|
||||
} else {
|
||||
return getGlyphWidth(glyphIndex) + 20;
|
||||
}
|
||||
@@ -104,31 +105,31 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
sos.write(fontName.getBytes("utf-8"));
|
||||
sos.writeUI16(numGlyphs);
|
||||
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos2, version);
|
||||
List<Long> offsetTable = new ArrayList<>();
|
||||
ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream();
|
||||
|
||||
SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, version);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos());
|
||||
sos3.writeSHAPE(glyphShapeTable.get(i), 1);
|
||||
}
|
||||
byte baGlyphShapes[] = baosGlyphShapes.toByteArray();
|
||||
for (Long offset : offsetTable) {
|
||||
if (fontFlagsWideOffsets) {
|
||||
sos2.writeUI32(offsetTable[i]);
|
||||
sos.writeUI32(offset);
|
||||
} else {
|
||||
sos2.writeUI16((int) offsetTable[i]);
|
||||
sos.writeUI16((int) (long) offset);
|
||||
}
|
||||
}
|
||||
byte ba2[] = baos2.toByteArray();
|
||||
ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos3 = new SWFOutputStream(baos3, version);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos3.writeSHAPE(glyphShapeTable[i], 1);
|
||||
}
|
||||
byte ba3[] = baos3.toByteArray();
|
||||
sos.write(ba2);
|
||||
if (numGlyphs > 0) {
|
||||
long offset = ba2.length + ba3.length;
|
||||
long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length;
|
||||
if (fontFlagsWideOffsets) {
|
||||
sos.writeUI32(offset + 4);
|
||||
sos.writeUI32(offset);
|
||||
} else {
|
||||
sos.writeUI16((int) (offset + 2));
|
||||
sos.writeUI16((int) offset);
|
||||
}
|
||||
sos.write(ba3);
|
||||
sos.write(baGlyphShapes);
|
||||
|
||||
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
if (fontFlagsWideCodes) {
|
||||
@@ -143,10 +144,10 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
sos.writeSI16(fontDescent);
|
||||
sos.writeSI16(fontLeading);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos.writeSI16(fontAdvanceTable[i]);
|
||||
sos.writeSI16(fontAdvanceTable.get(i));
|
||||
}
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos.writeRECT(fontBoundsTable[i]);
|
||||
sos.writeRECT(fontBoundsTable.get(i));
|
||||
}
|
||||
sos.writeUI16(fontKerningTable.length);
|
||||
for (int k = 0; k < fontKerningTable.length; k++) {
|
||||
@@ -164,6 +165,7 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
*
|
||||
* @param data Data bytes
|
||||
* @param version SWF version
|
||||
* @param pos
|
||||
* @throws IOException
|
||||
*/
|
||||
public DefineFont2Tag(byte data[], int version, long pos) throws IOException {
|
||||
@@ -182,26 +184,25 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
int fontNameLen = sis.readUI8();
|
||||
fontName = new String(sis.readBytes(fontNameLen));
|
||||
numGlyphs = sis.readUI16();
|
||||
offsetTable = new long[numGlyphs];
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
//offsetTable = new long[numGlyphs];
|
||||
for (int i = 0; i < numGlyphs; i++) { //offsetTable
|
||||
if (fontFlagsWideOffsets) {
|
||||
offsetTable[i] = sis.readUI32();
|
||||
sis.readUI32();
|
||||
} else {
|
||||
offsetTable[i] = sis.readUI16();
|
||||
sis.readUI16();
|
||||
}
|
||||
}
|
||||
long codeTableOffset = 0;
|
||||
if (numGlyphs > 0) {
|
||||
if (numGlyphs > 0) { //codeTableOffset
|
||||
if (fontFlagsWideOffsets) {
|
||||
codeTableOffset = sis.readUI32();
|
||||
sis.readUI32();
|
||||
} else {
|
||||
codeTableOffset = sis.readUI16();
|
||||
sis.readUI16();
|
||||
}
|
||||
}
|
||||
|
||||
glyphShapeTable = new SHAPE[numGlyphs];
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
glyphShapeTable[i] = sis.readSHAPE(1);
|
||||
glyphShapeTable.add(sis.readSHAPE(1));
|
||||
}
|
||||
|
||||
codeTable = new ArrayList<>(); //[numGlyphs];
|
||||
@@ -216,13 +217,13 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
fontAscent = sis.readSI16();
|
||||
fontDescent = sis.readSI16();
|
||||
fontLeading = sis.readSI16();
|
||||
fontAdvanceTable = new int[numGlyphs];
|
||||
fontAdvanceTable = new ArrayList<>();
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
fontAdvanceTable[i] = sis.readSI16();
|
||||
fontAdvanceTable.add(sis.readSI16());
|
||||
}
|
||||
fontBoundsTable = new RECT[numGlyphs];
|
||||
fontBoundsTable = new ArrayList<>();
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
fontBoundsTable[i] = sis.readRECT();
|
||||
fontBoundsTable.add(sis.readRECT());
|
||||
}
|
||||
int kerningCount = sis.readUI16();
|
||||
fontKerningTable = new KERNINGRECORD[kerningCount];
|
||||
@@ -238,7 +239,7 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SHAPE[] getGlyphShapeTable() {
|
||||
public List<SHAPE> getGlyphShapeTable() {
|
||||
return glyphShapeTable;
|
||||
}
|
||||
|
||||
@@ -304,4 +305,28 @@ public class DefineFont2Tag extends CharacterTag implements FontTag {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(List<Tag> tags, char character) {
|
||||
int fontStyle = getFontStyle();
|
||||
String fname = getFontName(tags);
|
||||
|
||||
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fname, fontStyle, getDivider() * 1000, character);
|
||||
glyphShapeTable.add(shp);
|
||||
fontBoundsTable.add(shp.getBounds());
|
||||
codeTable.add((int) character);
|
||||
|
||||
Font fnt = new Font(fname, fontStyle, getDivider() * 1000);
|
||||
fontAdvanceTable.add((new JPanel()).getFontMetrics(fnt).charWidth(character));
|
||||
numGlyphs++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacters(List<Tag> tags) {
|
||||
String ret = "";
|
||||
for (int i : codeTable) {
|
||||
ret += (char) i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,20 +20,22 @@ import com.jpexs.decompiler.flash.Configuration;
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.abc.CopyOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
|
||||
import com.jpexs.decompiler.flash.types.LANGCODE;
|
||||
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.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
public class DefineFont3Tag extends FontTag {
|
||||
|
||||
public int fontId;
|
||||
public boolean fontFlagsHasLayout;
|
||||
@@ -47,14 +49,14 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
public LANGCODE languageCode;
|
||||
public String fontName;
|
||||
public int numGlyphs;
|
||||
public long offsetTable[];
|
||||
public SHAPE glyphShapeTable[];
|
||||
//public long offsetTable[];
|
||||
public List<SHAPE> glyphShapeTable;
|
||||
public List<Integer> codeTable;
|
||||
public int fontAscent;
|
||||
public int fontDescent;
|
||||
public int fontLeading;
|
||||
public int fontAdvanceTable[];
|
||||
public RECT fontBoundsTable[];
|
||||
public List<Integer> fontAdvanceTable;
|
||||
public List<RECT> fontBoundsTable;
|
||||
public KERNINGRECORD fontKerningTable[];
|
||||
public static final int ID = 75;
|
||||
|
||||
@@ -65,13 +67,13 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
|
||||
@Override
|
||||
public int getGlyphWidth(int glyphIndex) {
|
||||
return glyphShapeTable[glyphIndex].getBounds().getWidth() / 20;
|
||||
return glyphShapeTable.get(glyphIndex).getBounds().getWidth() / 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGlyphAdvance(int glyphIndex) {
|
||||
if (fontFlagsHasLayout) {
|
||||
return fontAdvanceTable[glyphIndex] / 20;
|
||||
return fontAdvanceTable.get(glyphIndex) / 20;
|
||||
} else {
|
||||
return getGlyphWidth(glyphIndex) + 20;
|
||||
}
|
||||
@@ -103,25 +105,37 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
int fontNameLen = sis.readUI8();
|
||||
fontName = new String(sis.readBytes(fontNameLen));
|
||||
numGlyphs = sis.readUI16();
|
||||
offsetTable = new long[numGlyphs];
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
for (int i = 0; i < numGlyphs; i++) { //offsetTable
|
||||
if (fontFlagsWideOffsets) {
|
||||
offsetTable[i] = sis.readUI32();
|
||||
sis.readUI32();
|
||||
} else {
|
||||
offsetTable[i] = sis.readUI16();
|
||||
sis.readUI16();
|
||||
}
|
||||
}
|
||||
long codeTableOffset = 0;
|
||||
if (numGlyphs > 0) {
|
||||
if (fontFlagsWideOffsets) {
|
||||
codeTableOffset = sis.readUI32();
|
||||
sis.readUI32(); //codeTableOffset
|
||||
} else {
|
||||
codeTableOffset = sis.readUI16();
|
||||
sis.readUI16(); //codeTableOffset
|
||||
}
|
||||
}
|
||||
glyphShapeTable = new SHAPE[numGlyphs];
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
SHAPE firstShape = null;
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
glyphShapeTable[i] = sis.readSHAPE(1);
|
||||
SHAPE shp = sis.readSHAPE(1);
|
||||
/*cnt++;
|
||||
if (cnt > 2) {
|
||||
shp = firstShape;
|
||||
SHAPE generated = SHAPERECORD.systemFontCharacterToSHAPE("Times New Roman", 0, 1000, 'A');
|
||||
shp = generated;
|
||||
} else {
|
||||
firstShape = shp;
|
||||
}*/
|
||||
glyphShapeTable.add(shp);
|
||||
//shp=SHAPERECORD.systemFontCharacterToSHAPE("Times New Roman", 0, 20000 /*??*/, 'A');
|
||||
|
||||
//glyphShapeTable.add(sis.readSHAPE(1));
|
||||
}
|
||||
codeTable = new ArrayList<>(); //int[numGlyphs];
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
@@ -135,13 +149,13 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
fontAscent = sis.readSI16();
|
||||
fontDescent = sis.readSI16();
|
||||
fontLeading = sis.readSI16();
|
||||
fontAdvanceTable = new int[numGlyphs];
|
||||
fontAdvanceTable = new ArrayList<>();
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
fontAdvanceTable[i] = sis.readSI16();
|
||||
fontAdvanceTable.add(sis.readSI16());
|
||||
}
|
||||
fontBoundsTable = new RECT[numGlyphs];
|
||||
fontBoundsTable = new ArrayList<>();
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
fontBoundsTable[i] = sis.readRECT();
|
||||
fontBoundsTable.add(sis.readRECT());
|
||||
}
|
||||
int kerningCount = sis.readUI16();
|
||||
fontKerningTable = new KERNINGRECORD[kerningCount];
|
||||
@@ -180,33 +194,30 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
sos.write(fontName.getBytes("utf-8"));
|
||||
sos.writeUI16(numGlyphs);
|
||||
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos2, version);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
if (fontFlagsWideOffsets) {
|
||||
sos2.writeUI32(offsetTable[i]);
|
||||
} else {
|
||||
sos2.writeUI16((int) offsetTable[i]);
|
||||
}
|
||||
}
|
||||
byte ba2[] = baos2.toByteArray();
|
||||
ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
|
||||
List<Long> offsetTable = new ArrayList<>();
|
||||
ByteArrayOutputStream baosGlyphShapes = new ByteArrayOutputStream();
|
||||
|
||||
SWFOutputStream sos3 = new SWFOutputStream(baos3, version);
|
||||
SWFOutputStream sos3 = new SWFOutputStream(baosGlyphShapes, version);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos3.writeSHAPE(glyphShapeTable[i], 1);
|
||||
offsetTable.add((glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + sos3.getPos());
|
||||
sos3.writeSHAPE(glyphShapeTable.get(i), 1);
|
||||
}
|
||||
byte ba3[] = baos3.toByteArray();
|
||||
sos.write(ba2);
|
||||
if (numGlyphs > 0) {
|
||||
byte baGlyphShapes[] = baosGlyphShapes.toByteArray();
|
||||
for (Long offset : offsetTable) {
|
||||
if (fontFlagsWideOffsets) {
|
||||
sos.writeUI32(offset);
|
||||
} else {
|
||||
sos.writeUI16((int) (long) offset);
|
||||
}
|
||||
}
|
||||
if (numGlyphs > 0) {
|
||||
long offset = (glyphShapeTable.size() + 1/*CodeTableOffset*/) * (fontFlagsWideOffsets ? 4 : 2) + baGlyphShapes.length;
|
||||
if (fontFlagsWideOffsets) {
|
||||
long offset = ba2.length + ba3.length + 4;
|
||||
sos.writeUI32(offset);
|
||||
} else {
|
||||
long offset = ba2.length + ba3.length + 2;
|
||||
sos.writeUI16((int) offset);
|
||||
}
|
||||
sos.write(ba3);
|
||||
sos.write(baGlyphShapes);
|
||||
|
||||
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
@@ -222,10 +233,10 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
sos.writeSI16(fontDescent);
|
||||
sos.writeSI16(fontLeading);
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos.writeSI16(fontAdvanceTable[i]);
|
||||
sos.writeSI16(fontAdvanceTable.get(i));
|
||||
}
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
sos.writeRECT(fontBoundsTable[i]);
|
||||
sos.writeRECT(fontBoundsTable.get(i));
|
||||
}
|
||||
sos.writeUI16(fontKerningTable.length);
|
||||
for (int k = 0; k < fontKerningTable.length; k++) {
|
||||
@@ -244,7 +255,7 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SHAPE[] getGlyphShapeTable() {
|
||||
public List<SHAPE> getGlyphShapeTable() {
|
||||
return glyphShapeTable;
|
||||
}
|
||||
|
||||
@@ -300,4 +311,26 @@ public class DefineFont3Tag extends CharacterTag implements FontTag {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(List<Tag> tags, char character) {
|
||||
int fontStyle = getFontStyle();
|
||||
String fname = getFontName(tags);
|
||||
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fname, fontStyle, getDivider() * 1000, character);
|
||||
glyphShapeTable.add(shp);
|
||||
fontBoundsTable.add(new RECT());//shp.getBounds());
|
||||
codeTable.add((int) character);
|
||||
Font fnt = new Font(fname, fontStyle, getDivider() * 1000);
|
||||
fontAdvanceTable.add((new JPanel()).getFontMetrics(fnt).charWidth(character));
|
||||
numGlyphs++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacters(List<Tag> tags) {
|
||||
String ret = "";
|
||||
for (int i : codeTable) {
|
||||
ret += (char) i;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,14 @@ package com.jpexs.decompiler.flash.tags;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWFInputStream;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -32,11 +33,10 @@ import java.util.List;
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
public class DefineFontTag extends FontTag {
|
||||
|
||||
public int fontId;
|
||||
public int offsetTable[];
|
||||
public SHAPE glyphShapeTable[];
|
||||
public List<SHAPE> glyphShapeTable;
|
||||
private DefineFontInfoTag fontInfoTag = null;
|
||||
private DefineFontInfo2Tag fontInfo2Tag = null;
|
||||
|
||||
@@ -52,7 +52,7 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
|
||||
@Override
|
||||
public int getGlyphWidth(int glyphIndex) {
|
||||
return glyphShapeTable[glyphIndex].getBounds().getWidth();
|
||||
return glyphShapeTable.get(glyphIndex).getBounds().getWidth();
|
||||
}
|
||||
|
||||
private void ensureFontInfo(List<Tag> tags) {
|
||||
@@ -111,12 +111,17 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
SWFOutputStream sos = new SWFOutputStream(os, version);
|
||||
try {
|
||||
sos.writeUI16(fontId);
|
||||
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
List<Integer> offsetTable = new ArrayList<>();
|
||||
SWFOutputStream sos2 = new SWFOutputStream(baos2, version);
|
||||
for (SHAPE shape : glyphShapeTable) {
|
||||
offsetTable.add(glyphShapeTable.size() * 2 + (int) sos2.getPos());
|
||||
sos2.writeSHAPE(shape, 1);
|
||||
}
|
||||
for (int offset : offsetTable) {
|
||||
sos.writeUI16(offset);
|
||||
}
|
||||
for (SHAPE shape : glyphShapeTable) {
|
||||
sos.writeSHAPE(shape, 1);
|
||||
}
|
||||
sos.write(baos2.toByteArray());
|
||||
} catch (IOException e) {
|
||||
}
|
||||
return baos.toByteArray();
|
||||
@@ -136,14 +141,13 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
fontId = sis.readUI16();
|
||||
int firstOffset = sis.readUI16();
|
||||
int nGlyphs = firstOffset / 2;
|
||||
offsetTable = new int[nGlyphs];
|
||||
glyphShapeTable = new SHAPE[nGlyphs];
|
||||
offsetTable[0] = firstOffset;
|
||||
glyphShapeTable = new ArrayList<>();
|
||||
|
||||
for (int i = 1; i < nGlyphs; i++) {
|
||||
offsetTable[i] = sis.readUI16();
|
||||
sis.readUI16(); //offset
|
||||
}
|
||||
for (int i = 0; i < nGlyphs; i++) {
|
||||
glyphShapeTable[i] = sis.readSHAPE(1);
|
||||
glyphShapeTable.add(sis.readSHAPE(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +157,7 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SHAPE[] getGlyphShapeTable() {
|
||||
public List<SHAPE> getGlyphShapeTable() {
|
||||
return glyphShapeTable;
|
||||
}
|
||||
|
||||
@@ -215,4 +219,33 @@ public class DefineFontTag extends CharacterTag implements FontTag {
|
||||
public int getDivider() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCharacter(List<Tag> tags, char character) {
|
||||
glyphShapeTable.add(SHAPERECORD.systemFontCharacterToSHAPE(getFontName(tags), getFontStyle(), getDivider() * 1000, character));
|
||||
ensureFontInfo(tags);
|
||||
if (fontInfoTag != null) {
|
||||
fontInfoTag.codeTable.add((int) character);
|
||||
}
|
||||
if (fontInfo2Tag != null) {
|
||||
fontInfo2Tag.codeTable.add((int) character);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacters(List<Tag> tags) {
|
||||
String ret = "";
|
||||
ensureFontInfo(tags);
|
||||
if (fontInfoTag != null) {
|
||||
for (int i : fontInfoTag.codeTable) {
|
||||
ret += (char) i;
|
||||
}
|
||||
}
|
||||
if (fontInfo2Tag != null) {
|
||||
for (int i : fontInfo2Tag.codeTable) {
|
||||
ret += (char) i;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,13 +329,16 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
for (int i = 0; i < txt.length(); i++) {
|
||||
char c = txt.charAt(i);
|
||||
tr.glyphEntries[i] = new GLYPHENTRY();
|
||||
if (!font.containsChar(tags, c)) {
|
||||
font.addCharacter(tags, c);
|
||||
}
|
||||
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());
|
||||
}
|
||||
/*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;
|
||||
@@ -458,7 +461,7 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
SHAPE glyphs[] = new SHAPE[0];
|
||||
List<SHAPE> glyphs = new ArrayList<>();
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
if (rec.styleFlagsHasColor) {
|
||||
textColor = rec.textColorA.toColor();
|
||||
@@ -476,12 +479,12 @@ public class DefineText2Tag extends CharacterTag implements BoundedTag, TextTag,
|
||||
}
|
||||
|
||||
for (GLYPHENTRY entry : rec.glyphEntries) {
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs[entry.glyphIndex].shapeRecords);
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords);
|
||||
rect.Xmax /= font.getDivider();
|
||||
rect.Xmin /= font.getDivider();
|
||||
rect.Ymax /= font.getDivider();
|
||||
rect.Ymin /= font.getDivider();
|
||||
BufferedImage img = SHAPERECORD.shapeToImage(tags, 4, null, null, glyphs[entry.glyphIndex].shapeRecords, textColor);
|
||||
BufferedImage img = SHAPERECORD.shapeToImage(tags, 4, null, null, glyphs.get(entry.glyphIndex).shapeRecords, textColor);
|
||||
AffineTransform tr = new AffineTransform();
|
||||
tr.setToIdentity();
|
||||
float rat = textHeight / 1000f;
|
||||
|
||||
@@ -328,13 +328,16 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
for (int i = 0; i < txt.length(); i++) {
|
||||
char c = txt.charAt(i);
|
||||
tr.glyphEntries[i] = new GLYPHENTRY();
|
||||
if (!font.containsChar(tags, c)) {
|
||||
font.addCharacter(tags, c);
|
||||
}
|
||||
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());
|
||||
}
|
||||
/*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;
|
||||
@@ -471,7 +474,7 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
SHAPE glyphs[] = new SHAPE[0];
|
||||
List<SHAPE> glyphs = new ArrayList<>();
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
if (rec.styleFlagsHasColor) {
|
||||
textColor = rec.textColor.toColor();
|
||||
@@ -489,12 +492,12 @@ public class DefineTextTag extends CharacterTag implements BoundedTag, TextTag,
|
||||
}
|
||||
|
||||
for (GLYPHENTRY entry : rec.glyphEntries) {
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs[entry.glyphIndex].shapeRecords);
|
||||
RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords);
|
||||
rect.Xmax /= font.getDivider();
|
||||
rect.Xmin /= font.getDivider();
|
||||
rect.Ymax /= font.getDivider();
|
||||
rect.Ymin /= font.getDivider();
|
||||
BufferedImage img = SHAPERECORD.shapeToImage(tags, 1, null, null, glyphs[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 / 1000f;
|
||||
|
||||
@@ -18,39 +18,63 @@ package com.jpexs.decompiler.flash.tags.base;
|
||||
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.types.SHAPE;
|
||||
import java.awt.Font;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface FontTag extends AloneTag {
|
||||
public abstract class FontTag extends CharacterTag implements AloneTag {
|
||||
|
||||
public int getFontId();
|
||||
public FontTag(int id, String name, byte data[], long pos) {
|
||||
super(id, name, data, pos);
|
||||
}
|
||||
|
||||
public SHAPE[] getGlyphShapeTable();
|
||||
public abstract int getFontId();
|
||||
|
||||
public char glyphToChar(List<Tag> tags, int glyphIndex);
|
||||
public abstract List<SHAPE> getGlyphShapeTable();
|
||||
|
||||
public int charToGlyph(List<Tag> tags, char c);
|
||||
public abstract void addCharacter(List<Tag> tags, char character);
|
||||
|
||||
public int getGlyphAdvance(int glyphIndex);
|
||||
public abstract char glyphToChar(List<Tag> tags, int glyphIndex);
|
||||
|
||||
public int getGlyphWidth(int glyphIndex);
|
||||
public abstract int charToGlyph(List<Tag> tags, char c);
|
||||
|
||||
public String getFontName(List<Tag> tags);
|
||||
public abstract int getGlyphAdvance(int glyphIndex);
|
||||
|
||||
public boolean isSmall();
|
||||
public abstract int getGlyphWidth(int glyphIndex);
|
||||
|
||||
public boolean isBold();
|
||||
public abstract String getFontName(List<Tag> tags);
|
||||
|
||||
public boolean isItalic();
|
||||
public abstract boolean isSmall();
|
||||
|
||||
public int getDivider();
|
||||
public abstract boolean isBold();
|
||||
|
||||
public int getAscent();
|
||||
public abstract boolean isItalic();
|
||||
|
||||
public int getDescent();
|
||||
public abstract int getDivider();
|
||||
|
||||
public int getLeading();
|
||||
public abstract int getAscent();
|
||||
|
||||
public abstract int getDescent();
|
||||
|
||||
public abstract int getLeading();
|
||||
|
||||
public boolean containsChar(List<Tag> tags, char character) {
|
||||
return charToGlyph(tags, character) > -1;
|
||||
}
|
||||
|
||||
public int getFontStyle() {
|
||||
int fontStyle = 0;
|
||||
if (isBold()) {
|
||||
fontStyle |= Font.BOLD;
|
||||
}
|
||||
if (isItalic()) {
|
||||
fontStyle |= Font.ITALIC;
|
||||
}
|
||||
return fontStyle;
|
||||
}
|
||||
|
||||
public abstract String getCharacters(List<Tag> tags);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.jpexs.decompiler.flash.types.shaperecords;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.SWFOutputStream;
|
||||
import com.jpexs.decompiler.flash.tags.Tag;
|
||||
import com.jpexs.decompiler.flash.tags.base.ImageTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.NeedsCharacters;
|
||||
@@ -29,9 +30,11 @@ import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
|
||||
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.SHAPE;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.LinearGradientPaint;
|
||||
import java.awt.MultipleGradientPaint.CycleMethod;
|
||||
@@ -39,9 +42,13 @@ import java.awt.Point;
|
||||
import java.awt.RadialGradientPaint;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.TexturePaint;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -51,6 +58,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -66,19 +74,6 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static String edgesToStr(List<SHAPERECORD> records) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
String ret = "";
|
||||
for (SHAPERECORD rec : records) {
|
||||
x = rec.changeX(x);
|
||||
y = rec.changeY(y);
|
||||
ret += ("[" + x + "," + y + "],");
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
private static class Path {
|
||||
|
||||
public boolean used = false;
|
||||
@@ -859,4 +854,185 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
|
||||
}
|
||||
|
||||
public abstract boolean isMove();
|
||||
|
||||
public static List<SHAPE> systemFontCharactersToSHAPES(String fontName, int fontStyle, int fontSize, String characters) {
|
||||
List<SHAPE> ret = new ArrayList<>();
|
||||
for (int i = 0; i < characters.length(); i++) {
|
||||
ret.add(systemFontCharacterToSHAPE(fontName, fontStyle, fontSize, characters.charAt(i)));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static SHAPE systemFontCharacterToSHAPE(String fontName, int fontStyle, int fontSize, char character) {
|
||||
List<SHAPERECORD> retList = new ArrayList<>();
|
||||
Font f = new Font(fontName, fontStyle, fontSize);
|
||||
GlyphVector v = f.createGlyphVector((new JPanel()).getFontMetrics(f).getFontRenderContext(), "" + character);
|
||||
Shape shp = v.getOutline();
|
||||
double points[] = new double[6];
|
||||
double lastX = 0;
|
||||
double lastY = 0;
|
||||
double startX = 0;
|
||||
double startY = 0;
|
||||
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;
|
||||
StyleChangeRecord scr = new StyleChangeRecord();
|
||||
scr.stateMoveTo = true;
|
||||
scr.moveDeltaX = (int) Math.round(points[0]);
|
||||
scr.moveDeltaY = (int) Math.round(points[1]);
|
||||
scr.moveBits = SWFOutputStream.getNeededBitsS(scr.moveDeltaX, scr.moveDeltaY);
|
||||
retList.add(scr);
|
||||
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));
|
||||
ser.numBits = SWFOutputStream.getNeededBitsS(ser.deltaX, ser.deltaY) - 2;
|
||||
if (ser.numBits < 0) {
|
||||
ser.numBits = 0;
|
||||
}
|
||||
retList.add(ser);
|
||||
lastX = points[0];
|
||||
lastY = points[1];
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
double cubicCoords[] = new double[]{
|
||||
lastX, lastY,
|
||||
points[0], points[1],
|
||||
points[2], points[3],
|
||||
points[4], points[5]
|
||||
};
|
||||
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] - quadCoords[i][0]));
|
||||
cer.anchorDeltaY = (int) Math.round((quadCoords[i][3] - quadCoords[i][1]));
|
||||
cer.numBits = SWFOutputStream.getNeededBitsS(cer.controlDeltaX, cer.controlDeltaY, cer.anchorDeltaX, cer.anchorDeltaY) - 2;
|
||||
if (cer.numBits < 0) {
|
||||
cer.numBits = 0;
|
||||
}
|
||||
lastX = quadCoords[i][2];
|
||||
lastY = quadCoords[i][3];
|
||||
retList.add(cer);
|
||||
}
|
||||
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] - points[0]));
|
||||
cer.anchorDeltaY = (int) Math.round((points[3] - 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);
|
||||
lastX = points[2];
|
||||
lastY = points[3];
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE: //Closing line back to last SEG_MOVETO
|
||||
if ((startX == lastX) && (startY == lastY)) {
|
||||
break;
|
||||
}
|
||||
StraightEdgeRecord closeSer = new StraightEdgeRecord();
|
||||
closeSer.generalLineFlag = true;
|
||||
closeSer.deltaX = (int) Math.round((startX - lastX));
|
||||
closeSer.deltaY = (int) Math.round((startY - lastY));
|
||||
closeSer.numBits = SWFOutputStream.getNeededBitsS(closeSer.deltaX, closeSer.deltaY) - 2;
|
||||
if (closeSer.numBits < 0) {
|
||||
closeSer.numBits = 0;
|
||||
}
|
||||
retList.add(closeSer);
|
||||
lastX = startX;
|
||||
lastY = startY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SHAPE shape = new SHAPE();
|
||||
StyleChangeRecord init;
|
||||
if (!retList.isEmpty() && retList.get(0) instanceof StyleChangeRecord) {
|
||||
init = (StyleChangeRecord) retList.get(0);
|
||||
} else {
|
||||
init = new StyleChangeRecord();
|
||||
retList.add(0, init);
|
||||
}
|
||||
|
||||
|
||||
retList.add(new EndShapeRecord());
|
||||
init.stateFillStyle0 = true;
|
||||
init.fillStyle0 = 1;
|
||||
shape.shapeRecords = retList;
|
||||
shape.numFillBits = 1;
|
||||
shape.numLineBits = 0;
|
||||
return shape;
|
||||
}
|
||||
|
||||
// Taken from org.apache.fop.afp.util
|
||||
private static double[][] approximateCubic(double[] cubicControlPointCoords) {
|
||||
if (cubicControlPointCoords.length < 8) {
|
||||
throw new IllegalArgumentException("Must have at least 8 coordinates");
|
||||
}
|
||||
|
||||
//extract point objects from source array
|
||||
Point2D p0 = new Point2D.Double(cubicControlPointCoords[0], cubicControlPointCoords[1]);
|
||||
Point2D p1 = new Point2D.Double(cubicControlPointCoords[2], cubicControlPointCoords[3]);
|
||||
Point2D p2 = new Point2D.Double(cubicControlPointCoords[4], cubicControlPointCoords[5]);
|
||||
Point2D p3 = new Point2D.Double(cubicControlPointCoords[6], cubicControlPointCoords[7]);
|
||||
|
||||
//calculates the useful base points
|
||||
Point2D pa = getPointOnSegment(p0, p1, 3.0 / 4.0);
|
||||
Point2D pb = getPointOnSegment(p3, p2, 3.0 / 4.0);
|
||||
|
||||
//get 1/16 of the [P3, P0] segment
|
||||
double dx = (p3.getX() - p0.getX()) / 16.0;
|
||||
double dy = (p3.getY() - p0.getY()) / 16.0;
|
||||
|
||||
//calculates control point 1
|
||||
Point2D pc1 = getPointOnSegment(p0, p1, 3.0 / 8.0);
|
||||
|
||||
//calculates control point 2
|
||||
Point2D pc2 = getPointOnSegment(pa, pb, 3.0 / 8.0);
|
||||
pc2 = movePoint(pc2, -dx, -dy);
|
||||
|
||||
//calculates control point 3
|
||||
Point2D pc3 = getPointOnSegment(pb, pa, 3.0 / 8.0);
|
||||
pc3 = movePoint(pc3, dx, dy);
|
||||
|
||||
//calculates control point 4
|
||||
Point2D pc4 = getPointOnSegment(p3, p2, 3.0 / 8.0);
|
||||
|
||||
//calculates the 3 anchor points
|
||||
Point2D pa1 = getMidPoint(pc1, pc2);
|
||||
Point2D pa2 = getMidPoint(pa, pb);
|
||||
Point2D pa3 = getMidPoint(pc3, pc4);
|
||||
|
||||
//return the points for the four quadratic curves
|
||||
return new double[][]{
|
||||
{pc1.getX(), pc1.getY(), pa1.getX(), pa1.getY()},
|
||||
{pc2.getX(), pc2.getY(), pa2.getX(), pa2.getY()},
|
||||
{pc3.getX(), pc3.getY(), pa3.getX(), pa3.getY()},
|
||||
{pc4.getX(), pc4.getY(), p3.getX(), p3.getY()}};
|
||||
}
|
||||
|
||||
private static Point2D.Double movePoint(Point2D point, double dx, double dy) {
|
||||
return new Point2D.Double(point.getX() + dx, point.getY() + dy);
|
||||
}
|
||||
|
||||
private static Point2D getMidPoint(Point2D p0, Point2D p1) {
|
||||
return getPointOnSegment(p0, p1, 0.5);
|
||||
}
|
||||
|
||||
private static Point2D getPointOnSegment(Point2D p0, Point2D p1, double ratio) {
|
||||
double x = p0.getX() + ((p1.getX() - p0.getX()) * ratio);
|
||||
double y = p0.getY() + ((p1.getY() - p0.getY()) * ratio);
|
||||
return new Point2D.Double(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user