diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index a6e936796..a304802ba 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -1978,8 +1978,8 @@ public class SWFInputStream extends InputStream { */ public BEVELFILTER readBEVELFILTER() throws IOException { BEVELFILTER ret = new BEVELFILTER(); + ret.highlightColor = readRGBA(); //Highlight color first. It it opposite of the documentation ret.shadowColor = readRGBA(); - ret.highlightColor = readRGBA(); ret.blurX = readFIXED(); ret.blurY = readFIXED(); ret.angle = readFIXED(); diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java index c12292f3a..a88bb6332 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -824,8 +824,8 @@ public class SWFOutputStream extends OutputStream { * @throws IOException */ public void writeBEVELFILTER(BEVELFILTER value) throws IOException { - writeRGBA(value.shadowColor); writeRGBA(value.highlightColor); + writeRGBA(value.shadowColor); writeFIXED(value.blurX); writeFIXED(value.blurY); writeFIXED(value.angle); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java index ba15d75bd..279b212b2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/CSMTextSettingsTag.java @@ -33,8 +33,8 @@ public class CSMTextSettingsTag extends Tag { public int textID; public int useFlashType; public int gridFit; - public double thickness; - public double sharpness; + public float thickness; + public float sharpness; /** * Gets data bytes @@ -52,8 +52,8 @@ public class CSMTextSettingsTag extends Tag { sos.writeUB(2, useFlashType); sos.writeUB(3, gridFit); sos.writeUB(3, 0); - sos.writeFIXED(thickness); //TODO:write F32 - sos.writeFIXED(sharpness); //TODO:write F32 + sos.writeFLOAT(thickness); //F32 = FLOAT + sos.writeFLOAT(sharpness); //F32 = FLOAT sos.writeUI8(0); } catch (IOException e) { } @@ -74,8 +74,8 @@ public class CSMTextSettingsTag extends Tag { useFlashType = (int) sis.readUB(2); gridFit = (int) sis.readUB(3); sis.readUB(3); //reserved - thickness = sis.readFIXED(); //TODO: read F32 - sharpness = sis.readFIXED(); //TODO: read F32 + thickness = sis.readFLOAT(); //F32 = FLOAT + sharpness = sis.readFLOAT(); //F32 = FLOAT sis.readUI8(); //reserved } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java index fff9929c1..a84d485a7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont2Tag.java @@ -59,6 +59,11 @@ public class DefineFont2Tag extends CharacterTag implements FontTag { public RECT fontBoundsTable[]; public KERNINGRECORD fontKerningTable[]; + @Override + public boolean isSmall() { + return fontFlagsSmallText; + } + @Override public int getGlyphWidth(int glyphIndex) { return glyphShapeTable[glyphIndex].getBounds().getWidth(); @@ -246,9 +251,13 @@ public class DefineFont2Tag extends CharacterTag implements FontTag { public int charToGlyph(List tags, char c) { return codeTable.indexOf((Integer) (int) c); } - + @Override - public String getFontName(List tags){ - return fontName; + public String getFontName(List tags) { + String ret = fontName; + if (ret.contains("" + (char) 0)) { + ret = ret.substring(0, ret.indexOf(0)); + } + return ret; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java index 4d1c6ee14..2b36a3744 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFont3Tag.java @@ -57,6 +57,11 @@ public class DefineFont3Tag extends CharacterTag implements FontTag { public RECT fontBoundsTable[]; public KERNINGRECORD fontKerningTable[]; + @Override + public boolean isSmall() { + return fontFlagsSmallText; + } + @Override public int getGlyphWidth(int glyphIndex) { return glyphShapeTable[glyphIndex].getBounds().getWidth() / 20; @@ -246,9 +251,13 @@ public class DefineFont3Tag extends CharacterTag implements FontTag { public int getCharacterID() { return fontId; } - + @Override - public String getFontName(List tags){ - return fontName; + public String getFontName(List tags) { + String ret = fontName; + if (ret.contains("" + (char) 0)) { + ret = ret.substring(0, ret.indexOf(0)); + } + return ret; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java index 1328c9596..2e3a08854 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontInfo2Tag.java @@ -67,7 +67,7 @@ public class DefineFontInfo2Tag extends Tag { sos.writeUB(1, fontFlagsBold ? 1 : 0); sos.writeUB(1, fontFlagsWideCodes ? 1 : 0); sos.writeLANGCODE(languageCode); - for (int c:codeTable) { + for (int c : codeTable) { sos.writeUI16(c); } } catch (IOException e) { @@ -96,7 +96,7 @@ public class DefineFontInfo2Tag extends Tag { fontFlagsBold = sis.readUB(1) == 1; fontFlagsWideCodes = sis.readUB(1) == 1; //Always 1 languageCode = sis.readLANGCODE(); - int ctLen= sis.available() / 2; + int ctLen = sis.available() / 2; codeTable = new ArrayList(); for (int i = 0; i < ctLen; i++) { codeTable.add(sis.readUI16()); diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java index 931e9ea75..c3849b56b 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineFontTag.java @@ -40,6 +40,11 @@ public class DefineFontTag extends CharacterTag implements FontTag { private DefineFontInfoTag fontInfoTag = null; private DefineFontInfo2Tag fontInfo2Tag = null; + @Override + public boolean isSmall() { + return false; + } + @Override public int getGlyphAdvance(int glyphIndex) { return getGlyphWidth(glyphIndex); @@ -74,7 +79,7 @@ public class DefineFontTag extends CharacterTag implements FontTag { ensureFontInfo(tags); if (fontInfo2Tag != null) { return (char) (int) fontInfo2Tag.codeTable.get(glyphIndex); - }else if (fontInfoTag != null) { + } else if (fontInfoTag != null) { return (char) (int) fontInfoTag.codeTable.get(glyphIndex); } else { return '?'; @@ -84,13 +89,13 @@ public class DefineFontTag extends CharacterTag implements FontTag { @Override public int charToGlyph(List tags, char c) { ensureFontInfo(tags); - if(fontInfo2Tag!=null){ + if (fontInfo2Tag != null) { return fontInfo2Tag.codeTable.indexOf(c); - }else if(fontInfoTag!=null){ + } else if (fontInfoTag != null) { return fontInfoTag.codeTable.indexOf(c); } return -1; - + } /** @@ -155,16 +160,16 @@ public class DefineFontTag extends CharacterTag implements FontTag { public int getCharacterID() { return fontId; } - + @Override - public String getFontName(List tags){ + public String getFontName(List tags) { ensureFontInfo(tags); - if(fontInfo2Tag!=null){ + if (fontInfo2Tag != null) { return fontInfo2Tag.fontName; } - if(fontInfoTag!=null){ + if (fontInfoTag != null) { return fontInfoTag.fontName; - } + } return null; } } diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java index cd4ecb264..a03bbc2bc 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/base/FontTag.java @@ -37,6 +37,8 @@ public interface FontTag extends AloneTag { public int getGlyphAdvance(int glyphIndex); public int getGlyphWidth(int glyphIndex); - + public String getFontName(List tags); + + public boolean isSmall(); } diff --git a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 900c85152..bf65b41ae 100644 --- a/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/trunk/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -19,7 +19,9 @@ package com.jpexs.decompiler.flash.xfl; import com.jpexs.decompiler.flash.Main; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.tags.ABCContainerTag; +import com.jpexs.decompiler.flash.tags.CSMTextSettingsTag; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.DefineFontNameTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DefineText2Tag; @@ -69,10 +71,12 @@ import java.awt.Font; import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.io.StringReader; import java.io.StringWriter; import java.io.UnsupportedEncodingException; @@ -87,12 +91,19 @@ import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.imageio.ImageIO; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; /** * @@ -767,8 +778,8 @@ public class XFLConverter { } else if (tag instanceof DefineSpriteTag) { DefineSpriteTag sprite = (DefineSpriteTag) tag; RECT spriteRect = sprite.getRect(characters); - double centerPoint3DX = ((double) (matrix.translateX + spriteRect.getWidth() / 2)) / 20.0; - double centerPoint3DY = ((double) (matrix.translateY + spriteRect.getHeight() / 2)) / 20.0; + double centerPoint3DX = twipToPixel(matrix.translateX + spriteRect.getWidth() / 2); + double centerPoint3DY = twipToPixel(matrix.translateY + spriteRect.getHeight() / 2); ret += " centerPoint3DX=\"" + centerPoint3DX + "\" centerPoint3DY=\"" + centerPoint3DY + "\""; } else if (tag instanceof ButtonTag) { ret += " symbolType=\"button\""; @@ -998,7 +1009,8 @@ public class XFLConverter { transformer.transform(xmlInput, xmlOutput); return xmlOutput.getWriter().toString(); } catch (Exception e) { - throw new RuntimeException(e); // simple exception handling, please review it + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Pretty print error", e); + return input; } } @@ -1024,7 +1036,7 @@ public class XFLConverter { if ((ch instanceof ShapeTag) && oneInstanceShapes.contains(characterId)) { elements += convertShape(characters, po.getMatrix(), (ShapeTag) ch); } else if (ch instanceof TextTag) { - elements += convertText(tags, (TextTag) ch, po.getMatrix()); + elements += convertText(tags, (TextTag) ch, po.getMatrix(), po.getFilters()); } else { elements += convertSymbolInstance(po.getName(), po.getMatrix(), po.getColorTransform(), po.getColorTransformWithAlpha(), po.getBlendMode(), po.getFilters(), characters.get(characterId), characters); } @@ -1184,24 +1196,76 @@ public class XFLConverter { return ret; } - public static String convertText(List tags, TextTag tag, MATRIX matrix) { + public static String convertText(List tags, TextTag tag, MATRIX matrix, List filters) { String ret = ""; if (matrix == null) { matrix = new MATRIX(); } + CSMTextSettingsTag csmts = null; + String filterStr = ""; + if (!filters.isEmpty()) { + filterStr += ""; + for (FILTER f : filters) { + filterStr += convertFilter(f); + } + filterStr += ""; + } + + for (Tag t : tags) { + if (t instanceof CSMTextSettingsTag) { + CSMTextSettingsTag c = (CSMTextSettingsTag) t; + if (c.textID == tag.getCharacterID()) { + csmts = c; + break; + } + } + } + String fontRenderingMode = "standard"; + String antiAlias = ""; + if (csmts != null) { + if (csmts.thickness == 0 & csmts.sharpness == 0) { + fontRenderingMode = null; + } else { + fontRenderingMode = "customThicknessSharpness"; + } + antiAlias = " antiAliasSharpness=\"" + doubleToString(csmts.sharpness) + "\" antiAliasThickness=\"" + doubleToString(csmts.thickness) + "\""; + } String matStr = ""; matStr += ""; matStr += convertMatrix(matrix); matStr += ""; if ((tag instanceof DefineTextTag) || (tag instanceof DefineText2Tag)) { - ret += ""; - ret += matStr; List textRecords = new ArrayList(); if (tag instanceof DefineTextTag) { textRecords = ((DefineTextTag) tag).textRecords; } else if (tag instanceof DefineText2Tag) { textRecords = ((DefineText2Tag) tag).textRecords; } + looprec: + for (TEXTRECORD rec : textRecords) { + if (rec.styleFlagsHasFont) { + for (Tag t : tags) { + if (t instanceof FontTag) { + FontTag ft = (FontTag) t; + if (ft.getFontId() == rec.fontId) { + if (ft.isSmall()) { + fontRenderingMode = "bitmap"; + break looprec; + } + } + } + } + } + } + + ret += ""; + ret += matStr; + ret += ""; int fontId = -1; FontTag font = null; @@ -1250,10 +1314,10 @@ public class XFLConverter { } } ret += ""; - ret += "" + rec.getText(tags, font) + ""; + ret += "" + xmlString(rec.getText(tags, font)) + ""; ret += ""; - ret += ""; } - //TODO:DefineEditText return ret; } @@ -1350,8 +1483,8 @@ public class XFLConverter { + " " + baseName + "_alternate.html\n" + " 0\n" + " \n" - + " " + (swf.displayRect.getWidth() / 20) + "\n" - + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 0\n" + " 1\n" @@ -1435,8 +1568,8 @@ public class XFLConverter { + " \n" + " \n" + " \n" - + " " + (swf.displayRect.getWidth() / 20) + "\n" - + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 4718592\n" + " 0\n" @@ -1461,8 +1594,8 @@ public class XFLConverter { + " 1\n" + " \n" + " \n" - + " " + (swf.displayRect.getWidth() / 20) + "\n" - + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 0\n" + " 1\n" + " 1\n" @@ -1480,8 +1613,8 @@ public class XFLConverter { + " \n" + " \n" + " \n" - + " " + (swf.displayRect.getWidth() / 20) + "\n" - + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 1\n" + " 0\n" + " 0\n" @@ -1497,8 +1630,8 @@ public class XFLConverter { + " \n" + " \n" + " \n" - + " " + (swf.displayRect.getWidth() / 20) + "\n" - + " " + (swf.displayRect.getHeight() / 20) + "\n" + + " " + twipToPixel(swf.displayRect.getWidth()) + "\n" + + " " + twipToPixel(swf.displayRect.getHeight()) + "\n" + " 1\n" + " 0\n" + " \n" @@ -1674,4 +1807,216 @@ public class XFLConverter { return ""; } + + private static String convertHTMLText(List tags, DefineEditTextTag det, String html) { + HTMLTextParser tparser = new HTMLTextParser(tags, det); + try { + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setValidating(false); + + SAXParser parser = factory.newSAXParser(); + + XMLReader reader = parser.getXMLReader(); + + + reader.setContentHandler(tparser); + reader.setErrorHandler(tparser); + reader.parse(new InputSource(new InputStreamReader(new ByteArrayInputStream(html.getBytes("UTF-8")), "UTF-8"))); + } catch (Exception e) { + Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error while converting HTML", e); + } + return tparser.result; + } + + private static String xmlString(String s) { + return s.replace("<", "<").replace(">", ">").replace("\"", """).replace("&", "&").replace("\r\n", " ").replace("\r", " ").replace("\n", " "); + } + + private static double twipToPixel(double tw) { + return tw / 20.0; + } + + private static class HTMLTextParser extends DefaultHandler { + + public String result = ""; + private String fontFace = ""; + private String color = ""; + private int size = -1; + private int indent = -1; + private int leftMargin = -1; + private int rightMargin = -1; + private int lineSpacing = -1; + private double letterSpacing = -1; + private String alignment = null; + private List tags; + private boolean bold = false; + private boolean italic = false; + private boolean underline = false; + private boolean li = false; + private String url = null; + private String target = null; + + public HTMLTextParser(List tags, DefineEditTextTag det) { + if (det.hasLayout) { + leftMargin = det.leftMargin; + rightMargin = det.rightMargin; + indent = det.indent; + lineSpacing = det.leading; + String alignNames[] = {"left", "right", "center", "justify"}; + alignment = alignNames[det.align]; + } + this.tags = tags; + } + + @Override + public void startDocument() throws SAXException { + } + + @Override + public void startElement(String uri, String localName, + String qName, Attributes attributes) throws SAXException { + if (qName.equals("a")) { + String href = attributes.getValue("href"); + if (href != null) { + url = href; + } + String t = attributes.getValue("target"); + if (t != null) { + target = t; + } + } else if (qName.equals("b")) { + bold = true; + } else if (qName.equals("i")) { + italic = true; + } else if (qName.equals("u")) { + underline = true; + } else if (qName.equals("li")) { + li = true; + } else if (qName.equals("p")) { + String a = attributes.getValue("align"); + if (a != null) { + alignment = a; + } + if (!result.equals("")) { + putText("\r\n"); + } + } else if (qName.equals("font")) { + //kerning ? + String ls = attributes.getValue("letterSpacing"); + if (ls != null) { + letterSpacing = Double.parseDouble(ls); + } + String s = attributes.getValue("size"); + if (s != null) { + size = Integer.parseInt(s); + } + String c = attributes.getValue("color"); + if (c != null) { + color = c; + } + String f = attributes.getValue("face"); + if (f != null) { + for (Tag t : tags) { + if (t instanceof FontTag) { + FontTag ft = (FontTag) t; + String fontName = ""; + if (f.equals(ft.getFontName(tags))) { + for (Tag u : tags) { + if (u instanceof DefineFontNameTag) { + if (((DefineFontNameTag) u).fontId == ft.getFontId()) { + fontName = ((DefineFontNameTag) u).fontName; + } + } + } + if (fontName == null) { + fontName = ft.getFontName(tags); + } + fontFace = new Font(fontName, (italic ? Font.ITALIC : 0) | (bold ? Font.BOLD : 0) | (!italic && !bold ? Font.PLAIN : 0), size < 0 ? 10 : size).getPSName(); + break; + } + } + } + } + } + //textformat,tab,br + } + + @Override + public void endElement(String uri, String localName, + String qName) throws SAXException { + if (qName.equals("a")) { + url = null; + target = null; + } + if (qName.equals("b")) { + bold = false; + } + if (qName.equals("i")) { + italic = false; + } + if (qName.equals("u")) { + underline = false; + } + if (qName.equals("li")) { + li = false; + } + } + + private void putText(String txt) { + + result += ""; + result += "" + xmlString(txt) + ""; + result += ""; + result += " -1) { + result += " indent=\"" + twipToPixel(indent) + "\""; + } + if (leftMargin > -1) { + result += " leftMargin=\"" + twipToPixel(leftMargin) + "\""; + } + if (letterSpacing > -1) { + result += " letterSpacing=\"" + letterSpacing + "\""; + } + if (lineSpacing > -1) { + result += " lineSpacing=\"" + twipToPixel(lineSpacing) + "\""; + } + if (rightMargin > -1) { + result += " rightMargin=\"" + twipToPixel(rightMargin) + "\""; + } + if (size > -1) { + result += " size=\"" + size + "\""; + result += " bitmapSize=\"" + (size * 20) + "\""; + } + if (fontFace != null) { + result += " face=\"" + fontFace + "\""; + } + if (color != null) { + result += " fillColor=\"" + color + "\""; + } + if (url != null) { + result += " url=\"" + url + "\""; + } + if (target != null) { + result += " target=\"" + target + "\""; + } + result += "/>"; + result += ""; + result += ""; + } + + @Override + public void characters(char[] ch, int start, int length) + throws SAXException { + putText(new String(ch, start, length)); + + } + + @Override + public void endDocument() { + } + } }