Converting GFX tags to classic tags before running in Flash player

This commit is contained in:
Jindra Petřík
2022-12-31 12:52:20 +01:00
parent c9335ac9ba
commit 505013207b
6 changed files with 218 additions and 50 deletions

View File

@@ -1071,13 +1071,13 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
@Override
public void saveTo(OutputStream os) throws IOException {
checkCharset();
byte[] uncompressedData = saveToByteArray();
byte[] uncompressedData = saveToByteArray(false);
compress(new ByteArrayInputStream(uncompressedData), os, compression, lzmaProperties);
}
public void saveTo(OutputStream os, boolean gfx) throws IOException {
public void saveTo(OutputStream os, boolean gfx, boolean includeImported) throws IOException {
checkCharset();
byte[] uncompressedData = saveToByteArray(gfx);
byte[] uncompressedData = saveToByteArray(gfx, includeImported);
compress(new ByteArrayInputStream(uncompressedData), os, compression, lzmaProperties);
}
@@ -1113,8 +1113,8 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
return ret;
}
private byte[] saveToByteArray() throws IOException {
return saveToByteArray(gfx);
private byte[] saveToByteArray(boolean includeImported) throws IOException {
return saveToByteArray(gfx, includeImported);
}
private void checkCharset() {
@@ -1123,7 +1123,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
}
}
private byte[] saveToByteArray(boolean gfx) throws IOException {
private byte[] saveToByteArray(boolean gfx, boolean includeImported) throws IOException {
byte[] data;
try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); SWFOutputStream sos = new SWFOutputStream(baos, version, charset)) {
sos.write(getHeaderBytes(SWFCompression.NONE, gfx));
@@ -1133,7 +1133,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
sos.writeFIXED8(frameRate);
sos.writeUI16(frameCount);
sos.writeTags(getLocalTags());
sos.writeTags(includeImported ? getTags() : getLocalTags());
if (hasEndTag) {
sos.writeUI16(0);
}
@@ -1289,7 +1289,7 @@ public final class SWF implements SWFContainerItem, Timelined, Openable {
isModified = false;
try {
uncompressedData = saveToByteArray();
uncompressedData = saveToByteArray(false);
} catch (IOException ex) {
logger.log(Level.SEVERE, "Cannot save SWF", ex);
}

View File

@@ -0,0 +1,189 @@
/*
* Copyright (C) 2010-2022 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.ImportAssets2Tag;
import com.jpexs.decompiler.flash.tags.ImportAssetsTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.gfx.DefineCompactedFont;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalGradient;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalImage2;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound;
import com.jpexs.decompiler.flash.tags.gfx.DefineGradientMap;
import com.jpexs.decompiler.flash.tags.gfx.DefineSubImage;
import com.jpexs.decompiler.flash.tags.gfx.ExporterInfo;
import com.jpexs.decompiler.flash.tags.gfx.FontTextureInfo;
import com.jpexs.decompiler.flash.types.KERNINGRECORD;
import com.jpexs.decompiler.flash.types.LANGCODE;
import com.jpexs.decompiler.flash.types.SHAPE;
import com.jpexs.decompiler.flash.types.gfx.FontType;
import com.jpexs.helpers.Helper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Converts GFX SWF to normal SWF.
* @author JPEXS
*/
public class GfxConvertor {
public DefineFont2Tag convertDefineCompactedFont(DefineCompactedFont compactedFont) {
DefineFont2Tag ret = new DefineFont2Tag(compactedFont.getSwf());
ret.fontID = compactedFont.getFontId();
ret.fontFlagsBold = compactedFont.isBold();
ret.fontFlagsItalic = compactedFont.isItalic();
ret.fontFlagsWideOffsets = true;
ret.fontFlagsWideCodes = true;
ret.fontFlagsHasLayout = true;
ret.fontAscent = compactedFont.resize(compactedFont.getAscent());
ret.fontDescent = compactedFont.resize(compactedFont.getDescent());
ret.fontLeading = compactedFont.resize(compactedFont.getLeading());
ret.fontAdvanceTable = new ArrayList<>();
ret.fontBoundsTable = new ArrayList<>();
ret.codeTable = new ArrayList<>();
ret.glyphShapeTable = new ArrayList<>();
List<SHAPE> shp = compactedFont.getGlyphShapeTable();
for (int g = 0; g < shp.size(); g++) {
ret.fontAdvanceTable.add((int) compactedFont.getGlyphAdvance(g)); //already resized
ret.codeTable.add((int) compactedFont.glyphToChar(g));
SHAPE shpX = compactedFont.resizeShape(shp.get(g));
ret.glyphShapeTable.add(shpX);
ret.fontBoundsTable.add(compactedFont.getGlyphBounds(g));
}
ret.fontName = compactedFont.getFontNameIntag();
ret.languageCode = new LANGCODE(1);
ret.fontKerningTable = new ArrayList<>();
FontType ft = compactedFont.fonts.get(0);
for (int i = 0; i < ft.kerning.size(); i++) {
KERNINGRECORD kr = new KERNINGRECORD();
kr.fontKerningAdjustment = compactedFont.resize(ft.kerning.get(i).advance);
kr.fontKerningCode1 = ft.kerning.get(i).char1;
kr.fontKerningCode2 = ft.kerning.get(i).char2;
ret.fontKerningTable.add(kr);
}
return ret;
}
public DefineBitsLossless2Tag convertDefineSubImage(DefineSubImage defineSubImage) {
DefineBitsLossless2Tag ret = new DefineBitsLossless2Tag(defineSubImage.getSwf());
ret.characterID = defineSubImage.characterID;
ret.bitmapWidth = defineSubImage.getImageDimension().width;
ret.bitmapHeight = defineSubImage.getImageDimension().height;
ret.bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
try {
ret.setImage(Helper.readStream(defineSubImage.getImageData()));
} catch (IOException ex) {
Logger.getLogger(GfxConvertor.class.getName()).log(Level.SEVERE, null, ex);
}
return ret;
}
public DefineBitsLossless2Tag convertDefineExternalImage(DefineExternalImage defineExternalImage) {
DefineBitsLossless2Tag ret = new DefineBitsLossless2Tag(defineExternalImage.getSwf());
ret.characterID = defineExternalImage.characterID;
ret.bitmapWidth = defineExternalImage.getImageDimension().width;
ret.bitmapHeight = defineExternalImage.getImageDimension().height;
ret.bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
try {
ret.setImage(Helper.readStream(defineExternalImage.getImageData()));
} catch (IOException ex) {
Logger.getLogger(GfxConvertor.class.getName()).log(Level.SEVERE, null, ex);
}
return ret;
}
public Tag convertTag(Tag tag) {
if (tag instanceof DefineCompactedFont) {
return convertDefineCompactedFont((DefineCompactedFont)tag);
}
if (tag instanceof DefineExternalGradient) {
return null;
}
if (tag instanceof DefineExternalImage) {
return convertDefineExternalImage((DefineExternalImage) tag);
}
if (tag instanceof DefineExternalImage2) {
return null;
}
if (tag instanceof DefineExternalSound) {
return null;
}
if (tag instanceof DefineExternalStreamSound) {
return null;
}
if (tag instanceof DefineGradientMap) {
return null;
}
if (tag instanceof DefineSubImage) {
return convertDefineSubImage((DefineSubImage) tag);
}
if (tag instanceof ExporterInfo) {
return null;
}
if (tag instanceof FontTextureInfo) {
return null;
}
if (tag instanceof ImportAssetsTag) {
return null;
}
if (tag instanceof ImportAssets2Tag) {
return null;
}
return tag;
}
public SWF convertSwf(SWF gfxSwf) {
if (!gfxSwf.gfx) {
return gfxSwf;
}
SWF ret = new SWF();
ret.displayRect = gfxSwf.displayRect;
ret.frameRate = gfxSwf.frameRate;
ret.compression = gfxSwf.compression;
ret.frameCount = gfxSwf.frameCount;
ret.gfx = false;
ret.hasEndTag = gfxSwf.hasEndTag;
for (Tag t:gfxSwf.getTags()) {
Tag ct = convertTag(t);
if (ct != null) {
ret.addTag(ct);
}
}
return ret;
}
}

View File

@@ -430,7 +430,7 @@ public abstract class Tag implements NeedsCharacters, Exportable, Serializable {
* @throws IOException
*/
public void writeTag(SWFOutputStream sos) throws IOException {
if (Configuration._debugCopy.get() || isModified()) {
if (Configuration._debugCopy.get() || isModified() || isImported()) {
byte[] newData = getData();
byte[] newHeaderData = getHeader(newData.length);
sos.write(newHeaderData);

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags.gfx;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.gfx.GfxConvertor;
import com.jpexs.decompiler.flash.helpers.FontHelper;
import com.jpexs.decompiler.flash.tags.DefineFont2Tag;
import com.jpexs.decompiler.flash.tags.base.FontTag;
@@ -435,50 +436,14 @@ public final class DefineCompactedFont extends FontTag {
return ret;
}
protected int resize(double val) {
public int resize(double val) {
FontType ft = fonts.get(0);
return (int) Math.round(val * 1024.0 / ft.nominalSize);
}
@Override
public FontTag toClassicFont() {
DefineFont2Tag ret = new DefineFont2Tag(swf);
ret.fontID = getFontId();
ret.fontFlagsBold = isBold();
ret.fontFlagsItalic = isItalic();
ret.fontFlagsWideOffsets = true;
ret.fontFlagsWideCodes = true;
ret.fontFlagsHasLayout = true;
ret.fontAscent = resize(getAscent());
ret.fontDescent = resize(getDescent());
ret.fontLeading = resize(getLeading());
ret.fontAdvanceTable = new ArrayList<>();
ret.fontBoundsTable = new ArrayList<>();
ret.codeTable = new ArrayList<>();
ret.glyphShapeTable = new ArrayList<>();
List<SHAPE> shp = getGlyphShapeTable();
for (int g = 0; g < shp.size(); g++) {
ret.fontAdvanceTable.add((int) getGlyphAdvance(g)); //already resized
ret.codeTable.add((int) glyphToChar(g));
SHAPE shpX = resizeShape(shp.get(g));
ret.glyphShapeTable.add(shpX);
ret.fontBoundsTable.add(getGlyphBounds(g));
}
ret.fontName = getFontNameIntag();
ret.languageCode = new LANGCODE(1);
ret.fontKerningTable = new ArrayList<>();
FontType ft = fonts.get(0);
for (int i = 0; i < ft.kerning.size(); i++) {
KERNINGRECORD kr = new KERNINGRECORD();
kr.fontKerningAdjustment = resize(ft.kerning.get(i).advance);
kr.fontKerningCode1 = ft.kerning.get(i).char1;
kr.fontKerningCode2 = ft.kerning.get(i).char2;
ret.fontKerningTable.add(kr);
}
return ret;
return new GfxConvertor().convertDefineCompactedFont(this);
}
@Override