package com.jpexs.decompiler.flash.iggy.conversion; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFCompression; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.iggy.IggyShape; import com.jpexs.decompiler.flash.iggy.IggyCharKerning; import com.jpexs.decompiler.flash.iggy.IggyShapeNode; import com.jpexs.decompiler.flash.iggy.IggyCharOffset; import com.jpexs.decompiler.flash.iggy.IggyCharAdvances; import com.jpexs.decompiler.flash.iggy.IggyDeclStrings; import com.jpexs.decompiler.flash.iggy.IggyFile; import com.jpexs.decompiler.flash.iggy.IggyFont; import com.jpexs.decompiler.flash.iggy.IggySwf; import com.jpexs.decompiler.flash.iggy.IggyText; import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.DefineFont2Tag; import com.jpexs.decompiler.flash.tags.DoABC2Tag; import com.jpexs.decompiler.flash.tags.EndTag; import com.jpexs.decompiler.flash.tags.FileAttributesTag; import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; import com.jpexs.decompiler.flash.types.KERNINGRECORD; import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.SHAPE; import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; 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.ByteArrayRange; import java.awt.Color; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * * WIP * * @author JPEXS */ public class IggyToSwfConvertor { public static void exportAllSwfsToDir(IggyFile file, File outputDir) throws IOException { exportSwfToDir(file, outputDir); } public static void exportSwfToDir(IggyFile file, File outputDir) throws IOException { try (FileOutputStream fos = new FileOutputStream(new File(outputDir, file.getSwfName()))) { exportSwf(file, fos); } } public static void exportSwfToFile(IggyFile file, File outputFile) throws IOException { try (FileOutputStream fos = new FileOutputStream(outputFile)) { exportSwf(file, fos); } } public static void exportSwf(IggyFile file, OutputStream output) throws IOException { SWF swf = getSwf(file); swf.saveTo(output); } private static int makeLengthsEm(double val) { return (int) (val * 1024.0); } private static int makeLengthsTwip(double val) { return (int) (val * SWF.unitDivisor); } public static SWF getSwf(IggyFile file) { SWF swf = new SWF(); swf.compression = SWFCompression.NONE; swf.frameCount = 1; //FIXME!! swf.frameRate = file.getSwfFrameRate(); swf.gfx = false; swf.displayRect = new RECT( makeLengthsTwip(file.getSwfXMin()), makeLengthsTwip(file.getSwfXMax()), makeLengthsTwip(file.getSwfYMin()), makeLengthsTwip(file.getSwfYMax())); swf.version = 10; //FIXME FileAttributesTag fat = new FileAttributesTag(swf); fat.actionScript3 = true; fat.hasMetadata = false; fat.useNetwork = false; swf.addTag(fat); IggySwf iggySwf = file.getSwf(); int currentCharId = 0; Map<Integer, Integer> fontIndex2CharId = new HashMap<>(); for (int fontIndex = 0; fontIndex < iggySwf.getFonts().size(); fontIndex++) { IggyFont iggyFont = iggySwf.getFonts().get(fontIndex); DefineFont2Tag fontTag = new DefineFont2Tag(swf); currentCharId++; fontIndex2CharId.put(fontIndex, currentCharId); fontTag.fontID = currentCharId; /*System.out.println("==================="); System.out.println("xscale: " + iggyFont.getXscale()); //80 System.out.println("yscale: " + iggyFont.getYscale()); //19 System.out.println("unk_float1: " + iggyFont.getUnk_float()[0]); System.out.println("unk_float2: " + iggyFont.getUnk_float()[1]); System.out.println("unk_float3: " + iggyFont.getUnk_float()[2]); System.out.println("unk_float4: " + iggyFont.getUnk_float()[3]); System.out.println("unk_float5: " + iggyFont.getUnk_float()[4]); System.out.println("what_2: " + iggyFont.getWhat_2()); System.out.println("what_3: " + iggyFont.getWhat_3());*/ fontTag.fontKerningTable = new ArrayList<>(); IggyCharKerning ker = iggyFont.getCharKernings(); if (ker != null) { for (int i = 0; i < ker.getKernCount(); i++) { int kerningCode1 = ker.getCharsA().get(i); int kerningCode2 = ker.getCharsA().get(i); int kerningOffset = ker.getKerningOffsets().get(i); fontTag.fontKerningTable.add(new KERNINGRECORD(kerningCode1, kerningCode2, kerningOffset)); } } fontTag.fontFlagsWideCodes = true; fontTag.fontFlagsWideOffsets = true; fontTag.fontAscent = iggyFont.getAscent(); fontTag.fontDescent = iggyFont.getDescent(); fontTag.fontLeading = iggyFont.getLeading(); fontTag.codeTable = new ArrayList<>(); fontTag.fontName = iggyFont.getName(); fontTag.glyphShapeTable = new ArrayList<>(); fontTag.fontBoundsTable = new ArrayList<>(); fontTag.fontAdvanceTable = new ArrayList<>(); fontTag.fontFlagsHasLayout = true; IggyCharAdvances advanceValues = iggyFont.getCharAdvances(); for (int i = 0; i < iggyFont.getCharacterCount(); i++) { int code = iggyFont.getCharIndices().getChars().get(i); fontTag.codeTable.add(code); IggyShape glyph = iggyFont.getChars().get(i); SHAPE shp; if (glyph != null) { shp = IggyShapeToSwfConvertor.convertCharToShape(glyph); fontTag.fontBoundsTable.add(shp.getBounds()); } else { shp = new SHAPE(); shp.shapeRecords = new ArrayList<>(); shp.shapeRecords.add(new EndShapeRecord()); fontTag.fontBoundsTable.add(new RECT()); //?? } fontTag.glyphShapeTable.add(shp); fontTag.fontAdvanceTable.add(makeLengthsEm(advanceValues.getScales().get(i))); } fontTag.setModified(true); swf.addTag(fontTag); } Map<Integer, Integer> textIndex2CharId = new HashMap<>(); for (int textIndex = 0; textIndex < iggySwf.getTexts().size(); textIndex++) { IggyText iggyText = iggySwf.getTexts().get(textIndex); DefineEditTextTag textTag = new DefineEditTextTag(swf); currentCharId++; textIndex2CharId.put(textIndex, currentCharId); textTag.characterID = currentCharId; textTag.hasText = true; textTag.initialText = iggyText.getInitialText(); textTag.html = true; textTag.noSelect = true; textTag.wasStatic = true; textTag.hasFont = false; textTag.hasFontClass = false; textTag.hasMaxLength = false; //textTag.multiline = true; //textTag.wordWrap = true; //textTag.hasTextColor = true; //textTag.textColor = new RGBA(Color.black); //textTag.fontHeight = 40; //?? textTag.readOnly = true; textTag.bounds = new RECT( makeLengthsTwip(iggyText.getPar1()), makeLengthsTwip(iggyText.getPar3()), makeLengthsTwip(iggyText.getPar2()), makeLengthsTwip(iggyText.getPar4()) ); //textTag.hasFont = true; //textTag.fontId = fontIndex2CharId.get(iggyText.getFontIndex()); textTag.setModified(true); swf.addTag(textTag); } IggyDeclStrings declStrings = iggySwf.getDeclStrings(); if (declStrings != null) { byte[] abcData = declStrings.getData(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { baos.write(new byte[]{1, 0, 0, 0, 0, 0x10, 0, 0x2E}); baos.write(abcData); } catch (IOException ex) { //should not happen } byte[] fullAbcTagData = baos.toByteArray(); try { DoABC2Tag nabc = new DoABC2Tag(new SWFInputStream(swf, fullAbcTagData), new ByteArrayRange(fullAbcTagData)); nabc.setModified(true); swf.addTag(nabc); } catch (IOException ex) { //ignore } } swf.addTag( new EndTag(swf)); swf.setModified( true); return swf; } public static void main(String[] args) { if (args.length < 2 || (args[0].isEmpty() || args[1].isEmpty())) { System.err.println("Invalid arguments"); System.err.println("Usage: iggy-extract.bat file.iggy d:/outdir/"); System.exit(1); } File file = new File(args[0]); if (!file.exists()) { System.err.println("FAIL: Input file: " + file.getAbsolutePath() + " does not exist."); System.exit(1); } File outDir = new File(args[1]); if (!outDir.exists()) { if (!outDir.mkdirs()) { System.err.println("FAIL: Cannot create output directory"); System.exit(1); } } try { System.out.print("(1/2) Loading file " + args[0] + "..."); IggyFile iggyFile = new IggyFile(new File(args[0])); System.out.println("OK"); System.out.print("(2/2) Exporting SWF files to " + args[1] + "..."); exportAllSwfsToDir(iggyFile, new File(args[1])); System.out.println("OK"); System.out.println("All finished sucessfully."); System.exit(0); } catch (IOException ex) { System.out.println("FAIL"); System.err.println("Error while converting: " + ex.getMessage()); System.exit(1); } } }