faster DefineBitsLosslessX reading

This commit is contained in:
honfika@gmail.com
2015-05-08 20:54:48 +02:00
parent 8a784d2d0b
commit 6d49dc584d
13 changed files with 7173 additions and 7030 deletions

View File

@@ -1,285 +1,282 @@
/*
* Copyright (C) 2010-2015 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.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.base.AloneTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
import com.jpexs.decompiler.flash.types.ARGB;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
@SWFType(BasicType.UI16)
public int characterID;
@SWFType(BasicType.UI8)
public int bitmapFormat;
@SWFType(BasicType.UI16)
public int bitmapWidth;
@SWFType(BasicType.UI16)
public int bitmapHeight;
@SWFType(BasicType.UI8)
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
public int bitmapColorTableSize;
public ByteArrayRange zlibBitmapData; //TODO: Parse ALPHACOLORMAPDATA,ALPHABITMAPDATA
public static final int FORMAT_8BIT_COLORMAPPED = 3;
public static final int FORMAT_32BIT_ARGB = 5;
@HideInRawEdit
private ALPHACOLORMAPDATA colorMapData;
@HideInRawEdit
private ALPHABITMAPDATA bitmapData;
@Internal
private boolean decompressed = false;
public static final int ID = 36;
@Override
public int getCharacterId() {
return characterID;
}
private byte[] createEmptyImage() {
try {
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
bitmapData.bitmapPixelData = new ARGB[1];
bitmapData.bitmapPixelData[0] = new ARGB();
bitmapData.bitmapPixelData[0].alpha = 0xff;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeALPHABITMAPDATA(bitmapData, FORMAT_32BIT_ARGB, 1, 1);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
return zlibOS.toByteArray();
} catch (IOException ex) {
Logger.getLogger(DefineBitsLossless2Tag.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public void setImage(byte[] data) throws IOException {
SerializableImage image = new SerializableImage(ImageHelper.read(new ByteArrayInputStream(data)));
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
int width = image.getWidth();
int height = image.getHeight();
bitmapData.bitmapPixelData = new ARGB[width * height];
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int pos = 0; pos < pixels.length; pos++) {
int argb = pixels[pos];
int a = (argb >> 24) & 0xff;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb) & 0xff;
r = r * a / 255;
g = g * a / 255;
b = b * a / 255;
bitmapData.bitmapPixelData[pos] = new ARGB();
bitmapData.bitmapPixelData[pos].alpha = a;
bitmapData.bitmapPixelData[pos].red = r;
bitmapData.bitmapPixelData[pos].green = g;
bitmapData.bitmapPixelData[pos].blue = b;
}
int format = FORMAT_32BIT_ARGB;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeALPHABITMAPDATA(bitmapData, format, width, height);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
bitmapFormat = format;
bitmapWidth = width;
bitmapHeight = height;
decompressed = false;
clearCache();
setModified(true);
}
/**
* Constructor
*
* @param swf
*/
public DefineBitsLossless2Tag(SWF swf) {
super(swf, ID, "DefineBitsLossless2", null);
characterID = swf.getNextCharacterId();
bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
bitmapWidth = 1;
bitmapHeight = 1;
zlibBitmapData = new ByteArrayRange(createEmptyImage());
}
public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, "DefineBitsLossless2", data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
characterID = sis.readUI16("characterID");
bitmapFormat = sis.readUI8("bitmapFormat");
bitmapWidth = sis.readUI16("bitmapWidth");
bitmapHeight = sis.readUI16("bitmapHeight");
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
}
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
}
public ALPHACOLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
}
return colorMapData;
}
public ALPHABITMAPDATA getBitmapData() {
if (!decompressed) {
uncompressData();
}
return bitmapData;
}
private void uncompressData() {
try {
SWFInputStream sis = new SWFInputStream(swf, Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength()))));
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
colorMapData = sis.readALPHACOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
}
if (bitmapFormat == FORMAT_32BIT_ARGB) {
bitmapData = sis.readALPHABITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
}
} catch (IOException ex) {
}
decompressed = true;
}
/**
* Gets data bytes
*
* @return Bytes of data
*/
@Override
public byte[] getData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
try {
sos.writeUI16(characterID);
sos.writeUI8(bitmapFormat);
sos.writeUI16(bitmapWidth);
sos.writeUI16(bitmapHeight);
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
sos.writeUI8(bitmapColorTableSize);
}
sos.write(zlibBitmapData);
} catch (IOException e) {
throw new Error("This should never happen.", e);
}
return baos.toByteArray();
}
@Override
public String getImageFormat() {
return "png";
}
@Override
public InputStream getImageData() {
return null;
}
@Override
public SerializableImage getImage() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_ARGB);
ALPHACOLORMAPDATA colorMapData = null;
ALPHABITMAPDATA bitmapData = null;
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED) {
colorMapData = getColorMapData();
}
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB) {
bitmapData = getBitmapData();
}
int pos32aligned = 0;
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
int c = 0;
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED)) {
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
if (colorTableIndex < colorMapData.colorTableRGB.length) {
c = multiplyAlpha(colorMapData.colorTableRGB[colorTableIndex].toInt());
}
}
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB)) {
c = multiplyAlpha(bitmapData.bitmapPixelData[pos].toInt());
}
bi.setRGB(x, y, c);
pos32aligned++;
pos++;
}
while ((pos32aligned % 4 != 0)) {
pos32aligned++;
}
}
cachedImage = bi;
return bi;
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}
/*
* Copyright (C) 2010-2015 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.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.base.AloneTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA;
import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import com.jpexs.helpers.Stopwatch;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
@SWFType(BasicType.UI16)
public int characterID;
@SWFType(BasicType.UI8)
public int bitmapFormat;
@SWFType(BasicType.UI16)
public int bitmapWidth;
@SWFType(BasicType.UI16)
public int bitmapHeight;
@SWFType(BasicType.UI8)
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
public int bitmapColorTableSize;
public ByteArrayRange zlibBitmapData; //TODO: Parse ALPHACOLORMAPDATA,ALPHABITMAPDATA
public static final int FORMAT_8BIT_COLORMAPPED = 3;
public static final int FORMAT_32BIT_ARGB = 5;
@HideInRawEdit
private ALPHACOLORMAPDATA colorMapData;
@HideInRawEdit
private ALPHABITMAPDATA bitmapData;
@Internal
private boolean decompressed = false;
public static final int ID = 36;
@Override
public int getCharacterId() {
return characterID;
}
private byte[] createEmptyImage() {
try {
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
bitmapData.bitmapPixelData = new int[]{0xff000000};
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeALPHABITMAPDATA(bitmapData, FORMAT_32BIT_ARGB, 1, 1);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
return zlibOS.toByteArray();
} catch (IOException ex) {
Logger.getLogger(DefineBitsLossless2Tag.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public void setImage(byte[] data) throws IOException {
SerializableImage image = new SerializableImage(ImageHelper.read(new ByteArrayInputStream(data)));
ALPHABITMAPDATA bitmapData = new ALPHABITMAPDATA();
int width = image.getWidth();
int height = image.getHeight();
bitmapData.bitmapPixelData = new int[width * height];
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int pos = 0; pos < pixels.length; pos++) {
int argb = pixels[pos];
int a = (argb >> 24) & 0xff;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb) & 0xff;
r = r * a / 255;
g = g * a / 255;
b = b * a / 255;
bitmapData.bitmapPixelData[pos] = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF);
}
int format = FORMAT_32BIT_ARGB;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeALPHABITMAPDATA(bitmapData, format, width, height);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
bitmapFormat = format;
bitmapWidth = width;
bitmapHeight = height;
decompressed = false;
clearCache();
setModified(true);
}
/**
* Constructor
*
* @param swf
*/
public DefineBitsLossless2Tag(SWF swf) {
super(swf, ID, "DefineBitsLossless2", null);
characterID = swf.getNextCharacterId();
bitmapFormat = DefineBitsLossless2Tag.FORMAT_32BIT_ARGB;
bitmapWidth = 1;
bitmapHeight = 1;
zlibBitmapData = new ByteArrayRange(createEmptyImage());
}
public DefineBitsLossless2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, "DefineBitsLossless2", data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
characterID = sis.readUI16("characterID");
bitmapFormat = sis.readUI8("bitmapFormat");
bitmapWidth = sis.readUI16("bitmapWidth");
bitmapHeight = sis.readUI16("bitmapHeight");
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
}
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
}
public ALPHACOLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
}
return colorMapData;
}
public ALPHABITMAPDATA getBitmapData() {
if (!decompressed) {
uncompressData();
}
return bitmapData;
}
private void uncompressData() {
try {
SWFInputStream sis = new SWFInputStream(swf, Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength()))));
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
colorMapData = sis.readALPHACOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
}
if (bitmapFormat == FORMAT_32BIT_ARGB) {
Stopwatch sw = Stopwatch.startNew();
bitmapData = sis.readALPHABITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
sw.stop();
System.out.println("uncompress: " + sw.getElapsedMilliseconds());
}
} catch (IOException ex) {
}
decompressed = true;
}
/**
* Gets data bytes
*
* @return Bytes of data
*/
@Override
public byte[] getData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
try {
sos.writeUI16(characterID);
sos.writeUI8(bitmapFormat);
sos.writeUI16(bitmapWidth);
sos.writeUI16(bitmapHeight);
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
sos.writeUI8(bitmapColorTableSize);
}
sos.write(zlibBitmapData);
} catch (IOException e) {
throw new Error("This should never happen.", e);
}
return baos.toByteArray();
}
@Override
public String getImageFormat() {
return "png";
}
@Override
public InputStream getImageData() {
return null;
}
@Override
public SerializableImage getImage() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_ARGB);
ALPHACOLORMAPDATA colorMapData = null;
ALPHABITMAPDATA bitmapData = null;
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED) {
colorMapData = getColorMapData();
}
if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB) {
bitmapData = getBitmapData();
}
int pos32aligned = 0;
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
int c = 0;
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED)) {
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
if (colorTableIndex < colorMapData.colorTableRGB.length) {
c = multiplyAlpha(colorMapData.colorTableRGB[colorTableIndex]);
}
}
if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB)) {
c = multiplyAlpha(bitmapData.bitmapPixelData[pos]);
}
bi.setRGB(x, y, c);
pos32aligned++;
pos++;
}
while ((pos32aligned % 4 != 0)) {
pos32aligned++;
}
}
cachedImage = bi;
return bi;
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}

View File

@@ -1,287 +1,283 @@
/*
* Copyright (C) 2010-2015 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.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.base.AloneTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.types.BITMAPDATA;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.COLORMAPDATA;
import com.jpexs.decompiler.flash.types.PIX24;
import com.jpexs.decompiler.flash.types.RGB;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
@SWFType(BasicType.UI16)
public int characterID;
@SWFType(BasicType.UI8)
public int bitmapFormat;
@SWFType(BasicType.UI16)
public int bitmapWidth;
@SWFType(BasicType.UI16)
public int bitmapHeight;
@SWFType(BasicType.UI8)
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
public int bitmapColorTableSize;
public ByteArrayRange zlibBitmapData; //TODO: Parse COLORMAPDATA,BITMAPDATA
public static final int FORMAT_8BIT_COLORMAPPED = 3;
public static final int FORMAT_15BIT_RGB = 4;
public static final int FORMAT_24BIT_RGB = 5;
@HideInRawEdit
private COLORMAPDATA colorMapData;
@HideInRawEdit
private BITMAPDATA bitmapData;
@Internal
private boolean decompressed = false;
public static final int ID = 20;
private byte[] createEmptyImage() {
try {
BITMAPDATA bitmapData = new BITMAPDATA();
bitmapData.bitmapPixelDataPix24 = new PIX24[1];
bitmapData.bitmapPixelDataPix24[0] = new PIX24();
bitmapData.bitmapPixelDataPix24[0].reserved = 0xff;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeBITMAPDATA(bitmapData, FORMAT_24BIT_RGB, 1, 1);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
return zlibOS.toByteArray();
} catch (IOException ex) {
Logger.getLogger(DefineBitsLosslessTag.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public void setImage(byte[] data) throws IOException {
SerializableImage image = new SerializableImage(ImageHelper.read(new ByteArrayInputStream(data)));
int width = image.getWidth();
int height = image.getHeight();
bitmapData = new BITMAPDATA();
bitmapData.bitmapPixelDataPix24 = new PIX24[width * height];
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int pos = 0; pos < pixels.length; pos++) {
int argb = pixels[pos];
//int a = (argb >> 24) & 0xff;
int r = (argb >> 16) & 0xff;
int g = (argb >> 8) & 0xff;
int b = (argb) & 0xff;
bitmapData.bitmapPixelDataPix24[pos] = new PIX24();
bitmapData.bitmapPixelDataPix24[pos].red = r;
bitmapData.bitmapPixelDataPix24[pos].green = g;
bitmapData.bitmapPixelDataPix24[pos].blue = b;
bitmapData.bitmapPixelDataPix24[pos].reserved = 0xff; //documentation says 0, but image is sometimes broken with 0, so there is 0xff, which works (maybe alpha?)
}
int format = FORMAT_24BIT_RGB;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeBITMAPDATA(bitmapData, format, width, height);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
bitmapFormat = format;
bitmapWidth = width;
bitmapHeight = height;
decompressed = false;
clearCache();
setModified(true);
}
@Override
public InputStream getImageData() {
return null;
}
@Override
public SerializableImage getImage() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_RGB);
COLORMAPDATA colorMapData = null;
BITMAPDATA bitmapData = null;
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
colorMapData = getColorMapData();
}
if ((bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) || (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB)) {
bitmapData = getBitmapData();
}
int pos32aligned = 0;
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
int c = 0;
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
if (colorTableIndex < colorMapData.colorTableRGB.length) {
RGB color = colorMapData.colorTableRGB[colorTableIndex];
c = color.toInt();
}
}
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
c = new RGB(bitmapData.bitmapPixelDataPix15[pos].red * 8, bitmapData.bitmapPixelDataPix15[pos].green * 8, bitmapData.bitmapPixelDataPix15[pos].blue * 8).toInt();
}
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
c = new RGB(bitmapData.bitmapPixelDataPix24[pos].red, bitmapData.bitmapPixelDataPix24[pos].green, bitmapData.bitmapPixelDataPix24[pos].blue).toInt();
}
bi.setRGB(x, y, c);
pos32aligned++;
pos++;
}
while ((pos32aligned % 4 != 0)) {
pos32aligned++;
}
}
cachedImage = bi;
return bi;
}
@Override
public int getCharacterId() {
return characterID;
}
public COLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
}
return colorMapData;
}
public BITMAPDATA getBitmapData() {
if (!decompressed) {
uncompressData();
}
return bitmapData;
}
private void uncompressData() {
try {
SWFInputStream sis = new SWFInputStream(swf, Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength()))));
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
colorMapData = sis.readCOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
}
if ((bitmapFormat == FORMAT_15BIT_RGB) || (bitmapFormat == FORMAT_24BIT_RGB)) {
bitmapData = sis.readBITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
}
} catch (IOException ex) {
}
decompressed = true;
}
/**
* Constructor
*
* @param swf
*/
public DefineBitsLosslessTag(SWF swf) {
super(swf, ID, "DefineBitsLossless", null);
characterID = swf.getNextCharacterId();
bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
bitmapWidth = 1;
bitmapHeight = 1;
zlibBitmapData = new ByteArrayRange(createEmptyImage());
}
public DefineBitsLosslessTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, "DefineBitsLossless", data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
characterID = sis.readUI16("characterID");
bitmapFormat = sis.readUI8("bitmapFormat");
bitmapWidth = sis.readUI16("bitmapWidth");
bitmapHeight = sis.readUI16("bitmapHeight");
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
}
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
}
/**
* Gets data bytes
*
* @return Bytes of data
*/
@Override
public byte[] getData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
try {
sos.writeUI16(characterID);
sos.writeUI8(bitmapFormat);
sos.writeUI16(bitmapWidth);
sos.writeUI16(bitmapHeight);
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
sos.writeUI8(bitmapColorTableSize);
}
sos.write(zlibBitmapData);
} catch (IOException e) {
throw new Error("This should never happen.", e);
}
return baos.toByteArray();
}
@Override
public String getImageFormat() {
return "png";
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}
/*
* Copyright (C) 2010-2015 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.tags;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.helpers.ImageHelper;
import com.jpexs.decompiler.flash.tags.base.AloneTag;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
import com.jpexs.decompiler.flash.types.BITMAPDATA;
import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.COLORMAPDATA;
import com.jpexs.decompiler.flash.types.annotations.Conditional;
import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit;
import com.jpexs.decompiler.flash.types.annotations.Internal;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.InflaterInputStream;
public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
@SWFType(BasicType.UI16)
public int characterID;
@SWFType(BasicType.UI8)
public int bitmapFormat;
@SWFType(BasicType.UI16)
public int bitmapWidth;
@SWFType(BasicType.UI16)
public int bitmapHeight;
@SWFType(BasicType.UI8)
@Conditional(value = "bitmapFormat", options = {FORMAT_8BIT_COLORMAPPED})
public int bitmapColorTableSize;
public ByteArrayRange zlibBitmapData; //TODO: Parse COLORMAPDATA,BITMAPDATA
public static final int FORMAT_8BIT_COLORMAPPED = 3;
public static final int FORMAT_15BIT_RGB = 4;
public static final int FORMAT_24BIT_RGB = 5;
@HideInRawEdit
private COLORMAPDATA colorMapData;
@HideInRawEdit
private BITMAPDATA bitmapData;
@Internal
private boolean decompressed = false;
public static final int ID = 20;
private byte[] createEmptyImage() {
try {
BITMAPDATA bitmapData = new BITMAPDATA();
bitmapData.bitmapPixelDataPix24 = new int[]{0xff000000};
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeBITMAPDATA(bitmapData, FORMAT_24BIT_RGB, 1, 1);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
return zlibOS.toByteArray();
} catch (IOException ex) {
Logger.getLogger(DefineBitsLosslessTag.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
@Override
public void setImage(byte[] data) throws IOException {
SerializableImage image = new SerializableImage(ImageHelper.read(new ByteArrayInputStream(data)));
int width = image.getWidth();
int height = image.getHeight();
bitmapData = new BITMAPDATA();
bitmapData.bitmapPixelDataPix24 = new int[width * height];
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int pos = 0; pos < pixels.length; pos++) {
// set the reserved bits to 0xff, because:
// documentation says 0, but image is sometimes broken with 0, so there is 0xff, which works (maybe alpha?)
int argb = pixels[pos] | 0xff000000;
bitmapData.bitmapPixelDataPix24[pos] = argb;
}
int format = FORMAT_24BIT_RGB;
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
SWFOutputStream sos = new SWFOutputStream(bitmapDataOS, getVersion());
sos.writeBITMAPDATA(bitmapData, format, width, height);
ByteArrayOutputStream zlibOS = new ByteArrayOutputStream();
SWFOutputStream sos2 = new SWFOutputStream(zlibOS, getVersion());
sos2.writeBytesZlib(bitmapDataOS.toByteArray());
zlibBitmapData = new ByteArrayRange(zlibOS.toByteArray());
bitmapFormat = format;
bitmapWidth = width;
bitmapHeight = height;
decompressed = false;
clearCache();
setModified(true);
}
@Override
public InputStream getImageData() {
return null;
}
@Override
public SerializableImage getImage() {
if (cachedImage != null) {
return cachedImage;
}
int[] pixels = new int[bitmapWidth * bitmapHeight];
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
COLORMAPDATA colorMapData = getColorMapData();
int pos32aligned = 0;
int pos = 0;
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
int c = 0;
int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff;
if (colorTableIndex < colorMapData.colorTableRGB.length) {
c = colorMapData.colorTableRGB[colorTableIndex];
}
pixels[pos++] = c;
pos32aligned++;
}
while ((pos32aligned % 4 != 0)) {
pos32aligned++;
}
}
} else if ((bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) || (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB)) {
BITMAPDATA bitmapData = getBitmapData();
int pos = 0;
int[] bitmapPixelData = null;
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) {
bitmapPixelData = bitmapData.bitmapPixelDataPix15;
} else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) {
bitmapPixelData = bitmapData.bitmapPixelDataPix24;
}
for (int y = 0; y < bitmapHeight; y++) {
for (int x = 0; x < bitmapWidth; x++) {
int c = bitmapPixelData[pos] | 0xff000000;
pixels[pos++] = c;
}
}
}
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_RGB, pixels);
cachedImage = bi;
return bi;
}
@Override
public int getCharacterId() {
return characterID;
}
public COLORMAPDATA getColorMapData() {
if (!decompressed) {
uncompressData();
}
return colorMapData;
}
public BITMAPDATA getBitmapData() {
if (!decompressed) {
uncompressData();
}
return bitmapData;
}
private void uncompressData() {
try {
byte[] uncompressedData = Helper.readStream(new InflaterInputStream(new ByteArrayInputStream(zlibBitmapData.getArray(), zlibBitmapData.getPos(), zlibBitmapData.getLength())));
SWFInputStream sis = new SWFInputStream(swf, uncompressedData);
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
colorMapData = sis.readCOLORMAPDATA(bitmapColorTableSize, bitmapWidth, bitmapHeight, "colorMapData");
} else if ((bitmapFormat == FORMAT_15BIT_RGB) || (bitmapFormat == FORMAT_24BIT_RGB)) {
bitmapData = sis.readBITMAPDATA(bitmapFormat, bitmapWidth, bitmapHeight, "bitmapData");
}
} catch (IOException ex) {
}
decompressed = true;
}
/**
* Constructor
*
* @param swf
*/
public DefineBitsLosslessTag(SWF swf) {
super(swf, ID, "DefineBitsLossless", null);
characterID = swf.getNextCharacterId();
bitmapFormat = DefineBitsLosslessTag.FORMAT_24BIT_RGB;
bitmapWidth = 1;
bitmapHeight = 1;
zlibBitmapData = new ByteArrayRange(createEmptyImage());
}
public DefineBitsLosslessTag(SWFInputStream sis, ByteArrayRange data) throws IOException {
super(sis.getSwf(), ID, "DefineBitsLossless", data);
readData(sis, data, 0, false, false, false);
}
@Override
public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException {
characterID = sis.readUI16("characterID");
bitmapFormat = sis.readUI8("bitmapFormat");
bitmapWidth = sis.readUI16("bitmapWidth");
bitmapHeight = sis.readUI16("bitmapHeight");
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
bitmapColorTableSize = sis.readUI8("bitmapColorTableSize");
}
zlibBitmapData = sis.readByteRangeEx(sis.available(), "zlibBitmapData");
}
/**
* Gets data bytes
*
* @return Bytes of data
*/
@Override
public byte[] getData() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
OutputStream os = baos;
SWFOutputStream sos = new SWFOutputStream(os, getVersion());
try {
sos.writeUI16(characterID);
sos.writeUI8(bitmapFormat);
sos.writeUI16(bitmapWidth);
sos.writeUI16(bitmapHeight);
if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) {
sos.writeUI8(bitmapColorTableSize);
}
sos.write(zlibBitmapData);
} catch (IOException e) {
throw new Error("This should never happen.", e);
}
return baos.toByteArray();
}
@Override
public String getImageFormat() {
return "png";
}
@Override
public void setCharacterId(int characterId) {
this.characterID = characterId;
}
}

View File

@@ -1,18 +1,19 @@
/*
* Copyright (C) 2010-2015 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.
* License along with this library.
*/
package com.jpexs.decompiler.flash.types;
import java.io.Serializable;
@@ -24,5 +25,5 @@ import java.io.Serializable;
*/
public class ALPHABITMAPDATA implements Serializable {
public int[] bitmapPixelData = new int[0];
}

View File

@@ -25,7 +25,7 @@ import java.io.Serializable;
*/
public class ALPHACOLORMAPDATA implements Serializable {
public RGBA[] colorTableRGB;
public int[] colorTableRGB;
public byte[] colorMapPixelData;
}

View File

@@ -25,7 +25,7 @@ import java.io.Serializable;
*/
public class BITMAPDATA implements Serializable {
public PIX15[] bitmapPixelDataPix15 = new PIX15[0];
public int[] bitmapPixelDataPix15 = new int[0];
public PIX24[] bitmapPixelDataPix24 = new PIX24[0];
public int[] bitmapPixelDataPix24 = new int[0];
}

View File

@@ -23,7 +23,7 @@ import java.io.Serializable;
*/
public class COLORMAPDATA implements Serializable {
public RGB[] colorTableRGB;
public int[] colorTableRGB;
public byte[] colorMapPixelData;
}

View File

@@ -16,6 +16,7 @@
*/
package com.jpexs.decompiler.flash.types;
import com.jpexs.decompiler.flash.types.annotations.Reserved;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import java.io.Serializable;
@@ -26,6 +27,10 @@ import java.io.Serializable;
*/
public class PIX15 implements Serializable {
@SWFType(value = BasicType.UB, count = 1)
@Reserved
public int reserved;
/**
* Red color value
*/

View File

@@ -509,7 +509,7 @@ public class Filtering {
return image.getRGB(0, 0, width, image.getHeight(), null, 0, width);
}
private static void setRGB(BufferedImage image, int width, int height, int[] pixels) {
public static void setRGB(BufferedImage image, int width, int height, int[] pixels) {
int type = image.getType();
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
image.getRaster().setDataElements(0, 0, width, height, pixels);

View File

@@ -61,6 +61,15 @@ public class SerializableImage implements Serializable {
image = new BufferedImage(width, height, imageType);
}
public SerializableImage(int width, int height, int imageType, int[] pixels) {
if (imageType != BufferedImage.TYPE_INT_ARGB && imageType != BufferedImage.TYPE_INT_RGB) {
throw new Error("Unsuppported image type: " + imageType);
}
image = new BufferedImage(width, height, imageType);
image.getRaster().setDataElements(0, 0, width, height, pixels);
}
public SerializableImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable<?, ?> properties) {
image = new BufferedImage(cm, raster, isRasterPremultiplied, properties);
}