diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java index bdf7fac91..9177628ea 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -166,6 +166,7 @@ public class SWFInputStream extends InputStream { return readNoBitReset(); } catch (EndOfStreamException ex) { Logger.getLogger(SWFInputStream.class.getName()).log(Level.SEVERE, null, ex); + System.exit(1); } return -1; } @@ -953,6 +954,36 @@ public class SWFInputStream extends InputStream { case 94: ret = new PlaceObject4Tag(swf, data, version, pos); break; + case 1000: + ret = new GFxExporterInfoTag(swf, data, version, pos); + break; + case 1001: + ret = new GFxDefineExternalImage(swf, data, version, pos); + break; + case 1002: + ret = new GFxFontTextureInfo(swf, data, version, pos); + break; + case 1003: + ret = new GFxDefineExternalGradient(swf, data, version, pos); + break; + case 1004: + ret = new GFxDefineGradientMap(swf, data, version, pos); + break; + case 1005: + ret = new GFxDefineCompactedFont(swf, data, version, pos); + break; + case 1006: + ret = new GFxDefineExternalSound(swf, data, version, pos); + break; + case 1007: + ret = new GFxDefineExternalStreamSound(swf, data, version, pos); + break; + case 1008: + ret = new GFxDefineSubImage(swf, data, version, pos); + break; + case 1009: + ret = new GFxDefineExternalImage2(swf, data, version, pos); + break; default: ret = new Tag(swf, tag.getId(), "Unknown", data, pos); } diff --git a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java index 09641695f..11a787200 100644 --- a/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java +++ b/trunk/src/com/jpexs/decompiler/flash/abc/types/traits/TraitFunction.java @@ -43,7 +43,7 @@ public class TraitFunction extends Trait implements TraitWithSlot { @Override public String convertHeader(Trait parent, String path, List abcTags, ABC abc, boolean isStatic, boolean pcode, int scriptIndex, int classIndex, boolean highlight, List fullyQualifiedNames, boolean parallel) { - String modifier = getModifiers(abcTags, abc, isStatic) + " "; + String modifier = getModifiers(abcTags, abc, isStatic) + " "; MethodBody body = abc.findBody(method_info); if (body == null) { modifier = "native " + modifier; diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java index 98664303a..d77214fec 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/MainFrame.java @@ -67,6 +67,7 @@ import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.EndTag; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; +import com.jpexs.decompiler.flash.tags.GFxDefineCompactedFont; import com.jpexs.decompiler.flash.tags.JPEGTablesTag; import com.jpexs.decompiler.flash.tags.PlaceObject2Tag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; @@ -1801,7 +1802,8 @@ public class MainFrame extends AppRibbonFrame implements ActionListener, TreeSel if ((t instanceof DefineFontTag) || (t instanceof DefineFont2Tag) || (t instanceof DefineFont3Tag) - || (t instanceof DefineFont4Tag)) { + || (t instanceof DefineFont4Tag) + || (t instanceof GFxDefineCompactedFont)) { return "font"; } if ((t instanceof DefineTextTag) diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineCompactedFont.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineCompactedFont.java new file mode 100644 index 000000000..858ed4c09 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineCompactedFont.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2010-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 . + */ +package com.jpexs.decompiler.flash.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.DrawableTag; +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.shaperecords.SHAPERECORD; +import java.awt.Color; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Stack; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineCompactedFont extends CharacterTag implements DrawableTag { + + public static final int ID = 1005; + public int fontId; + public List fonts; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @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();*/ + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineCompactedFont(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineCompactedFont", data, pos); + + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + fontId = sis.readUI16(); + fonts = new ArrayList<>(); + + while (sis.available() > 0) { + fonts.add(new FontType(new GFxInputStream(sis))); + } + } + + @Override + public BufferedImage toImage(int frame, List tags, RECT displayRect, HashMap characters, Stack visited) { + List shapes = new ArrayList<>(); + for (FontType f : fonts) { + shapes.addAll(f.getGlyphShapes()); + } + return SHAPERECORD.shapeListToImage(shapes, 500, 500, Color.black); + } + + @Override + public Point getImagePos(int frame, HashMap characters, Stack visited) { + return new Point(0, 0); + } + + @Override + public int getNumFrames() { + return 1; + } + + public String getFontName(List tags) { + String ret = ""; + for (int i = 0; i < fonts.size(); i++) { + if (i > 0) { + ret += ", "; + } + ret += fonts.get(i).fontName; + } + return ret; + } + + @Override + public String getName(List tags) { + String nameAppend = ""; + String fontName = getFontName(tags); + if (fontName != null) { + nameAppend = ": " + fontName; + } + return name + " (" + getCharacterId() + nameAppend + ")"; + } + + @Override + public int getCharacterId() { + return fontId; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalGradient.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalGradient.java new file mode 100644 index 000000000..eeab24654 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalGradient.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineExternalGradient extends Tag { + + public static final int ID = 1003; + public static final int BITMAP_FORMAT_DEFAULT = 0; + public static final int BITMAP_FORMAT_TGA = 1; + public static final int BITMAP_FORMAT_DDS = 2; + public int gradientId; + public int bitmapsFormat; + public int gradientSize; + public String fileName; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(gradientId); + sos.writeUI16(bitmapsFormat); + sos.writeUI16(gradientSize); + byte fileNameBytes[] = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineExternalGradient(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineExternalGradient", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + gradientId = sis.readUI16(); + bitmapsFormat = sis.readUI16(); + gradientSize = sis.readUI16(); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage.java new file mode 100644 index 000000000..cbc82be72 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineExternalImage extends Tag { + + public static final int ID = 1001; + public int characterId; + public int bitmapFormat; + public int targetWidth; + public int targetHeight; + public String fileName; + public static final int BITMAP_FORMAT_DEFAULT = 0; + public static final int BITMAP_FORMAT_TGA = 1; + public static final int BITMAP_FORMAT_DDS = 2; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(characterId); + sos.writeUI16(bitmapFormat); + sos.writeUI16(targetWidth); + sos.writeUI16(targetHeight); + byte fileNameBytes[] = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineExternalImage(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineExternalImage", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + characterId = sis.readUI16(); + bitmapFormat = sis.readUI16(); + targetWidth = sis.readUI16(); + targetHeight = sis.readUI16(); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage2.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage2.java new file mode 100644 index 000000000..d7f02ed96 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalImage2.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineExternalImage2 extends Tag { + + public static final int ID = 1009; + public long characterId; + public int bitmapFormat; + public int targetWidth; + public int targetHeight; + public String fileName; + public static final int BITMAP_FORMAT_DEFAULT = 0; + public static final int BITMAP_FORMAT_TGA = 1; + public static final int BITMAP_FORMAT_DDS = 2; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI32(characterId); + sos.writeUI16(bitmapFormat); + sos.writeUI16(targetWidth); + sos.writeUI16(targetHeight); + byte fileNameBytes[] = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineExternalImage2(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineExternalImage2", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + characterId = sis.readUI32(); + bitmapFormat = sis.readUI16(); + targetWidth = sis.readUI16(); + targetHeight = sis.readUI16(); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalSound.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalSound.java new file mode 100644 index 000000000..21e657c4e --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalSound.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineExternalSound extends Tag { + + public static final int ID = 1006; + public int characterId; + public int soundFormat; + public int bits; + public int channels; + public long sampleRate; + public long sampleCount; + public long seekSample; + public String exportName; + public String fileName; + public static final int SOUND_FORMAT_WAV = 0; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(characterId); + sos.writeUI16(soundFormat); + sos.writeUI16(bits); + sos.writeUI16(channels); + sos.writeUI32(sampleRate); + sos.writeUI32(sampleCount); + sos.writeUI32(seekSample); + byte[] exportNameBytes = exportName.getBytes(); + sos.writeUI8(exportNameBytes.length); + sos.write(exportNameBytes); + byte[] fileNameBytes = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineExternalSound(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineExternalSound", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + characterId = sis.readUI16(); + soundFormat = sis.readUI16(); + bits = sis.readUI16(); + channels = sis.readUI16(); + sampleRate = sis.readUI32(); + sampleCount = sis.readUI32(); + seekSample = sis.readUI32(); + int exportNameLen = sis.readUI8(); + exportName = new String(sis.readBytes(exportNameLen)); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalStreamSound.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalStreamSound.java new file mode 100644 index 000000000..c62b25e25 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineExternalStreamSound.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineExternalStreamSound extends Tag { + + public static final int ID = 1007; + public int soundFormat; + public int bits; + public int channels; + public long sampleRate; + public long sampleCount; + public long seekSample; + public long startFrame; + public long lastFrame; + public String fileName; + public static final int SOUND_FORMAT_WAV = 0; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(soundFormat); + sos.writeUI16(bits); + sos.writeUI16(channels); + sos.writeUI32(sampleRate); + sos.writeUI32(sampleCount); + sos.writeUI32(seekSample); + sos.writeUI32(startFrame); + sos.writeUI32(lastFrame); + byte[] fileNameBytes = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineExternalStreamSound(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineExternalStreamSound", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + soundFormat = sis.readUI16(); + bits = sis.readUI16(); + channels = sis.readUI16(); + sampleRate = sis.readUI32(); + sampleCount = sis.readUI32(); + seekSample = sis.readUI32(); + startFrame = sis.readUI32(); + lastFrame = sis.readUI32(); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineGradientMap.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineGradientMap.java new file mode 100644 index 000000000..c0a6908c9 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineGradientMap.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineGradientMap extends Tag { + + public static final int ID = 1004; + public int indices[]; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(indices.length); + for (int i = 0; i < indices.length; i++) { + sos.writeUI16(indices[i]); + } + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineGradientMap(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineGradientMap", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + int numGradients = sis.readUI16(); + indices = new int[numGradients]; + for (int i = 0; i < numGradients; i++) { + indices[i] = sis.readUI16(); + } + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineSubImage.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineSubImage.java new file mode 100644 index 000000000..e88fee478 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxDefineSubImage.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxDefineSubImage extends Tag { + + public static final int ID = 1008; + public int characterId; + public int imageCharacterId; + public int x1; + public int y1; + public int x2; + public int y2; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(characterId); + sos.writeUI16(imageCharacterId); + sos.writeUI16(x1); + sos.writeUI16(y1); + sos.writeUI16(x2); + sos.writeUI16(y2); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxDefineSubImage(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "DefineSubImage", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + characterId = sis.readUI16(); + imageCharacterId = sis.readUI16(); + x1 = sis.readUI16(); + y1 = sis.readUI16(); + x2 = sis.readUI16(); + y2 = sis.readUI16(); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxExporterInfoTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxExporterInfoTag.java new file mode 100644 index 000000000..6b05c9fe7 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxExporterInfoTag.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010-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 . + */ +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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxExporterInfoTag extends Tag { + + public static final int ID = 1000; + //Version (1.10 will be encoded as 0x10A) + public int version; + //Version 1.10 (0x10A) and above - flags + public long flags; + public int bitmapFormat; + public byte[] prefix; + public String swfName; + public static final int BITMAP_FORMAT_TGA = 1; + public static final int BITMAP_FORMAT_DDS = 2; + public static final int FLAG_CONTAINS_GLYPH_TEXTURES = 1; + public static final int FLAG_GLYPHS_STRIPPED_FROM_DEFINEFONT = 2; + public static final int FLAG_GRADIENT_IMAGES_EXPORTED = 4; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI16(version); + if (version >= 0x10a) { + sos.writeUI32(flags); + } + sos.writeUI16(bitmapFormat); + sos.writeUI8(prefix.length); + sos.write(prefix); + byte swfNameBytes[] = swfName.getBytes(); + sos.writeUI8(swfNameBytes.length); + sos.write(swfNameBytes); + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxExporterInfoTag(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "ExporterInfo", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + version = sis.readUI16(); + if (version >= 0x10a) { + flags = sis.readUI32(); + } + bitmapFormat = sis.readUI16(); + int prefixLen = sis.readUI8(); + prefix = sis.readBytes(prefixLen); + int swfNameLen = sis.readUI8(); + swfName = new String(sis.readBytes(swfNameLen)); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/GFxFontTextureInfo.java b/trunk/src/com/jpexs/decompiler/flash/tags/GFxFontTextureInfo.java new file mode 100644 index 000000000..581508e8b --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/tags/GFxFontTextureInfo.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010-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 . + */ +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.types.gfx.FONTINFO; +import com.jpexs.decompiler.flash.types.gfx.GFxInputStream; +import com.jpexs.decompiler.flash.types.gfx.TEXGLYPH; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * + * + * @author JPEXS + */ +public class GFxFontTextureInfo extends Tag { + + public static final int ID = 1002; + public long textureID; + public int textureFormat; + public String fileName; + public int textureWidth; + public int textureHeight; + public int padPixels; + public int nominalGlyphSz; + public TEXGLYPH texGlyphs[]; + public FONTINFO fonts[]; + public static final int TEXTURE_FORMAT_DEFAULT = 0; + public static final int TEXTURE_FORMAT_TGA = 1; + public static final int TEXTURE_FORMAT_DDS = 2; + + /** + * Gets data bytes + * + * @param version SWF version + * @return Bytes of data + */ + @Override + public byte[] getData(int version) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, version); + try { + sos.writeUI32(textureID); + sos.writeUI16(textureFormat); + byte fileNameBytes[] = fileName.getBytes(); + sos.writeUI8(fileNameBytes.length); + sos.write(fileNameBytes); + sos.writeUI16(textureWidth); + sos.writeUI16(textureHeight); + sos.writeUI8(padPixels); + sos.writeUI16(nominalGlyphSz); + sos.writeUI16(texGlyphs.length); + for (int i = 0; i < texGlyphs.length; i++) { + texGlyphs[i].write(sos); + } + sos.writeUI16(fonts.length); + for (int i = 0; i < fonts.length; i++) { + fonts[i].write(sos); + } + } catch (IOException e) { + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + * @param data Data bytes + * @param version SWF version + * @param pos + * @throws IOException + */ + public GFxFontTextureInfo(SWF swf, byte[] data, int version, long pos) throws IOException { + super(swf, ID, "FontTextureInfo", data, pos); + SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); + textureID = sis.readUI32(); + textureFormat = sis.readUI16(); + int fileNameLen = sis.readUI8(); + fileName = new String(sis.readBytes(fileNameLen)); + textureWidth = sis.readUI16(); + textureHeight = sis.readUI16(); + padPixels = sis.readUI8(); + nominalGlyphSz = sis.readUI16(); + int numTexGlyphs = sis.readUI16(); + texGlyphs = new TEXGLYPH[numTexGlyphs]; + for (int i = 0; i < numTexGlyphs; i++) { + texGlyphs[i] = new TEXGLYPH(new GFxInputStream(sis)); + } + int numFonts = sis.readUI16(); + fonts = new FONTINFO[numFonts]; + for (int i = 0; i < numFonts; i++) { + fonts[i] = new FONTINFO(new GFxInputStream(sis)); + } + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/TagStub.java b/trunk/src/com/jpexs/decompiler/flash/tags/TagStub.java index 59a20631a..84d0aa7fd 100644 --- a/trunk/src/com/jpexs/decompiler/flash/tags/TagStub.java +++ b/trunk/src/com/jpexs/decompiler/flash/tags/TagStub.java @@ -61,7 +61,7 @@ public class TagStub extends Tag { * @throws IOException */ public TagStub(SWF swf, byte[] data, int version, long pos) throws IOException { - super(swf, ID, "", data, pos); + super(swf, ID, "" /*TODO:Insert name here*/, data, pos); SWFInputStream sis = new SWFInputStream(new ByteArrayInputStream(data), version); } diff --git a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java index 6c3933eca..181f05e6f 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/SHAPE.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import java.awt.Color; import java.awt.image.BufferedImage; import java.util.HashSet; import java.util.List; @@ -53,8 +54,8 @@ public class SHAPE implements NeedsCharacters { return SHAPERECORD.shapeToSVG(shapeNum, null, null, numFillBits, numLineBits, shapeRecords); } - public BufferedImage toImage(int shapeNum, List tags) { - return SHAPERECORD.shapeToImage(tags, shapeNum, null, null,/* numFillBits, numLineBits, */ shapeRecords); + public BufferedImage toImage(int shapeNum, List tags, Color defaultColor) { + return SHAPERECORD.shapeToImage(tags, shapeNum, null, null,/* numFillBits, numLineBits, */ shapeRecords, defaultColor); } public RECT getBounds() { diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/ContourType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/ContourType.java new file mode 100644 index 000000000..7c4630ab6 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/ContourType.java @@ -0,0 +1,77 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class ContourType { + + public int moveToX; + public int moveToY; + public EdgeType[] edges; + public boolean isReference; + public long reference; + + public ContourType(GFxInputStream sis) throws IOException { + moveToX = sis.readSI15(); + moveToY = sis.readSI15(); + long numEdgesRef = sis.readUI30(); + isReference = (numEdgesRef & 1) == 1; + numEdgesRef = numEdgesRef >> 1; + long oldPos = sis.getPos(); + if (isReference) { + sis.setPos(numEdgesRef); + numEdgesRef = sis.readUI30(); + numEdgesRef = numEdgesRef >> 1; + } + + edges = new EdgeType[(int) numEdgesRef]; + for (int i = 0; i < edges.length; i++) { + edges[i] = new EdgeType(sis); + } + if (isReference) { + sis.setPos(oldPos); + } + + } + + public List toSHAPERECORDS() { + int multiplier = 20; + List recs = new ArrayList<>(); + StyleChangeRecord src = new StyleChangeRecord(); + src.stateMoveTo = true; + src.moveDeltaX = moveToX * multiplier; + src.moveDeltaY = moveToY * multiplier; + recs.add(src); + for (EdgeType e : edges) { + recs.add(e.toSHAPERECORD()); + } + return recs; + } + + public void write(SWFOutputStream sos) throws IOException { + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/EdgeType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/EdgeType.java new file mode 100644 index 000000000..d254a6169 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/EdgeType.java @@ -0,0 +1,267 @@ +/* + * 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 . + */ +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.IOException; + +/** + * + * @author JPEXS + */ +public class EdgeType { + + private static final int sizes[] = new int[]{1, 2, 1, 2, 1, 2, 3, 4, 2, 3, 4, 5, 6, 7, 8, 9}; + private static final int Edge_H12 = 0; // 2 bytes + private static final int Edge_H20 = 1; // 3 bytes + private static final int Edge_V12 = 2; // 2 bytes + private static final int Edge_V20 = 3; // 3 bytes + private static final int Edge_L6 = 4; // 2 bytes + private static final int Edge_L10 = 5; // 3 bytes + private static final int Edge_L14 = 6; // 4 bytes + private static final int Edge_L18 = 7; // 5 bytes + private static final int Edge_C5 = 8; // 3 bytes + private static final int Edge_C7 = 9; // 4 bytes + private static final int Edge_C9 = 10; // 5 bytes + private static final int Edge_C11 = 11; // 6 bytes + private static final int Edge_C13 = 12; // 7 bytes + private static final int Edge_C15 = 13; // 8 bytes + private static final int Edge_C17 = 14; // 9 bytes + private static final int Edge_C19 = 15; // 10 bytes + private static final int Edge_HLine = 0; + private static final int Edge_VLine = 1; + private static final int Edge_Line = 2; + private static final int Edge_Quad = 3; + public int data[]; + public byte raw[]; + + @Override + public String toString() { + String ret = "[Edge " + (raw[0] & 0xf) + " data:"; + for (int i = 0; i < data.length; i++) { + if (i > 0) { + ret += ", "; + } + ret += "" + data[i]; + } + ret += " raw: 0x"; + for (int i = 0; i < raw.length; i++) { + if (i > 0) { + ret += ""; + } + String h = Integer.toHexString(raw[i] & 0xff); + if (h.length() < 2) { + h = "0" + h; + } + ret += "" + h; + } + ret += "]"; + return ret; + } + + public EdgeType(GFxInputStream sis) throws IOException { + data = readEdge(sis); + /*if((raw[0]&0xf) == Edge_V20){ + data[1] = 0; + } + if((raw[0]&0xf) == Edge_C17){ + //System.out.println("========== 17 : "+toString()) ; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 0; + }*/ + } + + private byte[] readRawEdge(GFxInputStream sis) throws IOException { + int firstByte = sis.readUI8(); + int nb = sizes[firstByte & 0xF]; + byte ret[] = new byte[1 + nb]; + ret[0] = (byte) firstByte; + int i; + for (i = 0; i < nb; i++) { + ret[i + 1] = (byte) sis.readUI8(); + } + + return ret; + } + + private static int SInt8(int val) { + /*boolean sign = (val & 0x80) == 0x80; + val = val & 0x7F; + if (sign) { + val = -val; + } + return val;*/ + return (byte) val; + } + + public SHAPERECORD toSHAPERECORD() { + int multiplier = 20; + StraightEdgeRecord ser; + CurvedEdgeRecord cer; + switch (data[0]) { + case Edge_HLine: + ser = new StraightEdgeRecord(); + ser.generalLineFlag = false; + ser.deltaX = data[1] * multiplier; + return ser; + case Edge_VLine: + ser = new StraightEdgeRecord(); + ser.generalLineFlag = false; + ser.vertLineFlag = true; + ser.deltaY = data[1] * multiplier; + return ser; + case Edge_Line: + ser = new StraightEdgeRecord(); + ser.generalLineFlag = true; + ser.deltaX = data[1] * multiplier; + ser.deltaY = data[2] * multiplier; + return ser; + case Edge_Quad: + cer = new CurvedEdgeRecord(); + cer.controlDeltaX = data[1] * multiplier; + cer.controlDeltaY = data[2] * multiplier; + cer.anchorDeltaX = data[3] * multiplier; + cer.anchorDeltaY = data[4] * multiplier; + return cer; + } + return null; + } + + private int[] readEdge(GFxInputStream sis) throws IOException { + raw = readRawEdge(sis); + int data[] = new int[5]; + + switch (raw[0] & 0xF) { + case Edge_H12: + data[0] = Edge_HLine; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8(raw[1] & 0xff) << 4); + break; + + case Edge_H20: + data[0] = Edge_HLine; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8(raw[2] & 0xff) << 12); + break; + + case Edge_V12: + data[0] = Edge_VLine; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8(raw[1] & 0xff) << 4); + break; + + case Edge_V20: + data[0] = Edge_VLine; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8(raw[2] & 0xff) << 12); + break; + + case Edge_L6: + data[0] = Edge_Line; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 6) >> 2); + data[2] = SInt8(raw[1] & 0xff) >> 2; + break; + + case Edge_L10: + data[0] = Edge_Line; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 2) << 2); + data[2] = ((raw[1] & 0xff) >> 6) | (SInt8((raw[2] & 0xff)) << 2); + break; + + case Edge_L14: + data[0] = Edge_Line; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8((raw[2] & 0xff) << 6) << 6); + data[2] = ((raw[2] & 0xff) >> 2) | (SInt8((raw[3] & 0xff)) << 6); + break; + + case Edge_L18: + data[0] = Edge_Line; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8((raw[2] & 0xff) << 2) << 10); + data[2] = ((raw[2] & 0xff) >> 6) | ((raw[3] & 0xff) << 2) | (SInt8((raw[4] & 0xff)) << 10); + break; + + case Edge_C5: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 7) >> 3); + data[2] = SInt8((raw[1] & 0xff) << 2) >> 3; + data[3] = ((raw[1] & 0xff) >> 6) | (SInt8((raw[2] & 0xff) << 5) >> 3); + data[4] = SInt8((raw[2] & 0xff)) >> 3; + break; + + case Edge_C7: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 5) >> 1); + data[2] = ((raw[1] & 0xff) >> 3) | (SInt8((raw[2] & 0xff) << 6) >> 1); + data[3] = ((raw[2] & 0xff) >> 2) | (SInt8((raw[3] & 0xff) << 7) >> 1); + data[4] = SInt8(raw[3]) >> 1; + break; + + case Edge_C9: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 3) << 1); + data[2] = ((raw[1] & 0xff) >> 5) | (SInt8((raw[2] & 0xff) << 2) << 1); + data[3] = ((raw[2] & 0xff) >> 6) | (SInt8((raw[3] & 0xff) << 1) << 1); + data[4] = ((raw[3] & 0xff) >> 7) | (SInt8(raw[4] & 0xff) << 1); + break; + + case Edge_C11: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | (SInt8((raw[1] & 0xff) << 1) << 3); + data[2] = (raw[1] >> 7) | ((raw[2] & 0xff) << 1) | (SInt8((raw[3] & 0xff) << 6) << 3); + data[3] = ((raw[3] & 0xff) >> 2) | (SInt8((raw[4] & 0xff) << 3) << 3); + data[4] = ((raw[4] & 0xff) >> 5) | (SInt8(raw[5] & 0xff) << 3); + break; + + case Edge_C13: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8((raw[2] & 0xff) << 7) << 5); + data[2] = ((raw[2] & 0xff) >> 1) | (SInt8((raw[3] & 0xff) << 2) << 5); + data[3] = ((raw[3] & 0xff) >> 6) | ((raw[4] & 0xff) << 2) | (SInt8((raw[5] & 0xff) << 5) << 5); + data[4] = ((raw[5] & 0xff) >> 3) | (SInt8(raw[6] & 0xff) << 5); + break; + + case Edge_C15: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8((raw[2] & 0xff) << 5) << 7); + data[2] = ((raw[2] & 0xff) >> 3) | ((raw[3] & 0xff) << 5) | (SInt8((raw[4] & 0xff) << 6) << 7); + data[3] = ((raw[4] & 0xff) >> 2) | ((raw[5] & 0xff) << 6) | (SInt8((raw[6] & 0xff) << 7) << 7); + data[4] = ((raw[6] & 0xff) >> 1) | (SInt8((raw[7] & 0xff)) << 7); + break; + + case Edge_C17: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8((raw[2] & 0xff) << 3) << 9); + data[2] = ((raw[2] & 0xff) >> 5) | ((raw[3] & 0xff) << 3) | (SInt8((raw[4] & 0xff) << 2) << 9); + data[3] = ((raw[4] & 0xff) >> 6) | ((raw[5] & 0xff) << 2) | (SInt8((raw[6] & 0xff) << 1) << 9); + data[4] = ((raw[6] & 0xff) >> 7) | ((raw[7] & 0xff) << 1) | (SInt8(raw[8] & 0xff) << 9); + break; + + case Edge_C19: + data[0] = Edge_Quad; + data[1] = ((raw[0] & 0xff) >> 4) | ((raw[1] & 0xff) << 4) | (SInt8(raw[2] << 1) << 11); + data[2] = ((raw[2] & 0xff) >> 7) | ((raw[3] & 0xff) << 1) | ((raw[4] & 0xff) << 9) | (SInt8(raw[5] << 6) << 11); + data[3] = ((raw[5] & 0xff) >> 2) | ((raw[6] & 0xff) << 6) | (SInt8(raw[7] << 3) << 11); + data[4] = ((raw[7] & 0xff) >> 5) | ((raw[8] & 0xff) << 3) | (SInt8(raw[9]) << 11); + break; + } + return data; + } + + public void write(SWFOutputStream sos) throws IOException { + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/FONTINFO.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/FONTINFO.java new file mode 100644 index 000000000..584bb5ac4 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/FONTINFO.java @@ -0,0 +1,52 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class FONTINFO { + + public int fontId; + public GLYPHIDX glyphIndices[]; + + public FONTINFO(int fontId, int numGlyphs, GLYPHIDX[] glyphIndices) { + this.fontId = fontId; + this.glyphIndices = glyphIndices; + } + + public FONTINFO(GFxInputStream sis) throws IOException { + fontId = sis.readUI16(); + int numGlyphs = sis.readUI16(); + glyphIndices = new GLYPHIDX[numGlyphs]; + for (int i = 0; i < numGlyphs; i++) { + glyphIndices[i] = new GLYPHIDX(sis); + } + } + + public void write(SWFOutputStream sos) throws IOException { + sos.writeUI16(fontId); + sos.writeUI16(glyphIndices.length); + for (int i = 0; i < glyphIndices.length; i++) { + glyphIndices[i].write(sos); + } + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/FontType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/FontType.java new file mode 100644 index 000000000..8091271e2 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/FontType.java @@ -0,0 +1,90 @@ +/* + * 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 . + */ +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; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class FontType { + + public static final int FF_Italic = 0x0001; + public static final int FF_Bold = 0x0002; + public String fontName; + public int flags; + public int nominalSize; + public int ascent; + public int descent; + public int leading; + public GlyphType[] glyphs; + public GlyphInfoType[] glyphInfo; + public 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); + } + fontName = new String(baos.toByteArray()); + flags = sis.readUI16(); + nominalSize = sis.readUI16(); + ascent = sis.readSI16(); + descent = sis.readSI16(); + leading = sis.readSI16(); + long numGlyphs = sis.readUI32(); + long glyphBytesLen = sis.readUI32(); + byte glyphBytes[] = new byte[(int) glyphBytesLen]; + sis.read(glyphBytes); + glyphInfo = new GlyphInfoType[(int) numGlyphs]; + for (int i = 0; i < numGlyphs; i++) { + glyphInfo[i] = new GlyphInfoType(sis); + } + + long kerningTableSize = sis.readUI30(); + kerning = new KerningPairType[((int) kerningTableSize)]; + for (int i = 0; i < kerningTableSize; i++) { + kerning[i] = 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); + } + } + + public List getGlyphShapes() { + List ret = new ArrayList<>(); + for (GlyphType g : glyphs) { + ret.add(g.toSHAPE()); + } + return ret; + } + + public void write(SWFOutputStream sos) throws IOException { + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/GFxInputStream.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GFxInputStream.java new file mode 100644 index 000000000..165e7f899 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GFxInputStream.java @@ -0,0 +1,163 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.helpers.ReReadableInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @author JPEXS + */ +public class GFxInputStream extends InputStream { + + private ReReadableInputStream is; + private static final int MaxUInt7 = (1 << 7) - 1; + + public GFxInputStream(InputStream is) { + this.is = new ReReadableInputStream(is); + } + + @Override + public int available() throws IOException { + return is.available(); + } + + public void setPos(long pos) throws IOException { + is.setPos(pos); + } + + public long getPos() { + return is.getPos(); + } + + @Override + public int read() throws IOException { + return is.read(); + } + + public int readUI8() throws IOException { + return read(); + } + + public int readUI16() throws IOException { + return read() + (read() << 8); + } + + /** + * Reads one SI16 (Signed 16bit integer) value from the stream + * + * @return SI16 value + * @throws IOException + */ + public int readSI16() throws IOException { + int uval = read() + (read() << 8); + if (uval >= 0x8000) { + return -(((~uval) & 0xffff) + 1); + } else { + return uval; + } + } + + public long readUI32() throws IOException { + return (read() + (read() << 8) + (read() << 16) + (read() << 24)) & 0xffffffff; + } + + public long readUI30() throws IOException { + long v; + int tb = readUI8(); + long t = tb; + switch (tb & 3) { + case 0: + v = t >> 2; + return v; + + case 1: + t = t >> 2; + v = t | (readUI8() << 6); + return v; + case 2: + t = t >> 2; + t = t | (readUI8() << 6); + v = t | (readUI8() << 14); + return v; + } + t = t >> 2; + t = t | (readUI8() << 6); + t = t | (readUI8() << 14); + v = t | (readUI8() << 22); + return v; + } + + public float readFLOAT() throws IOException { + int val = (int) readUI32(); + float ret = Float.intBitsToFloat(val); + return ret; + } + + public int readSI8() throws IOException { + int uval = read(); + if (uval >= 0x80) { + return -(((~uval) & 0xff) + 1); + } else { + return uval; + } + } + + public int readSI15() throws IOException { + int t = readSI8(); + int v; + if ((t & 1) == 0) { + v = t >> 1; + return v; + } + t = ((t >> 1) & MaxUInt7); + v = (t | (readSI8() << 7)); + return v; + } + + public int readUI15() throws IOException { + int t = readUI8(); + int v; + if ((t & 1) == 0) { + v = t >> 1; + return v; + } + t = (t >> 1); + v = (t | (readUI8() << 7)); + return v; + } + + /** + * Reads bytes from the stream + * + * @param count Number of bytes to read + * @return Array of read bytes + * @throws IOException + */ + public byte[] readBytes(long count) throws IOException { + if (count <= 0) { + return new byte[0]; + } + byte[] ret = new byte[(int) count]; + for (int i = 0; i < count; i++) { + ret[i] = (byte) read(); + } + return ret; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/GLYPHIDX.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GLYPHIDX.java new file mode 100644 index 000000000..4be9681c0 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GLYPHIDX.java @@ -0,0 +1,45 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class GLYPHIDX { + + public int indexInFont; + public int indexInTexture; + + public GLYPHIDX(int indexInFont, int indexInTexture) { + this.indexInFont = indexInFont; + this.indexInTexture = indexInTexture; + } + + public GLYPHIDX(GFxInputStream sis) throws IOException { + this.indexInFont = sis.readUI16(); + this.indexInTexture = sis.readUI16(); + } + + public void write(SWFOutputStream sos) throws IOException { + sos.writeUI16(indexInFont); + sos.writeUI16(indexInTexture); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphInfoType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphInfoType.java new file mode 100644 index 000000000..99d9b82a3 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphInfoType.java @@ -0,0 +1,49 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class GlyphInfoType { + + public int glyphCode; + public int advanceX; + public long globalOffset; + + public GlyphInfoType(int glyphCode, int advance, int glyphPos) { + this.glyphCode = glyphCode; + this.advanceX = advance; + this.globalOffset = glyphPos; + } + + public GlyphInfoType(GFxInputStream sis) throws IOException { + this.glyphCode = sis.readUI16(); + this.advanceX = sis.readSI16(); + this.globalOffset = sis.readUI32(); + } + + public void write(SWFOutputStream sos) throws IOException { + sos.writeUI16(glyphCode); + sos.writeSI16(advanceX); + sos.writeUI32(globalOffset); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphType.java new file mode 100644 index 000000000..681995bde --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/GlyphType.java @@ -0,0 +1,66 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author JPEXS + */ +public class GlyphType { + + public int[] boundingBox; + public ContourType[] contours; + + public GlyphType(GFxInputStream sis) throws IOException { + boundingBox = new int[4]; + for (int i = 0; i < 4; i++) { + boundingBox[i] = sis.readSI15(); + } + int numContours = sis.readUI15(); + contours = new ContourType[numContours]; + for (int i = 0; i < numContours; i++) { + contours[i] = new ContourType(sis); + } + } + + public SHAPE toSHAPE() { + SHAPE shp = new SHAPE(); + shp.numFillBits = 1; + shp.numLineBits = 1; + List recs = new ArrayList<>(); + StyleChangeRecord scr = new StyleChangeRecord(); + scr.fillStyle0 = 1; + scr.stateFillStyle0 = true; + recs.add(scr); + for (ContourType cnt : contours) { + recs.addAll(cnt.toSHAPERECORDS()); + } + shp.shapeRecords = recs; + return shp; + } + + public void write(SWFOutputStream sos) throws IOException { + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/KerningPairType.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/KerningPairType.java new file mode 100644 index 000000000..9936e6ec0 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/KerningPairType.java @@ -0,0 +1,49 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class KerningPairType { + + public int char1; + public int char2; + public int advance; + + public KerningPairType(int char1, int char2, int advance) { + this.char1 = char1; + this.char2 = char2; + this.advance = advance; + } + + public KerningPairType(GFxInputStream sis) throws IOException { + this.char1 = sis.readUI16(); + this.char2 = sis.readUI16(); + this.advance = sis.readSI16(); + } + + public void write(SWFOutputStream sos) throws IOException { + sos.writeUI16(char1); + sos.writeUI16(char2); + sos.writeSI16(advance); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/gfx/TEXGLYPH.java b/trunk/src/com/jpexs/decompiler/flash/types/gfx/TEXGLYPH.java new file mode 100644 index 000000000..7fddac33b --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/gfx/TEXGLYPH.java @@ -0,0 +1,61 @@ +/* + * 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 . + */ +package com.jpexs.decompiler.flash.types.gfx; + +import com.jpexs.decompiler.flash.SWFOutputStream; +import java.io.IOException; + +/** + * + * @author JPEXS + */ +public class TEXGLYPH { + + public float uvBoundsLeft; + public float uvBoundsTop; + public float uvBoundsRight; + public float uvBoundsBottom; + public float uvOriginX; + public float uvOriginY; + + public TEXGLYPH(float uvBoundsLeft, float uvBoundsTop, float uvBoundsRight, float uvBoundsBottom, float uvOriginX, float uvOriginY) { + this.uvBoundsLeft = uvBoundsLeft; + this.uvBoundsTop = uvBoundsTop; + this.uvBoundsRight = uvBoundsRight; + this.uvBoundsBottom = uvBoundsBottom; + this.uvOriginX = uvOriginX; + this.uvOriginY = uvOriginY; + } + + public TEXGLYPH(GFxInputStream sis) throws IOException { + this.uvBoundsLeft = sis.readFLOAT(); + this.uvBoundsTop = sis.readFLOAT(); + this.uvBoundsRight = sis.readFLOAT(); + this.uvBoundsBottom = sis.readFLOAT(); + this.uvOriginX = sis.readFLOAT(); + this.uvOriginY = sis.readFLOAT(); + } + + public void write(SWFOutputStream sos) throws IOException { + sos.writeFLOAT(uvBoundsLeft); + sos.writeFLOAT(uvBoundsTop); + sos.writeFLOAT(uvBoundsRight); + sos.writeFLOAT(uvBoundsBottom); + sos.writeFLOAT(uvOriginX); + sos.writeFLOAT(uvOriginY); + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java index 10bfe226b..119695a16 100644 --- a/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java +++ b/trunk/src/com/jpexs/decompiler/flash/types/shaperecords/SHAPERECORD.java @@ -36,6 +36,7 @@ import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.LinearGradientPaint; @@ -74,7 +75,7 @@ import javax.swing.JPanel; */ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters { - private static final float DESCALE = 20; //20 + private static final float DESCALE = 20; @Override public Set getNeededCharacters() { @@ -838,6 +839,46 @@ public abstract class SHAPERECORD implements Cloneable, NeedsCharacters { return ret; } + public static BufferedImage shapeListToImage(List shapes, int prevWidth, int prevHeight, Color color) { + BufferedImage ret = new BufferedImage(prevWidth, prevHeight, BufferedImage.TYPE_INT_ARGB); + Graphics g = ret.getGraphics(); + int p = 0; + List images = new ArrayList<>(); + for (SHAPE s : shapes) { + images.add(s.toImage(1, new ArrayList(), color)); + } + int cols = (int) Math.ceil(Math.sqrt(images.size())); + int pos = 0; + int w2 = prevWidth / cols; + int h2 = prevHeight / cols; + loopy: + for (int y = 0; y < cols; y++) { + for (int x = 0; x < cols; x++) { + if (pos >= images.size()) { + break loopy; + } + int w1 = images.get(pos).getWidth(); + 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; + g.drawImage(images.get(pos), px, py, px + w, py + h, 0, 0, w1, h1, null); + pos++; + } + } + + return ret; + } + public static BufferedImage shapeToImage(List tags, int shapeNum, FILLSTYLEARRAY fillStyles, LINESTYLEARRAY lineStylesList, List records, Color defaultColor) { String key = "shape_" + records.hashCode() + "_" + (defaultColor == null ? "null" : defaultColor.hashCode()); if (cache.contains(key)) {