faster DefineBitsLosslessX reading

This commit is contained in:
2015-05-08 20:54:48 +02:00
parent 8a784d2d0b
commit 6d49dc584d
13 changed files with 7173 additions and 7030 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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;
}
}
@@ -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;
}
}
@@ -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 ARGB[] bitmapPixelData = new ARGB[0];
public int[] bitmapPixelData = new int[0];
}
@@ -25,7 +25,7 @@ import java.io.Serializable;
*/
public class ALPHACOLORMAPDATA implements Serializable {
public RGBA[] colorTableRGB;
public int[] colorTableRGB;
public byte[] colorMapPixelData;
}
@@ -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];
}
@@ -23,7 +23,7 @@ import java.io.Serializable;
*/
public class COLORMAPDATA implements Serializable {
public RGB[] colorTableRGB;
public int[] colorTableRGB;
public byte[] colorMapPixelData;
}
@@ -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
*/
@@ -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);
@@ -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);
}