mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 11:35:29 -04:00
Support OLD_JPEG and SubIFDs in TIFFUtilities
This commit is contained in:
parent
2955054a72
commit
8387a9ad37
@ -28,17 +28,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.contrib.tiff;
|
package com.twelvemonkeys.contrib.tiff;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.AbstractDirectory;
|
import com.twelvemonkeys.imageio.metadata.*;
|
||||||
import com.twelvemonkeys.imageio.metadata.AbstractEntry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFReader;
|
import com.twelvemonkeys.imageio.metadata.exif.EXIFReader;
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter;
|
import com.twelvemonkeys.imageio.metadata.exif.EXIFWriter;
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
@ -49,6 +46,7 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -319,24 +317,84 @@ public class TIFFUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long write(ImageOutputStream outputStream, EXIFWriter exifWriter) throws IOException {
|
private long write(ImageOutputStream outputStream, EXIFWriter exifWriter) throws IOException {
|
||||||
Entry stipOffsetsEntry = IFD.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
writeDirectoryData(IFD, outputStream);
|
||||||
long[] offsets;
|
|
||||||
if (stipOffsetsEntry.valueCount() == 1) {
|
ArrayList<Entry> newIFD = new ArrayList<Entry>();
|
||||||
offsets = new long[] {(long) stipOffsetsEntry.getValue()};
|
Iterator<Entry> it = IFD.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
newIFD.add(it.next());
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
offsets = (long[]) stipOffsetsEntry.getValue();
|
return exifWriter.writeIFD(newIFD, outputStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeDirectoryData(Directory IFD, ImageOutputStream outputStream) throws IOException {
|
||||||
|
Entry stripOffsetsEntry = IFD.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
||||||
|
long[] offsets = getValueAsLongArray(stripOffsetsEntry);
|
||||||
|
|
||||||
Entry stipByteCountsEntry = IFD.getEntryById(TIFF.TAG_STRIP_BYTE_COUNTS);
|
Entry stipByteCountsEntry = IFD.getEntryById(TIFF.TAG_STRIP_BYTE_COUNTS);
|
||||||
long[] byteCounts;
|
long[] byteCounts = getValueAsLongArray(stipByteCountsEntry);
|
||||||
if (stipOffsetsEntry.valueCount() == 1) {
|
|
||||||
byteCounts = new long[] {(long) stipByteCountsEntry.getValue()};
|
int[] newOffsets = writeData(offsets, byteCounts, outputStream);
|
||||||
|
|
||||||
|
IFD.remove(stripOffsetsEntry);
|
||||||
|
IFD.add(new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, newOffsets));
|
||||||
|
|
||||||
|
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
|
Entry oldJpegDataLength = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||||
|
if (oldJpegData != null && oldJpegData.valueCount() > 0 && oldJpegDataLength != null && oldJpegDataLength.valueCount() > 0) {
|
||||||
|
if (!Arrays.equals(getValueAsLongArray(oldJpegData), offsets) || !Arrays.equals(getValueAsLongArray(oldJpegDataLength), byteCounts)) {
|
||||||
|
offsets = getValueAsLongArray(oldJpegData);
|
||||||
|
byteCounts = getValueAsLongArray(oldJpegDataLength);
|
||||||
|
newOffsets = writeData(offsets, byteCounts, outputStream);
|
||||||
}
|
}
|
||||||
else {
|
IFD.remove(oldJpegData);
|
||||||
byteCounts = (long[]) stipByteCountsEntry.getValue();
|
IFD.add(new TIFFEntry(TIFF.TAG_JPEG_INTERCHANGE_FORMAT, newOffsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entry oldJpegTable;
|
||||||
|
long[] tableOffsets;
|
||||||
|
|
||||||
|
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);
|
||||||
|
IFD.remove(oldJpegTable);
|
||||||
|
IFD.add(new TIFFEntry(TIFF.TAG_OLD_JPEG_AC_TABLES, newOffsets));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
IFD.remove(oldJpegTable);
|
||||||
|
IFD.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);
|
||||||
|
IFD.remove(oldJpegTable);
|
||||||
|
IFD.add(new TIFFEntry(TIFF.TAG_OLD_JPEG_DC_TABLES, newOffsets));
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<Entry> it = IFD.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Entry e = it.next();
|
||||||
|
if (e.getValue() instanceof Directory) {
|
||||||
|
writeDirectoryData((Directory) e.getValue(), outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] writeData(long[] offsets, long[] byteCounts, ImageOutputStream outputStream) throws IOException {
|
||||||
int[] newOffsets = new int[offsets.length];
|
int[] newOffsets = new int[offsets.length];
|
||||||
for (int i = 0; i < offsets.length; i++) {
|
for (int i = 0; i < offsets.length; i++) {
|
||||||
newOffsets[i] = (int) outputStream.getStreamPosition();
|
newOffsets[i] = (int) outputStream.getStreamPosition();
|
||||||
@ -346,16 +404,41 @@ public class TIFFUtilities {
|
|||||||
stream.readFully(buffer);
|
stream.readFully(buffer);
|
||||||
outputStream.write(buffer);
|
outputStream.write(buffer);
|
||||||
}
|
}
|
||||||
|
return newOffsets;
|
||||||
ArrayList<Entry> newIFD = new ArrayList<Entry>();
|
|
||||||
Iterator<Entry> it = IFD.iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
newIFD.add(it.next());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newIFD.remove(stipOffsetsEntry);
|
private long[] getValueAsLongArray(Entry entry) throws IIOException {
|
||||||
newIFD.add(new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, newOffsets));
|
//TODO: code duplication from TIFFReader, should be extracted to metadata api
|
||||||
return exifWriter.writeIFD(newIFD, outputStream);
|
long[] value;
|
||||||
|
|
||||||
|
if (entry.valueCount() == 1) {
|
||||||
|
// For single entries, this will be a boxed type
|
||||||
|
value = new long[] {((Number) entry.getValue()).longValue()};
|
||||||
|
}
|
||||||
|
else if (entry.getValue() instanceof short[]) {
|
||||||
|
short[] shorts = (short[]) entry.getValue();
|
||||||
|
value = new long[shorts.length];
|
||||||
|
|
||||||
|
for (int i = 0, length = value.length; i < length; i++) {
|
||||||
|
value[i] = shorts[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry.getValue() instanceof int[]) {
|
||||||
|
int[] ints = (int[]) entry.getValue();
|
||||||
|
value = new long[ints.length];
|
||||||
|
|
||||||
|
for (int i = 0, length = value.length; i < length; i++) {
|
||||||
|
value[i] = ints[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry.getValue() instanceof long[]) {
|
||||||
|
value = (long[]) entry.getValue();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException(String.format("Unsupported %s type: %s (%s)", entry.getFieldName(), entry.getTypeName(), entry.getValue().getClass()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -419,6 +502,10 @@ public class TIFFUtilities {
|
|||||||
}
|
}
|
||||||
newIDFData.add(new TIFFEntry(TIFF.TAG_ORIENTATION, (short) orientation));
|
newIDFData.add(new TIFFEntry(TIFF.TAG_ORIENTATION, (short) orientation));
|
||||||
IFD = new AbstractDirectory(newIDFData) {
|
IFD = new AbstractDirectory(newIDFData) {
|
||||||
|
@Override
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,4 +44,8 @@ final class IFD extends AbstractDirectory {
|
|||||||
protected IFD(final Collection<? extends Entry> pEntries) {
|
protected IFD(final Collection<? extends Entry> pEntries) {
|
||||||
super(pEntries);
|
super(pEntries);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user