DefineBits (with JPEGTables) tags export fixed

This commit is contained in:
Jindra Petřík
2018-05-28 20:42:49 +02:00
parent 02660f396e
commit 83d42253c4
2 changed files with 63 additions and 5 deletions

View File

@@ -12,7 +12,8 @@
* 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.tags;
import com.jpexs.decompiler.flash.SWF;
@@ -25,6 +26,7 @@ import com.jpexs.decompiler.flash.types.BasicType;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.annotations.SWFVersion;
import com.jpexs.helpers.ByteArrayRange;
import com.jpexs.helpers.Helper;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
@@ -32,6 +34,9 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -112,19 +117,71 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
return ImageFormat.JPEG;
}
private static List<byte[]> parseJpegChunks(byte[] data) {
//A little inspired by shum way :-)
List<byte[]> ret = new ArrayList<>();
int pos = 0;
int n = data.length;
// Finding first marker, and skipping the data before this marker.
// (FF 00 - code is escaped FF; FF FF ... (FF xx) - fill bytes before marker).
while (pos < n && ((data[pos] & 0xFF) != 0xFF
|| (pos + 1 < n && ((data[pos + 1] & 0xFF) == 0x00 || (data[pos + 1] & 0xFF) == 0xFF)))) {
pos++;
}
while (pos < n) {
int start = pos++;
int code = data[pos++] & 0xFF;
// Some tags have length field -- using it
if ((code >= 0xC0 && code <= 0xC7)
|| (code >= 0xC9 && code <= 0xCF)
|| (code >= 0xDA && code <= 0xEF)
|| code == 0xFE) {
int length = (data[pos] & 0xFF) << 8 + (data[pos + 1] & 0xFF);
pos += length;
}
// Finding next marker.
while (pos < n && ((data[pos] & 0xFF) != 0xFF
|| (pos + 1 < n && ((data[pos + 1] & 0xff) == 0x00 || (data[pos + 1] & 0xFF) == 0xFF)))) {
pos++;
}
if (code == 0xD8 || code == 0xD9) {
// Removing SOI and EOI to avoid wrong EOI-SOI pairs in the middle.
continue;
}
ret.add(Arrays.copyOfRange(data, start, pos));
}
return ret;
}
@Override
public InputStream getOriginalImageData() {
if (swf.getJtt() != null) {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int errorLength = hasErrorHeader(jpegData) ? 4 : 0;
List<byte[]> jpegChunks = parseJpegChunks(jpegData.getRangeData(errorLength, jpegData.getLength() - errorLength));
ByteArrayRange jttdata = swf.getJtt().jpegData;
if (jttdata.getLength() != 0) {
int jttErrorLength = hasErrorHeader(jttdata) ? 4 : 0;
int jttErrorLength = hasErrorHeader(jttdata) ? 4 : 0;
List<byte[]> chunksJtt = parseJpegChunks(jttdata.getRangeData(jttErrorLength, jttdata.getLength() - jttErrorLength));
for (int c = 0; c < jpegChunks.size(); c++) {
int chunkType = (jpegChunks.get(c)[1] & 0xFF);
if (chunkType >= 0xC0 && chunkType <= 0xCF) {
jpegChunks.addAll(c, chunksJtt);
break;
}
}
}
jpegChunks.add(0, new byte[]{(byte) 0xFF, (byte) 0xD8}); //SOI to beginning
jpegChunks.add(new byte[]{(byte) 0xFF, (byte) 0xD9}); //EOI to the end
int errorLength = hasErrorHeader(jpegData) ? 4 : 0;
baos.write(jpegData.getArray(), jpegData.getPos() + errorLength, jpegData.getLength() - errorLength);
for (byte[] chunk : jpegChunks) {
baos.write(chunk);
}
return new ByteArrayInputStream(baos.toByteArray());
} catch (IOException ex) {
// this should never happen, since IOException comes from OutputStream, but ByteArrayOutputStream should never throw it