mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-02 02:55:28 -04:00
Transform old-style JPEG to new-style
merge JPEGTables & switching compression tag done handling JPEGInterchangeFormat tbd
This commit is contained in:
parent
65cab331d1
commit
1c642fbb7d
@ -33,6 +33,7 @@ import com.twelvemonkeys.imageio.metadata.AbstractDirectory;
|
||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||
@ -45,6 +46,8 @@ import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -348,6 +351,12 @@ public final class TIFFUtilities {
|
||||
byteCounts = getValueAsLongArray(stripByteCountsEntry);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// numStrips == 1 && JpegInterchangeFormat == StripOffset -> just remove InterchangeFormat/Length
|
||||
// numStrips >= 1 && JpegInterchangeFormat+JpegInterchangeFormatLength not within stip data -> prepend to each strip? Suspecting those to contain (just) table data.
|
||||
// else fail
|
||||
// TODO: Find some way to enable checking if the transformed pages could really be read or at least notify the transform to the user
|
||||
|
||||
// Write JPEGInterchangeFormat data before StripByteData, as our reader expects the JPEG data to follow if it is not included
|
||||
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||
boolean writeInterchangeFormat = false;
|
||||
@ -389,42 +398,105 @@ public final class TIFFUtilities {
|
||||
}
|
||||
}
|
||||
|
||||
Entry oldJpegTable;
|
||||
long[] tableOffsets;
|
||||
Validate.isTrue(IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT) == null, "Failed to transform old-style JPEG");
|
||||
Validate.isTrue(IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) == null, "Failed to transform old-style JPEG");
|
||||
|
||||
oldJpegTable = IFD.getEntryById(TIFF.TAG_OLD_JPEG_AC_TABLES);
|
||||
if (oldJpegTable != null && oldJpegTable.valueCount() > 0) {
|
||||
tableOffsets = getValueAsLongArray(oldJpegTable);
|
||||
byteCounts = new long[tableOffsets.length];
|
||||
Arrays.fill(byteCounts, 64);
|
||||
newOffsets = writeData(tableOffsets, byteCounts, outputStream);
|
||||
newIFD.remove(oldJpegTable);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_OLD_JPEG_AC_TABLES, newOffsets));
|
||||
Entry oldJpegTableQ, oldJpegTableDC, oldJpegTableAC;
|
||||
oldJpegTableQ = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
|
||||
oldJpegTableDC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
|
||||
oldJpegTableAC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_AC_TABLES);
|
||||
if (oldJpegTableQ != null || oldJpegTableDC != null || oldJpegTableAC != null) {
|
||||
Validate.isTrue(IFD.getEntryById(TIFF.TAG_JPEG_TABLES) == null, "Found old-style and new-style JPEGTables");
|
||||
|
||||
newIFD.add(mergeTables(oldJpegTableQ, oldJpegTableDC, oldJpegTableAC));
|
||||
if (oldJpegTableQ != null) {
|
||||
newIFD.remove(oldJpegTableQ);
|
||||
}
|
||||
if (oldJpegTableDC != null) {
|
||||
newIFD.remove(oldJpegTableDC);
|
||||
}
|
||||
if (oldJpegTableAC != null) {
|
||||
newIFD.remove(oldJpegTableAC);
|
||||
}
|
||||
}
|
||||
|
||||
oldJpegTable = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
|
||||
if (oldJpegTable != null && oldJpegTable.valueCount() > 0) {
|
||||
tableOffsets = getValueAsLongArray(oldJpegTable);
|
||||
byteCounts = new long[tableOffsets.length];
|
||||
Arrays.fill(byteCounts, 64);
|
||||
newOffsets = writeData(tableOffsets, byteCounts, outputStream);
|
||||
newIFD.remove(oldJpegTable);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_OLD_JPEG_Q_TABLES, newOffsets));
|
||||
}
|
||||
|
||||
oldJpegTable = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
|
||||
if (oldJpegTable != null && oldJpegTable.valueCount() > 0) {
|
||||
tableOffsets = getValueAsLongArray(oldJpegTable);
|
||||
byteCounts = new long[tableOffsets.length];
|
||||
Arrays.fill(byteCounts, 64);
|
||||
newOffsets = writeData(tableOffsets, byteCounts, outputStream);
|
||||
newIFD.remove(oldJpegTable);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_OLD_JPEG_DC_TABLES, newOffsets));
|
||||
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
|
||||
Number compression = (Number) compressionEntry.getValue();
|
||||
if (compression.shortValue() == TIFFExtension.COMPRESSION_OLD_JPEG) {
|
||||
newIFD.remove(compressionEntry);
|
||||
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
|
||||
}
|
||||
|
||||
return newIFD;
|
||||
}
|
||||
|
||||
private Entry mergeTables(Entry qEntry, Entry dcEntry, Entry acEntry) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(bos);
|
||||
dos.writeShort(JPEG.SOI);
|
||||
|
||||
if (qEntry != null && qEntry.valueCount() > 0) {
|
||||
long[] off = getValueAsLongArray(qEntry);
|
||||
byte[] table = new byte[64];
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
stream.readFully(table);
|
||||
dos.writeShort(JPEG.DQT);
|
||||
dos.writeShort(3 + 64);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
}
|
||||
}
|
||||
|
||||
// same marker for AC & DC tables, distinguished by flag in tableId
|
||||
if (dcEntry != null && dcEntry.valueCount() > 0) {
|
||||
long[] off = getValueAsLongArray(dcEntry);
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(tableId);
|
||||
dos.write(table);
|
||||
}
|
||||
}
|
||||
|
||||
if (acEntry != null && acEntry.valueCount() > 0) {
|
||||
long[] off = getValueAsLongArray(acEntry);
|
||||
for (int tableId = 0; tableId < off.length; tableId++) {
|
||||
stream.seek(off[tableId]);
|
||||
byte[] table = readHUFFTable();
|
||||
dos.writeShort(JPEG.DHT);
|
||||
dos.writeShort(3 + table.length);
|
||||
dos.writeByte(16 | tableId);
|
||||
dos.write(table);
|
||||
}
|
||||
}
|
||||
|
||||
dos.writeShort(JPEG.EOI);
|
||||
|
||||
bos.close();
|
||||
|
||||
return new TIFFEntry(TIFF.TAG_JPEG_TABLES, TIFF.TYPE_UNDEFINED, bos.toByteArray());
|
||||
}
|
||||
|
||||
private byte[] readHUFFTable() throws IOException {
|
||||
byte[] lengths = new byte[16];
|
||||
stream.readFully(lengths);
|
||||
int numCodes = 0;
|
||||
for (int i = 0; i < lengths.length; i++) {
|
||||
numCodes += lengths[i];
|
||||
}
|
||||
byte table[] = new byte[16 + numCodes];
|
||||
System.arraycopy(lengths, 0, table, 0, 16);
|
||||
int off = 16;
|
||||
for (int i = 0; i < lengths.length; i++) {
|
||||
stream.read(table, off, lengths[i]);
|
||||
off += lengths[i];
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
private int[] writeData(long[] offsets, long[] byteCounts, ImageOutputStream outputStream) throws IOException {
|
||||
int[] newOffsets = new int[offsets.length];
|
||||
for (int i = 0; i < offsets.length; i++) {
|
||||
@ -540,6 +612,7 @@ public final class TIFFUtilities {
|
||||
/**
|
||||
* TODO: Temporary clone, to be removed after TMI204 has been closed
|
||||
*/
|
||||
|
||||
public interface TIFFExtension {
|
||||
int ORIENTATION_TOPRIGHT = 2;
|
||||
int ORIENTATION_BOTRIGHT = 3;
|
||||
@ -548,6 +621,11 @@ public final class TIFFUtilities {
|
||||
int ORIENTATION_RIGHTTOP = 6;
|
||||
int ORIENTATION_RIGHTBOT = 7;
|
||||
int ORIENTATION_LEFTBOT = 8;
|
||||
|
||||
/** Deprecated. For backwards compatibility only ("Old-style" JPEG). */
|
||||
int COMPRESSION_OLD_JPEG = 6;
|
||||
/** JPEG Compression (lossy). */
|
||||
int COMPRESSION_JPEG = 7;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user