Fixed: #1153, #1347, #1552, #1553 Images export for some nonstandard JPEGs

This commit is contained in:
Jindra Petřík
2021-02-24 19:39:00 +01:00
parent e9cd0e6ad0
commit 94176f15a6
5 changed files with 165 additions and 6 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;
@@ -26,6 +27,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.JpegFixer;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
@@ -125,7 +127,15 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag {
@Override
public InputStream getOriginalImageData() {
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
JpegFixer jpegFixer = new JpegFixer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
jpegFixer.fixJpeg(new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength), baos);
} catch (IOException ex) {
Logger.getLogger(DefineBitsJPEG2Tag.class.getName()).log(Level.SEVERE, null, ex);
}
return new ByteArrayInputStream(baos.toByteArray());
}
@Override

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;
@@ -27,6 +28,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.JpegFixer;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
@@ -174,7 +176,14 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
public InputStream getOriginalImageData() {
if (bitmapAlphaData.getLength() == 0) { // No alpha
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
JpegFixer jpegFixer = new JpegFixer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
jpegFixer.fixJpeg(new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength), baos);
} catch (IOException ex) {
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, null, ex);
}
return new ByteArrayInputStream(baos.toByteArray());
}
return null;

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;
@@ -27,6 +28,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.JpegFixer;
import com.jpexs.helpers.SerializableImage;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
@@ -178,7 +180,15 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
@Override
public InputStream getOriginalImageData() {
if (bitmapAlphaData.getLength() == 0) { // No alpha
if (bitmapAlphaData.getLength() == 0) { // No alpha
JpegFixer jpegFixer = new JpegFixer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
jpegFixer.fixJpeg(new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()), baos);
} catch (IOException ex) {
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, null, ex);
}
return new ByteArrayInputStream(baos.toByteArray());
}
return null;

View File

@@ -0,0 +1,129 @@
package com.jpexs.helpers;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Fixes probles in some JPEGs to be readable by standard viewers.
*
* @author JPEXS
*/
public class JpegFixer {
private static final int SOI = 0xD8;
private static final int EOI = 0xD9;
private static final int SOF0 = 0xC0;
private static final int SOF1 = 0xC1;
private static final int SOF2 = 0xC2;
private static final int SOF3 = 0xC3;
private static final int SOF5 = 0xC5;
private static final int SOF6 = 0xC6;
private static final int SOF7 = 0xC7;
private static final int SOF9 = 0xC9;
private static final int SOF10 = 0xCA;
private static final int SOF11 = 0xCB;
private static final int SOF13 = 0xCD;
private static final int SOF14 = 0xCE;
private static final int SOF15 = 0xCF;
private static final int APP0 = 0xE0;
public void fixJpeg(InputStream is, OutputStream os) throws IOException {
List<byte[]> data = new ArrayList<>();
List<Integer> markers = new ArrayList<>();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int lastMarker = -1;
int val = is.read();
if (val == -1) {
return;
}
if (val == 0xFF) {
val = is.read();
if (val != SOI) {
//not a JPEG file, proceed as is
os.write(0xFF);
os.write(val);
while ((val = is.read()) > -1) {
os.write(val);
}
return;
}
} else {
//not a JPEG file, proceed as is
os.write(val);
while ((val = is.read()) > -1) {
os.write(val);
}
return;
}
while ((val = is.read()) > -1) {
if (val == 0xFF) {
val = is.read();
if (val == 0) {
baos.write(0xff);
baos.write(val);
continue;
}
} else {
baos.write(val);
continue;
}
if (lastMarker > -1) {
data.add(baos.toByteArray());
markers.add(lastMarker);
baos = new ByteArrayOutputStream();
}
lastMarker = val;
}
if (lastMarker > -1) {
data.add(baos.toByteArray());
markers.add(lastMarker);
}
boolean wasApp0 = false;
for (int i = 0; i < data.size(); i++) {
if (markers.get(i) == APP0) {
wasApp0 = true;
}
if (i > 0 && markers.get(i) == SOI && markers.get(i - 1) == EOI && !wasApp0) {
markers.remove(i);
data.remove(i);
markers.remove(i - 1);
data.remove(i - 1);
i--;
List<byte[]> dataToMove = new ArrayList<>();
List<Integer> markersToMove = new ArrayList<>();
for (int j = i; j < data.size(); j++) {
//move these data up
if (markers.get(j) == APP0 || Arrays.asList(SOF0, SOF1, SOF2, SOF3, SOF5, SOF6, SOF7, SOF9, SOF10, SOF11, SOF13, SOF14, SOF15).contains(markers.get(j))) {
markersToMove.add(markers.get(j));
dataToMove.add(data.get(j));
data.remove(j);
markers.remove(j);
j--;
} else {
break;
}
}
data.addAll(1, dataToMove);
markers.addAll(1, markersToMove);
break;
}
}
os.write(0xFF);
os.write(SOI);
for (int i = 0; i < data.size(); i++) {
os.write(0xFF);
os.write(markers.get(i));
os.write(data.get(i));
}
}
}