Fixed: #2308 FLA export - lossless image bin files generation wrong,

some javadoc added
This commit is contained in:
Jindra Petřík
2024-09-11 18:10:29 +02:00
parent 38e49e8dbd
commit 6f3b793318
3 changed files with 170 additions and 9 deletions

View File

@@ -21,8 +21,6 @@ import com.jpexs.helpers.Helper;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -31,11 +29,18 @@ import java.util.zip.DeflaterOutputStream;
import javax.imageio.ImageIO;
/**
*
* Generates bin/*.dat file for images.
* @author JPEXS
*/
public class ImageBinDataGenerator {
/**
* Generates data
* @param is Input stream
* @param os Output stream
* @param format Image format
* @throws IOException On I/O error
*/
public void generateBinData(InputStream is, OutputStream os, ImageFormat format) throws IOException {
byte[] inputData = Helper.readStream(is);
BufferedImage bimg = ImageIO.read(new ByteArrayInputStream(inputData));
@@ -58,9 +63,9 @@ public class ImageBinDataGenerator {
w.writeUI16(bimg.getWidth());
w.writeUI16(bimg.getHeight());
w.writeUI32(0);
w.writeUI32(0);
w.writeUI32(20 * bimg.getWidth());
w.writeUI32(0);
w.writeUI32(20 * bimg.getHeight());
w.write(0x01); //has transparency
@@ -72,10 +77,27 @@ public class ImageBinDataGenerator {
for (int y = 0; y < bimg.getHeight(); y++) {
for (int x = 0; x < bimg.getWidth(); x++) {
int rgba = bimg.getRGB(x, y);
def.write((rgba >> 24) & 0xFF); //a
def.write((rgba >> 16) & 0xFF); //b
def.write((rgba >> 8) & 0xFF); //g
def.write(rgba & 0xFF); //r
int a = (rgba >> 24) & 0xFF;
int b = (rgba >> 16) & 0xFF;
int g = (rgba >> 8) & 0xFF;
int r = rgba & 0xFF;
//some weird premultiplication
if (a != 255) {
r = (int)Math.floor(r * a / 256f);
g = (int)Math.floor(g * a / 256f);
b = (int)Math.floor(b * a / 256f);
}
//also weird, but this way it works...
if (a != 0 && a != 255) {
a = a + 1;
}
def.write(a);
def.write(b);
def.write(g);
def.write(r);
}
}
def.flush();

View File

@@ -0,0 +1,128 @@
/*
* Copyright (C) 2010-2024 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.xfl;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.InflaterInputStream;
import javax.imageio.ImageIO;
/**
* Reads bin/*.dat file of lossless images and produces BufferedImage
* @author JPEXS
*/
public class LosslessImageBinDataReader {
private final DataInputStream is;
public LosslessImageBinDataReader(InputStream is) {
this.is = new DataInputStream(is);
}
public BufferedImage readImage() throws IOException {
int sign1 = readEx();
int sign2 = readEx();
if (sign1 != 0x03 || sign2 != 0x05) {
throw new IOException("Invalid image");
}
int rowSize = readUI16();
int width = readUI16();
int height = readUI16();
long frameLeft = readUI32();
long frameRight = readUI32();
long frameTop = readUI32();
long frameBottom = readUI32();
int flags = readEx();
boolean hasAlpha = (flags & 1) == 1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int variant = readEx();
if (variant == 1) { //compressed
while (true) {
int chunkLen = readUI16();
if (chunkLen == 0) {
break;
}
byte[] chunk = new byte[chunkLen];
is.readFully(chunk);
baos.write(chunk);
}
}
ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
InflaterInputStream iis = new InflaterInputStream(new ByteArrayInputStream(baos.toByteArray()));
byte[] buf = new byte[4096];
int cnt;
while ((cnt = iis.read(buf)) > 0) {
baos2.write(buf, 0, cnt);
}
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
byte[] data = baos2.toByteArray();
int pos = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int a = data[pos++] & 0xFF;
int b = data[pos++] & 0xFF;
int g = data[pos++] & 0xFF;
int r = data[pos++] & 0xFF;
if (a != 0 && a != 255) {
a = a - 1;
r = (int)Math.floor(r * 256f / a);
g = (int)Math.floor(g * 256f / a);
b = (int)Math.floor(b * 256f / a);
}
int rgba = r + (g << 8) + (b << 16) + (a << 24);
img.setRGB(x, y, rgba);
}
}
return img;
}
private int readUI16() throws IOException {
return readEx() + (readEx() << 8);
}
private long readUI32() throws IOException {
return (readEx() + (readEx() << 8) + (readEx() << 16) + (readEx() << 24)) & 0xffffffffL;
}
private int readEx() throws IOException {
int ret = is.read();
if (ret == -1) {
throw new IOException("Premature end of the file reached");
}
return ret;
}
public static void main(String[] args) throws IOException {
File f = new File("in.bin");
LosslessImageBinDataReader r = new LosslessImageBinDataReader(new FileInputStream(f));
BufferedImage i = r.readImage();
ImageIO.write(i, "PNG", new File("out.png"));
}
}

View File

@@ -33,11 +33,15 @@ import java.io.OutputStream;
import java.util.List;
/**
*
* Generates bin/*.dat file for movies.
* @author JPEXS
*/
public class MovieBinDataGenerator {
/**
* Generates empty bin data.
* @return Byte array
*/
public byte[] generateEmptyBinData() {
return new byte[]{
(byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
@@ -56,6 +60,13 @@ public class MovieBinDataGenerator {
};
}
/**
* Generates data
* @param is Input stream
* @param os Output stream
* @param fps SWF fps
* @throws IOException On I/O error
*/
public void generateBinData(InputStream is, OutputStream os, float fps) throws IOException {
BinDataOutputStream df = new BinDataOutputStream(os);
FLVInputStream flvIs = new FLVInputStream(is);