GFx fonts: Adding characters

GFx fonts: Displaying text fields
Fonts display in internal viewer
This commit is contained in:
Jindra Petk
2013-09-23 06:55:03 +02:00
parent b3d7577453
commit 61fd0d1b83
21 changed files with 979 additions and 94 deletions

View File

@@ -292,6 +292,10 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
private JComboBox<String> fontSelection;
private JCommandButton saveCommandButton;
private PlayerControls flashControls;
private ImagePanel internelViewerPanel;
private JPanel viewerCards;
public static final String FLASH_VIEWER_CARD = "FLASHVIEWER";
public static final String INTERNAL_VIEWER_CARD = "INTERNALVIEWER";
private Map<Integer, String> sourceFontsMap = new HashMap<>();
private AbortRetryIgnoreHandler errorHandler = new AbortRetryIgnoreHandler() {
@Override
@@ -1273,7 +1277,19 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
paramsLabel.setHorizontalAlignment(SwingConstants.CENTER);
//paramsLabel.setBorder(new BevelBorder(BevelBorder.RAISED));
pan.add(prevLabel, BorderLayout.NORTH);
pan.add(leftComponent, BorderLayout.CENTER);
viewerCards = new JPanel();
viewerCards.setLayout(new CardLayout());
//viewerCards.add(leftComponent,FLASH_VIEWER_CARD);
internelViewerPanel = new ImagePanel();
JPanel ivPanel = new JPanel(new BorderLayout());
ivPanel.add(new HeaderLabel(translate("swfpreview.internal")), BorderLayout.NORTH);
ivPanel.add(internelViewerPanel, BorderLayout.CENTER);
viewerCards.add(ivPanel, INTERNAL_VIEWER_CARD);
((CardLayout) viewerCards.getLayout()).show(viewerCards, FLASH_VIEWER_CARD);
if (flashPanel != null) {
JPanel bottomPanel = new JPanel(new BorderLayout());
JPanel buttonsPanel = new JPanel(new FlowLayout());
@@ -1285,7 +1301,9 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
bottomPanel.add(buttonsPanel, BorderLayout.EAST);
pan.add(bottomPanel, BorderLayout.SOUTH);
}
previewSplitPane.setLeftComponent(pan);
pan.add(leftComponent, BorderLayout.CENTER);
viewerCards.add(pan, FLASH_VIEWER_CARD);
previewSplitPane.setLeftComponent(viewerCards);
parametersPanel = new JPanel(new BorderLayout());
parametersPanel.add(paramsLabel, BorderLayout.NORTH);
@@ -2941,6 +2959,13 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
}
}
private static Tag classicTag(Tag t) {
if (t instanceof GFxDefineCompactedFont) {
return ((GFxDefineCompactedFont) t).toClassicFont();
}
return t;
}
public void reload(boolean forceReload) {
Object tagObj = tagTree.getLastSelectedPathComponent();
if (tagObj == null) {
@@ -3047,9 +3072,13 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
imageButtonsPanel.setVisible(((ImageTag) tagObj).importSupported());
showCard(CARDIMAGEPANEL);
imagePanel.setImage(((ImageTag) tagObj).getImage(swf.tags));
} else if ((tagObj instanceof DrawableTag) && (!(tagObj instanceof TextTag)) && (miInternalViewer.isSelected())) {
} else if ((tagObj instanceof DrawableTag) && (!(tagObj instanceof TextTag)) && (!(tagObj instanceof FontTag)) && (miInternalViewer.isSelected())) {
showCard(CARDDRAWPREVIEWPANEL);
previewImagePanel.setDrawable((DrawableTag) tagObj, swf, characters, 50/*FIXME*/);
} else if ((tagObj instanceof FontTag) && (miInternalViewer.isSelected() || (tagObj instanceof GFxDefineCompactedFont))) {
showCard(CARDFLASHPANEL);
previewImagePanel.setDrawable((DrawableTag) tagObj, swf, characters, 50/*FIXME*/);
showFontTag((FontTag) tagObj);
} else if (tagObj instanceof FrameNode && ((FrameNode) tagObj).isDisplayed() && (miInternalViewer.isSelected())) {
showCard(CARDDRAWPREVIEWPANEL);
FrameNode fn = (FrameNode) tagObj;
@@ -3065,6 +3094,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
}
previewImagePanel.setImage(SWF.frameToImage(containerId, ((FrameNode) tagObj).getFrame() - 1, swf.tags, controlTags, rect, totalFrameCount, new Stack<Integer>()));
} else if (((tagObj instanceof FrameNode) && ((FrameNode) tagObj).isDisplayed()) || ((tagObj instanceof CharacterTag) || (tagObj instanceof FontTag)) && (tagObj instanceof Tag)) {
((CardLayout) viewerCards.getLayout()).show(viewerCards, FLASH_VIEWER_CARD);
try {
if (tempFile != null) {
@@ -3158,14 +3188,14 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
Set<Integer> needed = t.getDeepNeededCharacters(characters, new ArrayList<Integer>());
for (int n : needed) {
if (!doneCharacters.contains(n)) {
sos2.writeTag(characters.get(n));
sos2.writeTag(classicTag(characters.get(n)));
doneCharacters.add(n);
}
}
if (t instanceof CharacterTag) {
doneCharacters.add(((CharacterTag) t).getCharacterId());
}
sos2.writeTag(t);
sos2.writeTag(classicTag(t));
if (parent != null) {
if (t instanceof PlaceObjectTypeTag) {
@@ -3201,11 +3231,11 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
} else {
Set<Integer> needed = ((Tag) tagObj).getDeepNeededCharacters(characters, new ArrayList<Integer>());
for (int n : needed) {
sos2.writeTag(characters.get(n));
sos2.writeTag(classicTag(characters.get(n)));
}
}
sos2.writeTag(((Tag) tagObj));
sos2.writeTag(classicTag((Tag) tagObj));
int chtId = 0;
if (tagObj instanceof CharacterTag) {
@@ -3441,24 +3471,7 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
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() == -1 ? translate("value.unknown") : "" + ft.getDescent());
fontAscentLabel.setText(ft.getAscent() == -1 ? translate("value.unknown") : "" + ft.getAscent());
fontLeadingLabel.setText(ft.getLeading() == -1 ? translate("value.unknown") : "" + ft.getLeading());
String chars = ft.getCharacters(swf.tags);
fontCharactersTextArea.setText(chars);
if (sourceFontsMap.containsKey(ft.getFontId())) {
fontSelection.setSelectedItem(sourceFontsMap.get(ft.getFontId()));
} else {
fontSelection.setSelectedItem(FontTag.findInstalledFontName(ft.getFontName(swf.tags)));
}
fontChangeList.componentResized(null);
showDetailWithPreview(CARDFONTPANEL);
showFontTag((FontTag) tagObj);
} else {
parametersPanel.setVisible(false);
}
@@ -3468,6 +3481,33 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel
}
}
private void showFontTag(FontTag ft) {
if (miInternalViewer.isSelected() || ft instanceof GFxDefineCompactedFont) {
((CardLayout) viewerCards.getLayout()).show(viewerCards, INTERNAL_VIEWER_CARD);
internelViewerPanel.setDrawable(ft, swf, characters, 1);
} else {
((CardLayout) viewerCards.getLayout()).show(viewerCards, FLASH_VIEWER_CARD);
}
parametersPanel.setVisible(true);
previewSplitPane.setDividerLocation(previewSplitPane.getWidth() / 2);
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() == -1 ? translate("value.unknown") : "" + ft.getDescent());
fontAscentLabel.setText(ft.getAscent() == -1 ? translate("value.unknown") : "" + ft.getAscent());
fontLeadingLabel.setText(ft.getLeading() == -1 ? translate("value.unknown") : "" + ft.getLeading());
String chars = ft.getCharacters(swf.tags);
fontCharactersTextArea.setText(chars);
if (sourceFontsMap.containsKey(ft.getFontId())) {
fontSelection.setSelectedItem(sourceFontsMap.get(ft.getFontId()));
} else {
fontSelection.setSelectedItem(FontTag.findInstalledFontName(ft.getFontName(swf.tags)));
}
fontChangeList.componentResized(null);
showDetailWithPreview(CARDFONTPANEL);
}
public void refreshTree() {
List<ContainerItem> objs = new ArrayList<>();
objs.addAll(swf.tags);

View File

@@ -161,6 +161,10 @@ public class DefineFont2Tag extends FontTag {
return baos.toByteArray();
}
public DefineFont2Tag(SWF swf) throws IOException {
super(swf, ID, "DefineFont2", new byte[0], 0);
}
/**
* Constructor
*

View File

@@ -18,29 +18,47 @@ 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.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
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.gfx.FontType;
import com.jpexs.decompiler.flash.types.gfx.GFxInputStream;
import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream;
import com.jpexs.decompiler.flash.types.gfx.GlyphInfoType;
import com.jpexs.decompiler.flash.types.gfx.GlyphType;
import com.jpexs.decompiler.flash.types.gfx.KerningPairType;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import com.jpexs.helpers.Helper;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;
/**
*
*
* @author JPEXS
*/
public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag {
public class GFxDefineCompactedFont extends FontTag implements DrawableTag {
public static final int ID = 1005;
public int fontId;
@@ -54,15 +72,17 @@ public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag
*/
@Override
public byte[] getData(int version) {
return super.getData(version);
/*ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, version);
try {
//sos.write
} catch (IOException e) {
}
return baos.toByteArray();*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, version);
try {
sos.writeUI16(fontId);
for (FontType ft : fonts) {
ft.write(new GFxOutputStream(sos));
}
} catch (IOException e) {
}
return baos.toByteArray();
}
/**
@@ -92,6 +112,9 @@ public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag
for (FontType f : fonts) {
shapes.addAll(f.getGlyphShapes());
}
for (int i = 0; i < shapes.size(); i++) {
shapes.set(i, SHAPERECORD.resizeSHAPE(shapes.get(i), 20));
}
return SHAPERECORD.shapeListToImage(shapes, 500, 500, Color.black);
}
@@ -105,6 +128,7 @@ public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag
return 1;
}
@Override
public String getFontName(List<Tag> tags) {
String ret = "";
for (int i = 0; i < fonts.size(); i++) {
@@ -116,18 +140,217 @@ public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag
return ret;
}
@Override
public String getName(List<Tag> tags) {
String nameAppend = "";
String fontName = getFontName(tags);
if (fontName != null) {
nameAppend = ": " + fontName;
}
return name + " (" + getCharacterId() + nameAppend + ")";
}
@Override
public int getCharacterId() {
return fontId;
}
@Override
public int getFontId() {
return fontId;
}
@Override
public List<SHAPE> getGlyphShapeTable() {
return fonts.get(0).getGlyphShapes();
}
@Override
public void addCharacter(List<Tag> tags, char character, String fontName) {
int fontStyle = getFontStyle();
FontType font = fonts.get(0);
SHAPE shp = SHAPERECORD.systemFontCharacterToSHAPE(fontName, fontStyle, 20 * font.nominalSize, character);
int code = (int) character;
int pos = -1;
for (int i = 0; i < font.glyphInfo.size(); i++) {
if (font.glyphInfo.get(i).glyphCode > code) {
pos = i;
break;
}
}
if (pos == -1) {
pos = font.glyphInfo.size();
}
FontTag.shiftGlyphIndices(fontId, pos, tags);
Font fnt = new Font(fontName, fontStyle, 20 * font.nominalSize);
int advance = (int) Math.round(fnt.createGlyphVector((new JPanel()).getFontMetrics(fnt).getFontRenderContext(), "" + character).getGlyphMetrics(0).getAdvanceX());
font.glyphInfo.add(pos, new GlyphInfoType(code, advance, 0));
font.glyphs.add(pos, new GlyphType(shp.shapeRecords));
}
@Override
public char glyphToChar(List<Tag> tags, int glyphIndex) {
return (char) fonts.get(0).glyphInfo.get(glyphIndex).glyphCode;
}
@Override
public int charToGlyph(List<Tag> tags, char c) {
FontType ft = fonts.get(0);
for (int i = 0; i < ft.glyphInfo.size(); i++) {
if (ft.glyphInfo.get(i).glyphCode == c) {
return i;
}
}
return -1;
}
@Override
public int getGlyphAdvance(int glyphIndex) {
return fonts.get(0).glyphInfo.get(glyphIndex).advanceX;
}
@Override
public int getGlyphKerningAdjustment(List<Tag> tags, int glyphIndex, int nextGlyphIndex) {
int char1 = glyphToChar(tags, glyphIndex);
int char2 = glyphToChar(tags, nextGlyphIndex);
for (KerningPairType kp : fonts.get(0).kerning) {
if (kp.char1 == char1 && kp.char2 == char2) {
return kp.advance;
}
}
return 0;
}
@Override
public int getGlyphWidth(int glyphIndex) {
return getGlyphShapeTable().get(glyphIndex).getBounds().getWidth();
}
@Override
public boolean isSmall() {
return false;
}
@Override
public boolean isBold() {
return (fonts.get(0).flags & FontType.FF_Bold) == FontType.FF_Bold;
}
@Override
public boolean isItalic() {
return (fonts.get(0).flags & FontType.FF_Italic) == FontType.FF_Italic;
}
@Override
public int getDivider() {
return 1;
}
@Override
public int getAscent() {
return fonts.get(0).ascent;
}
@Override
public int getDescent() {
return fonts.get(0).descent;
}
@Override
public int getLeading() {
return fonts.get(0).leading;
}
@Override
public String getCharacters(List<Tag> tags) {
FontType ft = fonts.get(0);
String ret = "";
for (GlyphInfoType gi : ft.glyphInfo) {
ret += (char) gi.glyphCode;
}
return ret;
}
private int resizemultiplier() {
FontType ft = fonts.get(0);
return (int) Math.round(1024.0 / ft.nominalSize);
}
private int resize(int val) {
int ret = val * resizemultiplier();
return ret;
}
private SHAPE resize(SHAPE shp) {
SHAPE ret = new SHAPE();
ret.numFillBits = 1;
ret.numLineBits = 0;
List<SHAPERECORD> recs = new ArrayList<>();
for (SHAPERECORD r : shp.shapeRecords) {
SHAPERECORD c = (SHAPERECORD) Helper.deepCopy(r);
if (c instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) c;
scr.moveDeltaX = resize(scr.moveDeltaX);
scr.moveDeltaY = resize(scr.moveDeltaY);
scr.calculateBits();
}
if (c instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) c;
cer.controlDeltaX = resize(cer.controlDeltaX);
cer.controlDeltaY = resize(cer.controlDeltaY);
cer.anchorDeltaX = resize(cer.anchorDeltaX);
cer.anchorDeltaY = resize(cer.anchorDeltaY);
cer.calculateBits();
}
if (c instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) c;
ser.deltaX = resize(ser.deltaX);
ser.deltaY = resize(ser.deltaY);
ser.calculateBits();
}
recs.add(c);
}
ret.shapeRecords = recs;
return ret;
}
public FontTag toClassicFont() {
try {
DefineFont2Tag ret = new DefineFont2Tag(swf);
ret.fontId = fontId;
ret.fontFlagsBold = isBold();
ret.fontFlagsItalic = isItalic();
ret.fontFlagsWideOffsets = true;
ret.fontFlagsWideCodes = true;
ret.fontFlagsHasLayout = true;
FontType ft = fonts.get(0);
ret.fontAscent = resize(ft.ascent);
ret.fontDescent = resize(ft.descent);
ret.fontLeading = resize(ft.leading);
ret.fontAdvanceTable = new ArrayList<>();
ret.fontBoundsTable = new ArrayList<>();
ret.codeTable = new ArrayList<>();
ret.glyphShapeTable = new ArrayList<>();
ret.numGlyphs = ft.glyphInfo.size();
SHAPE shpA = SHAPERECORD.systemFontCharacterToSHAPE("Times New Roman", 0, getDivider() * 1024, 'A');
for (GlyphInfoType gi : ft.glyphInfo) {
ret.fontAdvanceTable.add(resize(gi.advanceX));
ret.codeTable.add(gi.glyphCode);
}
for (GlyphType gt : ft.glyphs) {
SHAPE shpX = resize(gt.toSHAPE());
ret.glyphShapeTable.add(shpX); //
ret.fontBoundsTable.add(new RECT(resize(gt.boundingBox[0]), resize(gt.boundingBox[1]), resize(gt.boundingBox[2]), resize(gt.boundingBox[3])));
}
ret.fontName = ft.fontName;
ret.languageCode = new LANGCODE(1);
ret.fontKerningTable = new KERNINGRECORD[0];/*new KERNINGRECORD[ft.kerning.size()];
for(int i=0;i<ft.kerning.size();i++){
KERNINGRECORD kr=new KERNINGRECORD();
kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance);
kr.fontKerningCode1 = ft.kerning.get(i).char1;
kr.fontKerningCode2 = ft.kerning.get(i).char2;
ret.fontKerningTable[i] = kr;
}*/
return ret;
} catch (IOException ex) {
Logger.getLogger(GFxDefineCompactedFont.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}

View File

@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.types.gfx.FONTINFO;
import com.jpexs.decompiler.flash.types.gfx.GFxInputStream;
import com.jpexs.decompiler.flash.types.gfx.GFxOutputStream;
import com.jpexs.decompiler.flash.types.gfx.TEXGLYPH;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -71,11 +72,11 @@ public class GFxFontTextureInfo extends Tag {
sos.writeUI16(nominalGlyphSz);
sos.writeUI16(texGlyphs.length);
for (int i = 0; i < texGlyphs.length; i++) {
texGlyphs[i].write(sos);
texGlyphs[i].write(new GFxOutputStream(sos));
}
sos.writeUI16(fonts.length);
for (int i = 0; i < fonts.length; i++) {
fonts[i].write(sos);
fonts[i].write(new GFxOutputStream(sos));
}
} catch (IOException e) {
}

View File

@@ -21,22 +21,29 @@ 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.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.Color;
import java.awt.Font;
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.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
/**
*
* @author JPEXS
*/
public abstract class FontTag extends CharacterTag implements AloneTag {
public abstract class FontTag extends CharacterTag implements AloneTag, DrawableTag {
public FontTag(SWF swf, int id, String name, byte[] data, long pos) {
super(swf, id, name, data, pos);
@@ -184,4 +191,19 @@ public abstract class FontTag extends CharacterTag implements AloneTag {
}
return fontNames.get(0);
}
@Override
public BufferedImage toImage(int frame, List<Tag> tags, RECT displayRect, HashMap<Integer, CharacterTag> characters, Stack<Integer> visited) {
return SHAPERECORD.shapeListToImage(getGlyphShapeTable(), 500, 500, Color.black);
}
@Override
public Point getImagePos(int frame, HashMap<Integer, CharacterTag> characters, Stack<Integer> visited) {
return new Point(0, 0);
}
@Override
public int getNumFrames() {
return 1;
}
}

View File

@@ -23,4 +23,11 @@ package com.jpexs.decompiler.flash.types;
public class LANGCODE {
public int languageCode;
public LANGCODE() {
}
public LANGCODE(int languageCode) {
this.languageCode = languageCode;
}
}

View File

@@ -16,8 +16,9 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import java.io.IOException;
import java.util.ArrayList;
@@ -35,6 +36,39 @@ public class ContourType {
public boolean isReference;
public long reference;
public ContourType(List<SHAPERECORD> records) {
int i = 0;
int divider = 20;
for (; i < records.size(); i++) {
if (records.get(i) instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) records.get(i);
if (scr.stateMoveTo) {
moveToX = scr.moveDeltaX / divider;
moveToY = scr.moveDeltaY / divider;
break;
}
}
}
List<EdgeType> edgesList = new ArrayList<>();
for (; i < records.size(); i++) {
SHAPERECORD rec = records.get(i);
if (rec instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) rec;
if (ser.generalLineFlag) {
edgesList.add(new EdgeType(ser.deltaX / divider, ser.deltaY / divider));
} else if (ser.vertLineFlag) {
edgesList.add(new EdgeType(true, ser.deltaY / divider));
} else {
edgesList.add(new EdgeType(false, ser.deltaX / divider));
}
} else if (rec instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) rec;
edgesList.add(new EdgeType(cer.controlDeltaX / divider, cer.controlDeltaY / divider, cer.anchorDeltaX / divider, cer.anchorDeltaY / divider));
}
}
edges = edgesList.toArray(new EdgeType[edgesList.size()]);
}
public ContourType(GFxInputStream sis) throws IOException {
moveToX = sis.readSI15();
moveToY = sis.readSI15();
@@ -59,19 +93,39 @@ public class ContourType {
}
public List<SHAPERECORD> toSHAPERECORDS() {
int multiplier = 20;
int multiplier = 1;
List<SHAPERECORD> recs = new ArrayList<>();
StyleChangeRecord src = new StyleChangeRecord();
src.stateMoveTo = true;
src.moveDeltaX = moveToX * multiplier;
src.moveDeltaY = moveToY * multiplier;
src.calculateBits();
recs.add(src);
for (EdgeType e : edges) {
recs.add(e.toSHAPERECORD());
}
int x = src.moveDeltaX;
int y = src.moveDeltaY;
for (SHAPERECORD rec : recs) {
x = rec.changeX(x);
y = rec.changeY(y);
}
StraightEdgeRecord closeSer = new StraightEdgeRecord();
closeSer.generalLineFlag = true;
closeSer.deltaX = (src.moveDeltaX - x);
closeSer.deltaY = (src.moveDeltaY - y);
closeSer.calculateBits();
recs.add(closeSer);
return recs;
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeSI15(moveToX);
sos.writeSI15(moveToY);
sos.writeUI30(edges.length << 1);
for (int i = 0; i < edges.length; i++) {
edges[i].write(sos);
}
}
}

View File

@@ -16,11 +16,13 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
@@ -52,6 +54,32 @@ public class EdgeType {
public int data[];
public byte raw[];
public EdgeType(boolean vertical, int v) {
data = new int[]{vertical ? Edge_VLine : Edge_HLine, v};
calcRaw();
}
public EdgeType(int x, int y) {
data = new int[]{Edge_Line, x, y};
calcRaw();
}
public EdgeType(int cx, int cy, int ax, int ay) {
data = new int[]{Edge_Quad, cx, cy, ax, ay};
calcRaw();
}
private void calcRaw() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GFxOutputStream sos = new GFxOutputStream(baos);
try {
write(sos);
} catch (IOException ex) {
Logger.getLogger(EdgeType.class.getName()).log(Level.SEVERE, null, ex);
}
raw = baos.toByteArray();
}
@Override
public String toString() {
String ret = "[Edge " + (raw[0] & 0xf) + " data:";
@@ -114,7 +142,7 @@ public class EdgeType {
}
public SHAPERECORD toSHAPERECORD() {
int multiplier = 20;
int multiplier = 1;
StraightEdgeRecord ser;
CurvedEdgeRecord cer;
switch (data[0]) {
@@ -122,18 +150,21 @@ public class EdgeType {
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.deltaX = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_VLine:
ser = new StraightEdgeRecord();
ser.generalLineFlag = false;
ser.vertLineFlag = true;
ser.deltaY = data[1] * multiplier;
ser.calculateBits();
return ser;
case Edge_Line:
ser = new StraightEdgeRecord();
ser.generalLineFlag = true;
ser.deltaX = data[1] * multiplier;
ser.deltaY = data[2] * multiplier;
ser.calculateBits();
return ser;
case Edge_Quad:
cer = new CurvedEdgeRecord();
@@ -141,6 +172,7 @@ public class EdgeType {
cer.controlDeltaY = data[2] * multiplier;
cer.anchorDeltaX = data[3] * multiplier;
cer.anchorDeltaY = data[4] * multiplier;
cer.calculateBits();
return cer;
}
return null;
@@ -262,6 +294,168 @@ public class EdgeType {
return data;
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
int x;
int y;
int m1 = 1;
int m2 = 3;
int m3 = 7;
int m4 = 0xF;
int m5 = 0x1F;
int m6 = 0x3F;
int m7 = 0x7F;
switch (data[0]) {
case Edge_HLine:
x = data[1];
if (x >= GFxOutputStream.MinSInt12 && x <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((x << 4) | Edge_H12);
sos.writeUI8(x >> 4);
return;
}
sos.writeUI8((x << 4) | Edge_H20);
sos.writeUI8(x >> 4);
sos.writeUI8(x >> 12);
break;
case Edge_VLine:
y = data[1];
if (y >= GFxOutputStream.MinSInt12 && y <= GFxOutputStream.MaxSInt12) {
sos.writeUI8((y << 4) | Edge_V12);
sos.writeUI8(y >> 4);
return;
}
sos.writeUI8((y << 4) | Edge_V20);
sos.writeUI8(y >> 4);
sos.writeUI8(y >> 12);
return;
case Edge_Line:
x = data[1];
y = data[2];
if (x >= GFxOutputStream.MinSInt6 && x <= GFxOutputStream.MaxSInt6 && y >= GFxOutputStream.MinSInt6 && y <= GFxOutputStream.MaxSInt6) {
sos.writeUI8((x << 4) | Edge_L6);
sos.writeUI8(((x >> 4) & m2) | (y << 2));
return;
}
if (x >= GFxOutputStream.MinSInt10 && x <= GFxOutputStream.MaxSInt10 && y >= GFxOutputStream.MinSInt10 && y <= GFxOutputStream.MaxSInt10) {
sos.writeUI8((x << 4) | Edge_L10);
sos.writeUI8(((x >> 4) & m6) | (y << 6));
sos.writeUI8(y >> 2);
return;
}
if (x >= GFxOutputStream.MinSInt14 && x <= GFxOutputStream.MaxSInt14 && y >= GFxOutputStream.MinSInt14 && y <= GFxOutputStream.MaxSInt14) {
sos.writeUI8((x << 4) | Edge_L14);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m2) | (y << 2));
sos.writeUI8(y >> 6);
return;
}
sos.writeUI8((x << 4) | Edge_L18);
sos.writeUI8(x >> 4);
sos.writeUI8(((x >> 12) & m6) | (y << 6));
sos.writeUI8(y >> 2);
sos.writeUI8(y >> 10);
return;
case Edge_Quad:
int cx = data[1];
int cy = data[2];
int ax = data[3];
int ay = data[4];
int minV = cx;
int maxV = cx;
if (cy < minV) {
minV = cy;
}
if (cy > maxV) {
maxV = cy;
}
if (ax < minV) {
minV = ax;
}
if (ax > maxV) {
maxV = ax;
}
if (ay < minV) {
minV = ay;
}
if (ay > maxV) {
maxV = ay;
}
if (minV >= GFxOutputStream.MinSInt5 && maxV <= GFxOutputStream.MaxSInt5) {
sos.writeUI8(((cx << 4) | Edge_C5));
sos.writeUI8((((cx >> 4) & m1) | ((cy << 1) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m3) | (ay << 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt7 && maxV <= GFxOutputStream.MaxSInt7) {
sos.writeUI8(((cx << 4) | Edge_C7));
sos.writeUI8((((cx >> 4) & m3) | (cy << 3)));
sos.writeUI8((((cy >> 5) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m1) | (ay << 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt9 && maxV <= GFxOutputStream.MaxSInt9) {
sos.writeUI8(((cx << 4) | Edge_C9));
sos.writeUI8((((cx >> 4) & m5) | (cy << 5)));
sos.writeUI8((((cy >> 3) & m6) | (ax << 6)));
sos.writeUI8((((ax >> 2) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
return;
}
if (minV >= GFxOutputStream.MinSInt11 && maxV <= GFxOutputStream.MaxSInt11) {
sos.writeUI8(((cx << 4) | Edge_C11));
sos.writeUI8((((cx >> 4) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8((((cy >> 9) & m2) | (ax << 2)));
sos.writeUI8((((ax >> 6) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
return;
}
if (minV >= GFxOutputStream.MinSInt13 && maxV <= GFxOutputStream.MaxSInt13) {
sos.writeUI8(((cx << 4) | Edge_C13));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m1) | (cy << 1)));
sos.writeUI8((((cy >> 7) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m3) | (ay << 3)));
sos.writeUI8(((ay >> 5)));
return;
}
if (minV >= GFxOutputStream.MinSInt15 && maxV <= GFxOutputStream.MaxSInt15) {
sos.writeUI8(((cx << 4) | Edge_C15));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m3) | (cy << 3)));
sos.writeUI8(((cy >> 5)));
sos.writeUI8((((cy >> 13) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m1) | (ay << 1)));
sos.writeUI8(((ay >> 7)));
return;
}
if (minV >= GFxOutputStream.MinSInt17 && maxV <= GFxOutputStream.MaxSInt17) {
sos.writeUI8(((cx << 4) | Edge_C17));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m5) | (cy << 5)));
sos.writeUI8(((cy >> 3)));
sos.writeUI8((((cy >> 11) & m6) | (ax << 6)));
sos.writeUI8(((ax >> 2)));
sos.writeUI8((((ax >> 10) & m7) | (ay << 7)));
sos.writeUI8(((ay >> 1)));
sos.writeUI8(((ay >> 9)));
return;
}
sos.writeUI8(((cx << 4) | Edge_C19));
sos.writeUI8(((cx >> 4)));
sos.writeUI8((((cx >> 12) & m7) | (cy << 7)));
sos.writeUI8(((cy >> 1)));
sos.writeUI8(((cy >> 9)));
sos.writeUI8((((cy >> 17) & m2) | (ax << 2)));
sos.writeUI8(((ax >> 6)));
sos.writeUI8((((ax >> 14) & m5) | (ay << 5)));
sos.writeUI8(((ay >> 3)));
sos.writeUI8(((ay >> 11)));
return;
}
}
}

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.IOException;
/**
@@ -42,7 +41,7 @@ public class FONTINFO {
}
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeUI16(fontId);
sos.writeUI16(glyphIndices.length);
for (int i = 0; i < glyphIndices.length; i++) {

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.types.SHAPE;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -37,14 +36,13 @@ public class FontType {
public int ascent;
public int descent;
public int leading;
public GlyphType[] glyphs;
public GlyphInfoType[] glyphInfo;
public KerningPairType[] kerning;
public List<GlyphType> glyphs;
public List<GlyphInfoType> glyphInfo;
public List<KerningPairType> kerning;
public FontType(GFxInputStream sis) throws IOException {
sis = new GFxInputStream(sis);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//fontId = sis.readUI16();
int val;
while ((val = sis.readUI8()) > 0) {
baos.write(val);
@@ -59,21 +57,21 @@ public class FontType {
long glyphBytesLen = sis.readUI32();
byte glyphBytes[] = new byte[(int) glyphBytesLen];
sis.read(glyphBytes);
glyphInfo = new GlyphInfoType[(int) numGlyphs];
glyphInfo = new ArrayList<>();
for (int i = 0; i < numGlyphs; i++) {
glyphInfo[i] = new GlyphInfoType(sis);
glyphInfo.add(new GlyphInfoType(sis));
}
long kerningTableSize = sis.readUI30();
kerning = new KerningPairType[((int) kerningTableSize)];
kerning = new ArrayList<>();
for (int i = 0; i < kerningTableSize; i++) {
kerning[i] = new KerningPairType(sis);
kerning.add(new KerningPairType(sis));
}
glyphs = new GlyphType[glyphInfo.length];
for (int i = 0; i < glyphInfo.length; i++) {
sis.setPos(glyphInfo[i].globalOffset);
glyphs[i] = new GlyphType(sis);
glyphs = new ArrayList<>();
for (int i = 0; i < glyphInfo.size(); i++) {
sis.setPos(glyphInfo.get(i).globalOffset);
glyphs.add(new GlyphType(sis));
}
}
@@ -85,6 +83,32 @@ public class FontType {
return ret;
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos = new GFxOutputStream(sos);
sos.write(fontName.getBytes());
sos.writeUI8(0);
sos.writeUI16(flags);
sos.writeUI16(nominalSize);
sos.writeUI16(ascent);
sos.writeUI16(descent);
sos.writeUI16(leading);
sos.writeUI32(glyphInfo.size()); //numGlyphs
long headerLen = sos.getPos() + 4;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GFxOutputStream sos2 = new GFxOutputStream(baos);
for (int i = 0; i < glyphs.size(); i++) {
glyphInfo.get(i).globalOffset = headerLen + sos2.getPos();
glyphs.get(i).write(sos2);
}
byte[] glyphBytes = baos.toByteArray();
sos.writeUI32(glyphBytes.length);
sos.write(glyphBytes);
for (int i = 0; i < glyphInfo.size(); i++) {
glyphInfo.get(i).write(sos);
}
sos.writeUI30(kerning.size());
for (KerningPairType kp : kerning) {
kp.write(sos);
}
}
}

View File

@@ -0,0 +1,195 @@
/*
* 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.types.gfx;
import java.io.IOException;
import java.io.OutputStream;
/**
*
* @author JPEXS
*/
public class GFxOutputStream extends OutputStream {
public static final int MaxUInt6 = (1 << 6) - 1;
public static final int MaxUInt7 = (1 << 7) - 1;
public static final int MaxUInt14 = (1 << 14) - 1;
public static final int MaxUInt22 = (1 << 22) - 1;
public static final int MaxUInt30 = (1 << 30) - 1;
public static final int MinSInt5 = -(1 << 4);
public static final int MaxSInt5 = (1 << 4) - 1;
public static final int MinSInt6 = -(1 << 5);
public static final int MaxSInt6 = (1 << 5) - 1;
public static final int MinSInt7 = -(1 << 6);
public static final int MaxSInt7 = (1 << 6) - 1;
public static final int MinSInt8 = -(1 << 7);
public static final int MaxSInt8 = (1 << 7) - 1;
public static final int MinSInt9 = -(1 << 8);
public static final int MaxSInt9 = (1 << 8) - 1;
public static final int MinSInt10 = -(1 << 9);
public static final int MaxSInt10 = (1 << 9) - 1;
public static final int MinSInt11 = -(1 << 10);
public static final int MaxSInt11 = (1 << 10) - 1;
public static final int MinSInt12 = -(1 << 11);
public static final int MaxSInt12 = (1 << 11) - 1;
public static final int MinSInt13 = -(1 << 12);
public static final int MaxSInt13 = (1 << 12) - 1;
public static final int MinSInt14 = -(1 << 13);
public static final int MaxSInt14 = (1 << 13) - 1;
public static final int MinSInt15 = -(1 << 14);
public static final int MaxSInt15 = (1 << 14) - 1;
public static final int MinSInt17 = -(1 << 16);
public static final int MaxSInt17 = (1 << 16) - 1;
public static final int MinSInt18 = -(1 << 17);
public static final int MaxSInt18 = (1 << 17) - 1;
public static final int MinSInt19 = -(1 << 18);
public static final int MaxSInt19 = (1 << 18) - 1;
public static final int MinSInt20 = -(1 << 19);
public static final int MaxSInt20 = (1 << 19) - 1;
public static final int MinSInt22 = -(1 << 21);
public static final int MaxSInt22 = (1 << 21) - 1;
private OutputStream os;
private long pos = 0;
public GFxOutputStream(OutputStream os) {
this.os = os;
}
public long getPos() {
return pos;
}
@Override
public void write(int b) throws IOException {
os.write(b);
pos++;
}
/**
* Writes SI32 (Signed 32bit integer) value to the stream
*
* @param value SI32 value
* @throws IOException
*/
public void writeSI32(long value) throws IOException {
writeUI32(value);
}
/**
* Writes SI16 (Signed 16bit integer) value to the stream
*
* @param value SI16 value
* @throws IOException
*/
public void writeSI16(int value) throws IOException {
writeUI16(value);
}
/**
* Writes SI8 (Signed 8bit integer) value to the stream
*
* @param value SI8 value
* @throws IOException
*/
public void writeSI8(int value) throws IOException {
writeUI8(value);
}
/**
* Writes UI32 (Unsigned 32bit integer) value to the stream
*
* @param value UI32 value
* @throws IOException
*/
public void writeUI32(long value) throws IOException {
write((int) (value & 0xff));
write((int) ((value >> 8) & 0xff));
write((int) ((value >> 16) & 0xff));
write((int) ((value >> 24) & 0xff));
}
/**
* Writes UI16 (Unsigned 16bit integer) value to the stream
*
* @param value UI16 value
* @throws IOException
*/
public void writeUI16(int value) throws IOException {
write((int) (value & 0xff));
write((int) ((value >> 8) & 0xff));
}
/**
* Writes UI8 (Unsigned 8bit integer) value to the stream
*
* @param val UI8 value to write
* @throws IOException
*/
public void writeUI8(int val) throws IOException {
write(val & 0xff);
}
/**
* Writes FLOAT (single precision floating point value) value to the stream
*
* @param value FLOAT value
* @throws IOException
*/
public void writeFLOAT(float value) throws IOException {
writeUI32(Float.floatToIntBits(value));
}
public void writeSI15(int v) throws IOException {
if (v >= MinSInt7 && v <= MaxSInt7) {
writeUI8(v << 1);
return;
}
writeUI8((v << 1) | 1);
writeUI8(v >> 7);
}
public void writeUI15(int v) throws IOException {
if (v <= MaxUInt7) {
writeUI8(v << 1);
return;
}
writeUI8((v << 1) | 1);
writeUI8(v >> 7);
}
public void writeUI30(int v) throws IOException {
if (v <= MaxUInt6) {
writeUI8(v << 2);
return;
}
if (v <= MaxUInt14) {
writeUI8((v << 2) | 1);
writeUI8(v >> 6);
return;
}
if (v <= MaxUInt22) {
writeUI8((v << 2) | 2);
writeUI8(v >> 6);
writeUI8(v >> 14);
return;
}
writeUI8((v << 2) | 3);
writeUI8(v >> 6);
writeUI8(v >> 14);
writeUI8(v >> 22);
}
}

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.IOException;
/**
@@ -38,7 +37,7 @@ public class GLYPHIDX {
this.indexInTexture = sis.readUI16();
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeUI16(indexInFont);
sos.writeUI16(indexInTexture);
}

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.IOException;
/**
@@ -41,7 +40,7 @@ public class GlyphInfoType {
this.globalOffset = sis.readUI32();
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeUI16(glyphCode);
sos.writeSI16(advanceX);
sos.writeUI32(globalOffset);

View File

@@ -16,8 +16,9 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
import java.io.IOException;
@@ -33,6 +34,32 @@ public class GlyphType {
public int[] boundingBox;
public ContourType[] contours;
public GlyphType(List<SHAPERECORD> records) {
RECT bounds = SHAPERECORD.getBounds(records);
boundingBox = new int[4];
boundingBox[0] = bounds.Xmin;
boundingBox[1] = bounds.Ymin;
boundingBox[2] = bounds.Xmax;
boundingBox[3] = bounds.Ymax;
List<SHAPERECORD> cont = new ArrayList<>();
List<ContourType> contoursList = new ArrayList<>();
for (int i = 0; i < records.size(); i++) {
SHAPERECORD r = records.get(i);
if ((r instanceof StyleChangeRecord) && ((StyleChangeRecord) r).stateMoveTo) {
if (!cont.isEmpty()) {
contoursList.add(new ContourType(cont));
cont.clear();
}
}
cont.add(r);
}
if (!cont.isEmpty()) {
contoursList.add(new ContourType(cont));
cont.clear();
}
contours = contoursList.toArray(new ContourType[contoursList.size()]);
}
public GlyphType(GFxInputStream sis) throws IOException {
boundingBox = new int[4];
for (int i = 0; i < 4; i++) {
@@ -48,19 +75,29 @@ public class GlyphType {
public SHAPE toSHAPE() {
SHAPE shp = new SHAPE();
shp.numFillBits = 1;
shp.numLineBits = 1;
shp.numLineBits = 0;
List<SHAPERECORD> recs = new ArrayList<>();
StyleChangeRecord scr = new StyleChangeRecord();
scr.fillStyle0 = 1;
scr.stateFillStyle0 = true;
scr.fillStyle0 = 0;
scr.fillStyle1 = 1;
scr.stateFillStyle1 = true;
scr.stateFillStyle0 = false;
recs.add(scr);
for (ContourType cnt : contours) {
recs.addAll(cnt.toSHAPERECORDS());
}
recs.add(new EndShapeRecord());
shp.shapeRecords = recs;
return shp;
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
for (int b : boundingBox) {
sos.writeSI15(b);
}
sos.writeUI15(contours.length);
for (ContourType cnt : contours) {
cnt.write(sos);
}
}
}

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.IOException;
/**
@@ -41,7 +40,7 @@ public class KerningPairType {
this.advance = sis.readSI16();
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeUI16(char1);
sos.writeUI16(char2);
sos.writeSI16(advance);

View File

@@ -16,7 +16,6 @@
*/
package com.jpexs.decompiler.flash.types.gfx;
import com.jpexs.decompiler.flash.SWFOutputStream;
import java.io.IOException;
/**
@@ -50,7 +49,7 @@ public class TEXGLYPH {
this.uvOriginY = sis.readFLOAT();
}
public void write(SWFOutputStream sos) throws IOException {
public void write(GFxOutputStream sos) throws IOException {
sos.writeFLOAT(uvBoundsLeft);
sos.writeFLOAT(uvBoundsTop);
sos.writeFLOAT(uvBoundsRight);

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.types.shaperecords;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFOutputStream;
/**
*
@@ -68,4 +69,12 @@ public class CurvedEdgeRecord extends SHAPERECORD {
public boolean isMove() {
return true;
}
@Override
public void calculateBits() {
numBits = SWFOutputStream.getNeededBitsS(controlDeltaX, controlDeltaY, anchorDeltaX, anchorDeltaY) - 2;
if (numBits < 0) {
numBits = 0;
}
}
}

View File

@@ -53,4 +53,8 @@ public class EndShapeRecord extends SHAPERECORD {
public boolean isMove() {
return false;
}
@Override
public void calculateBits() {
}
}

View File

@@ -32,6 +32,7 @@ import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.helpers.Cache;
import com.jpexs.helpers.Helper;
import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
@@ -73,10 +74,12 @@ import javax.swing.JPanel;
*
* @author JPEXS
*/
public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
public abstract class SHAPERECORD implements Cloneable, NeedsCharacters, Serializable {
private static final float DESCALE = 20;
public abstract void calculateBits();
@Override
public Set<Integer> getNeededCharacters() {
HashSet<Integer> ret = new HashSet<>();
@@ -847,10 +850,33 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
for (SHAPE s : shapes) {
images.add(s.toImage(1, new ArrayList<Tag>(), color));
}
int maxw = 0;
int maxh = 0;
for (BufferedImage im : images) {
if (im.getWidth() > maxw) {
maxw = im.getWidth();
}
if (im.getHeight() > maxh) {
maxh = im.getHeight();
}
}
int cols = (int) Math.ceil(Math.sqrt(images.size()));
int pos = 0;
int w2 = prevWidth / cols;
int h2 = prevHeight / cols;
int mh = maxh * w2 / maxw;
int mw;
if (mh > h2) {
mw = maxw * h2 / maxh;
mh = h2;
} else {
mw = w2;
}
float ratio = (float) mw / (float) maxw;
loopy:
for (int y = 0; y < cols; y++) {
for (int x = 0; x < cols; x++) {
@@ -861,16 +887,18 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
int h1 = images.get(pos).getHeight();
int h = h1 * w2 / w1;
int w;
if (h > h2) {
w = w1 * h2 / h1;
h = h2;
} else {
w = w2;
}
int px = x * w2 + w2 / 2 - w / 2;
int py = y * h2 + h2 / 2 - h / 2;
/*int h = h1 * mw / w1;
int w;
if (h > mh) {
w = w1 * mh / h1;
h = mh;
} else {
w = mw;
}*/
int w = Math.round(ratio * w1);
int h = Math.round(ratio * h1);
int px = x * mw + mw / 2 - w / 2;
int py = y * mh + mh - h;
g.drawImage(images.get(pos), px, py, px + w, py + h, 0, 0, w1, h1, null);
pos++;
}
@@ -1139,4 +1167,37 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters {
image = ImageIO.read(in);
}
}
public static SHAPE resizeSHAPE(SHAPE shp, int multiplier) {
SHAPE ret = new SHAPE();
ret.numFillBits = shp.numFillBits;
ret.numLineBits = shp.numLineBits;
List<SHAPERECORD> recs = new ArrayList<>();
for (SHAPERECORD r : shp.shapeRecords) {
SHAPERECORD c = (SHAPERECORD) Helper.deepCopy(r);
if (c instanceof StyleChangeRecord) {
StyleChangeRecord scr = (StyleChangeRecord) c;
scr.moveDeltaX = (multiplier * scr.moveDeltaX);
scr.moveDeltaY = (multiplier * scr.moveDeltaY);
scr.calculateBits();
}
if (c instanceof CurvedEdgeRecord) {
CurvedEdgeRecord cer = (CurvedEdgeRecord) c;
cer.controlDeltaX = (multiplier * cer.controlDeltaX);
cer.controlDeltaY = (multiplier * cer.controlDeltaY);
cer.anchorDeltaX = (multiplier * cer.anchorDeltaX);
cer.anchorDeltaY = (multiplier * cer.anchorDeltaY);
cer.calculateBits();
}
if (c instanceof StraightEdgeRecord) {
StraightEdgeRecord ser = (StraightEdgeRecord) c;
ser.deltaX = (multiplier * ser.deltaX);
ser.deltaY = (multiplier * ser.deltaY);
ser.calculateBits();
}
recs.add(c);
}
ret.shapeRecords = recs;
return ret;
}
}

View File

@@ -17,6 +17,7 @@
package com.jpexs.decompiler.flash.types.shaperecords;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFOutputStream;
/**
*
@@ -80,4 +81,12 @@ public class StraightEdgeRecord extends SHAPERECORD {
public boolean isMove() {
return true;
}
@Override
public void calculateBits() {
numBits = SWFOutputStream.getNeededBitsS(deltaX, deltaY) - 2;
if (numBits < 0) {
numBits = 0;
}
}
}

View File

@@ -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.types.FILLSTYLEARRAY;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import java.util.Set;
@@ -105,4 +106,9 @@ public class StyleChangeRecord extends SHAPERECORD implements Cloneable {
}
return null;
}
@Override
public void calculateBits() {
moveBits = SWFOutputStream.getNeededBitsS(moveDeltaX, moveDeltaY);
}
}