exifSegments = getAppSegments(JPEG.APP1, "Exif");
if (!exifSegments.isEmpty()) {
- JPEGSegment exif = exifSegments.get(0);
+ AppSegment exif = exifSegments.get(0);
InputStream data = exif.data();
if (data.read() == -1) {
@@ -1131,36 +1089,7 @@ public class JPEGImageReader extends ImageReaderBase {
IIOMetadata imageMetadata;
if (isLossless()) {
- return new AbstractMetadata(true, JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0, null, null, null) {
- @Override
- protected Node getNativeTree() {
- IIOMetadataNode root = new IIOMetadataNode(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
-
- root.appendChild(new IIOMetadataNode("JPEGvariety"));
- IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
- root.appendChild(markerSequence);
-
- for (JPEGSegment segment : segments) {
- switch (segment.marker()) {
- // SOF3 is the only one supported by now
- case JPEG.SOF3:
- markerSequence.appendChild(new IIOMetadataNode("sof"));
- break;
- case JPEG.DHT:
- markerSequence.appendChild(new IIOMetadataNode("dht"));
- break;
- case JPEG.DQT:
- markerSequence.appendChild(new IIOMetadataNode("dqt"));
- break;
- case JPEG.SOS:
- markerSequence.appendChild(new IIOMetadataNode("sos"));
- break;
- }
- }
-
- return root;
- }
- };
+ return new JPEGImage10Metadata(segments);
}
else {
try {
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/QuantizationTable.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/QuantizationTable.java
new file mode 100644
index 00000000..2d3a53d5
--- /dev/null
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/QuantizationTable.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 Michael Martinez
+ * Changes: Added support for selection values 2-7, fixed minor bugs &
+ * warnings, split into multiple class files, and general clean up.
+ *
+ * 08-25-2015: Helmut Dersch agreed to a license change from LGPL to MIT.
+ */
+
+/*
+ * Copyright (C) Helmut Dersch
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.twelvemonkeys.imageio.plugins.jpeg;
+
+import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
+
+import javax.imageio.stream.ImageInputStream;
+import java.io.DataInput;
+import java.io.IOException;
+
+final class QuantizationTable extends Segment {
+
+ private final int precision[] = new int[4]; // Quantization precision 8 or 16
+ private final int[] tq = new int[4]; // 1: this table is presented
+
+ protected final int quantTables[][] = new int[4][64]; // Tables
+
+ QuantizationTable() {
+ super(JPEG.DQT);
+
+ tq[0] = 0;
+ tq[1] = 0;
+ tq[2] = 0;
+ tq[3] = 0;
+ }
+
+ // TODO: Get rid of table param, make it a member?
+ protected void enhanceTables(final int[] table) throws IOException {
+ for (int t = 0; t < 4; t++) {
+ if (tq[t] != 0) {
+ enhanceQuantizationTable(quantTables[t], table);
+ }
+ }
+ }
+
+ private void enhanceQuantizationTable(final int qtab[], final int[] table) {
+ for (int i = 0; i < 8; i++) {
+ qtab[table[(0 * 8) + i]] *= 90;
+ qtab[table[(4 * 8) + i]] *= 90;
+ qtab[table[(2 * 8) + i]] *= 118;
+ qtab[table[(6 * 8) + i]] *= 49;
+ qtab[table[(5 * 8) + i]] *= 71;
+ qtab[table[(1 * 8) + i]] *= 126;
+ qtab[table[(7 * 8) + i]] *= 25;
+ qtab[table[(3 * 8) + i]] *= 106;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ qtab[table[0 + (8 * i)]] *= 90;
+ qtab[table[4 + (8 * i)]] *= 90;
+ qtab[table[2 + (8 * i)]] *= 118;
+ qtab[table[6 + (8 * i)]] *= 49;
+ qtab[table[5 + (8 * i)]] *= 71;
+ qtab[table[1 + (8 * i)]] *= 126;
+ qtab[table[7 + (8 * i)]] *= 25;
+ qtab[table[3 + (8 * i)]] *= 106;
+ }
+
+ for (int i = 0; i < 64; i++) {
+ qtab[i] >>= 6;
+ }
+ }
+
+ public static QuantizationTable read(final DataInput data, final int length) throws IOException {
+ int count = 0; // TODO: Could probably use data.getPosition for this
+
+ QuantizationTable table = new QuantizationTable();
+ while (count < length) {
+ final int temp = data.readUnsignedByte();
+ count++;
+ final int t = temp & 0x0F;
+
+ if (t > 3) {
+ throw new IOException("ERROR: Quantization table ID > 3");
+ }
+
+ table.precision[t] = temp >> 4;
+
+ if (table.precision[t] == 0) {
+ table.precision[t] = 8;
+ }
+ else if (table.precision[t] == 1) {
+ table.precision[t] = 16;
+ }
+ else {
+ throw new IOException("ERROR: Quantization table precision error");
+ }
+
+ table.tq[t] = 1;
+
+ if (table.precision[t] == 8) {
+ for (int i = 0; i < 64; i++) {
+ if (count > length) {
+ throw new IOException("ERROR: Quantization table format error");
+ }
+
+ table.quantTables[t][i] = data.readUnsignedByte();
+ count++;
+ }
+
+// table.enhanceQuantizationTable(table.quantTables[t], table);
+ }
+ else {
+ for (int i = 0; i < 64; i++) {
+ if (count > length) {
+ throw new IOException("ERROR: Quantization table format error");
+ }
+
+ table.quantTables[t][i] = data.readUnsignedShort();
+ count += 2;
+ }
+
+// table.enhanceQuantizationTable(table.quantTables[t], table);
+ }
+ }
+
+ if (count != length) {
+ throw new IOException("ERROR: Quantization table error [count!=Lq]");
+ }
+
+ return table;
+ }
+}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFComponent.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFComponent.java
deleted file mode 100644
index 3416aef8..00000000
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFComponent.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2013, Harald Kuhr
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name "TwelveMonkeys" nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.twelvemonkeys.imageio.plugins.jpeg;
-
-import java.io.Serializable;
-
-/**
-* SOFComponent
-*
-* @author Harald Kuhr
-* @author last modified by $Author: haraldk$
-* @version $Id: SOFComponent.java,v 1.0 22.04.13 16:40 haraldk Exp$
-*/
-final class SOFComponent {
- final int id;
- final int hSub;
- final int vSub;
- final int qtSel;
-
- SOFComponent(int id, int hSub, int vSub, int qtSel) {
- this.id = id;
- this.hSub = hSub;
- this.vSub = vSub;
- this.qtSel = qtSel;
- }
-
- @Override
- public String toString() {
- // Use id either as component number or component name, based on value
- Serializable idStr = (id >= 'a' && id <= 'z' || id >= 'A' && id <= 'Z') ? "'" + (char) id + "'" : id;
- return String.format("id: %s, sub: %d/%d, sel: %d", idStr, hSub, vSub, qtSel);
- }
-}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFSegment.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFSegment.java
deleted file mode 100644
index 31d5314e..00000000
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SOFSegment.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2013, Harald Kuhr
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name "TwelveMonkeys" nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package com.twelvemonkeys.imageio.plugins.jpeg;
-
-import java.io.DataInput;
-import java.io.IOException;
-import java.util.Arrays;
-
-/**
-* SOFSegment
-*
-* @author Harald Kuhr
-* @author last modified by $Author: haraldk$
-* @version $Id: SOFSegment.java,v 1.0 22.04.13 16:40 haraldk Exp$
-*/
-final class SOFSegment {
- final int marker;
- final int samplePrecision;
- final int lines; // height
- final int samplesPerLine; // width
- final SOFComponent[] components;
-
- SOFSegment(int marker, int samplePrecision, int lines, int samplesPerLine, SOFComponent[] components) {
- this.marker = marker;
- this.samplePrecision = samplePrecision;
- this.lines = lines;
- this.samplesPerLine = samplesPerLine;
- this.components = components;
- }
-
- final int componentsInFrame() {
- return components.length;
- }
-
- @Override
- public String toString() {
- return String.format(
- "SOF%d[%04x, precision: %d, lines: %d, samples/line: %d, components: %s]",
- marker & 0xff - 0xc0, marker, samplePrecision, lines, samplesPerLine, Arrays.toString(components)
- );
- }
-
- public static SOFSegment read(final int marker, final DataInput data) throws IOException {
- int samplePrecision = data.readUnsignedByte();
- int lines = data.readUnsignedShort();
- int samplesPerLine = data.readUnsignedShort();
- int componentsInFrame = data.readUnsignedByte();
-
- SOFComponent[] components = new SOFComponent[componentsInFrame];
-
- for (int i = 0; i < componentsInFrame; i++) {
- int id = data.readUnsignedByte();
- int sub = data.readUnsignedByte();
- int qtSel = data.readUnsignedByte();
-
- components[i] = new SOFComponent(id, ((sub & 0xF0) >> 4), (sub & 0xF), qtSel);
- }
-
- return new SOFSegment(marker, samplePrecision, lines, samplesPerLine, components);
- }
-}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Scan.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Scan.java
new file mode 100644
index 00000000..5e3612e6
--- /dev/null
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Scan.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, Harald Kuhr
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name "TwelveMonkeys" nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.twelvemonkeys.imageio.plugins.jpeg;
+
+import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
+import com.twelvemonkeys.imageio.stream.SubImageInputStream;
+
+import javax.imageio.IIOException;
+import javax.imageio.stream.ImageInputStream;
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.Arrays;
+
+final class Scan extends Segment {
+ final int selection; // Start of spectral or predictor selection
+ final int spectralEnd; // End of spectral selection
+ final int ah;
+ final int al;
+
+ final Component[] components;
+
+ Scan(final Component[] components, final int selection, final int spectralEnd, final int ah, final int al) {
+ super(JPEG.SOS);
+
+ this.components = components;
+ this.selection = selection;
+ this.spectralEnd = spectralEnd;
+ this.ah = ah;
+ this.al = al;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "SOS[selection: %d, spectralEnd: %d, ah: %d, al: %d, components: %s]",
+ selection, spectralEnd, ah, al, Arrays.toString(components)
+ );
+ }
+
+ public static Scan read(final ImageInputStream data) throws IOException {
+ int length = data.readUnsignedShort();
+
+ return read(new SubImageInputStream(data, length), length);
+ }
+
+ public static Scan read(final DataInput data, final int length) throws IOException {
+ int numComp = data.readUnsignedByte();
+
+ int expected = 6 + numComp * 2;
+ if (expected != length) {
+ throw new IIOException(String.format("Unexpected SOS length: %d != %d", length, expected));
+ }
+
+ Component[] components = new Component[numComp];
+
+ for (int i = 0; i < numComp; i++) {
+ int scanCompSel = data.readUnsignedByte();
+ final int temp = data.readUnsignedByte();
+
+ components[i] = new Component(scanCompSel, temp & 0x0F, temp >> 4);
+ }
+
+ int selection = data.readUnsignedByte();
+ int spectralEnd = data.readUnsignedByte();
+ int temp = data.readUnsignedByte();
+
+ return new Scan(components, selection, spectralEnd, temp >> 4, temp & 0x0F);
+ }
+
+ final static class Component {
+ final int scanCompSel; // Scan component selector
+ final int acTabSel; // AC table selector
+ final int dcTabSel; // DC table selector
+
+ Component(final int scanCompSel, final int acTabSel, final int dcTabSel) {
+ this.scanCompSel = scanCompSel;
+ this.acTabSel = acTabSel;
+ this.dcTabSel = dcTabSel;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("scanCompSel: %d, acTabSel: %d, dcTabSel: %d", scanCompSel, acTabSel, dcTabSel);
+ }
+ }
+}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Segment.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Segment.java
new file mode 100644
index 00000000..bb57b22d
--- /dev/null
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Segment.java
@@ -0,0 +1,72 @@
+package com.twelvemonkeys.imageio.plugins.jpeg;
+
+import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
+import com.twelvemonkeys.lang.Validate;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Segment.
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: harald.kuhr$
+ * @version $Id: Segment.java,v 1.0 22/08/16 harald.kuhr Exp$
+ */
+abstract class Segment {
+ final int marker;
+
+ protected Segment(final int marker) {
+ this.marker = Validate.isTrue(marker >> 8 == 0xFF, marker, "Unknown JPEG marker: 0x%04x");
+ }
+
+ public static Segment read(int marker, String identifier, int length, DataInput data) throws IOException {
+ // TODO: Fix length inconsistencies...
+// System.err.print("marker: " + marker);
+// System.err.println(" length: " + length);
+ switch (marker) {
+ case JPEG.DHT:
+ return HuffmanTable.read(data, length);
+ case JPEG.DQT:
+ return QuantizationTable.read(data, length - 2);
+ case JPEG.SOF0:
+ case JPEG.SOF1:
+ case JPEG.SOF2:
+ case JPEG.SOF3:
+ case JPEG.SOF5:
+ case JPEG.SOF6:
+ case JPEG.SOF7:
+ case JPEG.SOF9:
+ case JPEG.SOF10:
+ case JPEG.SOF11:
+ case JPEG.SOF13:
+ case JPEG.SOF14:
+ case JPEG.SOF15:
+ return Frame.read(marker, data, length);
+ case JPEG.SOS:
+ return Scan.read(data, length);
+ case JPEG.COM:
+ return Comment.read(data, length);
+ case JPEG.APP0:
+ case JPEG.APP1:
+ case JPEG.APP2:
+ case JPEG.APP3:
+ case JPEG.APP4:
+ case JPEG.APP5:
+ case JPEG.APP6:
+ case JPEG.APP7:
+ case JPEG.APP8:
+ case JPEG.APP9:
+ case JPEG.APP10:
+ case JPEG.APP11:
+ case JPEG.APP12:
+ case JPEG.APP13:
+ case JPEG.APP14:
+ case JPEG.APP15:
+ return AppSegment.read(marker, identifier, data, length);
+ // TODO: JPEG.DRI?
+ default:
+ return Unknown.read(marker, length, data);
+ }
+ }
+}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/ThumbnailReader.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/ThumbnailReader.java
index 370022c6..be3e7b28 100644
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/ThumbnailReader.java
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/ThumbnailReader.java
@@ -42,7 +42,6 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: ThumbnailReader.java,v 1.0 18.04.12 12:22 haraldk Exp$
*/
-// TODO: Get rid of the com.sun import!!
abstract class ThumbnailReader {
private final ThumbnailReadProgressListener progressListener;
@@ -68,19 +67,9 @@ abstract class ThumbnailReader {
}
static protected BufferedImage readJPEGThumbnail(final ImageReader reader, final ImageInputStream stream) throws IOException {
-// try {
-// try {
- reader.setInput(stream);
+ reader.setInput(stream);
- return reader.read(0);
-// }
-// finally {
-// input.close();
-// }
-// }
-// finally {
-// reader.dispose();
-// }
+ return reader.read(0);
}
static protected BufferedImage readRawThumbnail(final byte[] thumbnail, final int size, final int offset, int w, int h) {
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Unknown.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Unknown.java
new file mode 100644
index 00000000..9c59e504
--- /dev/null
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Unknown.java
@@ -0,0 +1,27 @@
+package com.twelvemonkeys.imageio.plugins.jpeg;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * Unknown.
+ *
+ * @author Harald Kuhr
+ * @author last modified by $Author: harald.kuhr$
+ * @version $Id: Unknown.java,v 1.0 22/08/16 harald.kuhr Exp$
+ */
+final class Unknown extends Segment {
+ final byte[] data;
+
+ private Unknown(final int marker, final byte[] data) {
+ super(marker);
+
+ this.data = data;
+ }
+
+ public static Segment read(int marker, int length, DataInput data) throws IOException {
+ byte[] bytes = new byte[length - 2];
+ data.readFully(bytes);
+ return new Unknown(marker, bytes);
+ }
+}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/ComponentSpec.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/ComponentSpec.java
index a22a4fac..3df58427 100644
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/ComponentSpec.java
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/ComponentSpec.java
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
public class ComponentSpec {
+ protected int id;
protected int hSamp; // Horizontal sampling factor
protected int quantTableSel; // Quantization table destination selector
protected int vSamp; // Vertical
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/FrameHeader.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/FrameHeader.java
index 6bf554f8..2443426b 100644
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/FrameHeader.java
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/FrameHeader.java
@@ -64,7 +64,7 @@ public class FrameHeader {
protected int read(final ImageInputStream data) throws IOException {
int count = 0;
- final int length = data.readUnsignedShort();
+ int length = data.readUnsignedShort();
count += 2;
precision = data.readUnsignedByte();
@@ -79,31 +79,31 @@ public class FrameHeader {
numComp = data.readUnsignedByte();
count++;
- //components = new ComponentSpec[numComp]; // some image exceed this range...
- components = new ComponentSpec[256]; // setting to 256 -- not sure what it should be.
+ components = new ComponentSpec[numComp];
- for (int i = 1; i <= numComp; i++) {
+ for (int i = 0; i < numComp; i++) {
if (count > length) {
throw new IOException("ERROR: frame format error");
}
- final int c = data.readUnsignedByte();
+ int cid = data.readUnsignedByte();
count++;
if (count >= length) {
throw new IOException("ERROR: frame format error [c>=Lf]");
}
- final int temp = data.readUnsignedByte();
+ int temp = data.readUnsignedByte();
count++;
- if (components[c] == null) {
- components[c] = new ComponentSpec();
+ if (components[i] == null) {
+ components[i] = new ComponentSpec();
}
- components[c].hSamp = temp >> 4;
- components[c].vSamp = temp & 0x0F;
- components[c].quantTableSel = data.readUnsignedByte();
+ components[i].id = cid;
+ components[i].hSamp = temp >> 4;
+ components[i].vSamp = temp & 0x0F;
+ components[i].quantTableSel = data.readUnsignedByte();
count++;
}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoder.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoder.java
index 2a93766f..2fe8d16e 100644
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoder.java
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoder.java
@@ -38,10 +38,14 @@ import java.io.IOException;
public class JPEGLosslessDecoder {
private final ImageInputStream input;
+
+ // TODO: Merge these classes with similar classes from the main package
+ // (FrameHeader == Frame, ComponentSpec == Frame.Component, ScanHeader == Scan etc)
private final FrameHeader frame;
private final HuffmanTable huffTable;
private final QuantizationTable quantTable;
private final ScanHeader scan;
+
private final int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];
private final int IDCT_Source[] = new int[64];
private final int nBlock[] = new int[10]; // number of blocks in the i-th Comp in a scan
@@ -224,9 +228,9 @@ public class JPEGLosslessDecoder {
final int[][] quantTables = quantTable.quantTables;
for (int i = 0; i < numComp; i++) {
- final int compN = scanComps[i].getScanCompSel();
- qTab[i] = quantTables[components[compN].quantTableSel];
- nBlock[i] = components[compN].vSamp * components[compN].hSamp;
+ ComponentSpec component = getComponentSpec(components, scanComps[i].getScanCompSel());
+ qTab[i] = quantTables[component.quantTableSel];
+ nBlock[i] = component.vSamp * component.hSamp;
dcTab[i] = HuffTab[scanComps[i].getDcTabSel()][0];
acTab[i] = HuffTab[scanComps[i].getAcTabSel()][1];
}
@@ -310,6 +314,16 @@ public class JPEGLosslessDecoder {
return outputRef;
}
+ private ComponentSpec getComponentSpec(ComponentSpec[] components, int sel) {
+ for (ComponentSpec component : components) {
+ if (component.id == sel) {
+ return component;
+ }
+ }
+
+ throw new IllegalArgumentException("No such component id: " + sel);
+ }
+
private int readScan() throws IOException {
return scan.read(input);
}
diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoderWrapper.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoderWrapper.java
index 13061b51..2a554fdd 100644
--- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoderWrapper.java
+++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/lossless/JPEGLosslessDecoderWrapper.java
@@ -1,18 +1,17 @@
package com.twelvemonkeys.imageio.plugins.jpeg.lossless;
import javax.imageio.stream.ImageInputStream;
-import java.awt.image.*;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInput;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.awt.image.DataBufferUShort;
+import java.awt.image.Raster;
import java.io.IOException;
/**
- * This class provides the conversion of a byte buffer
- * containing a JPEGLossless to an BufferedImage.
- * Therefore it uses the rii-mango JPEGLosslessDecoder
- * Library ( https://github.com/rii-mango/JPEGLosslessDecoder )
+ * This class provides the conversion of input data
+ * containing a JPEG Lossless to an BufferedImage.
*
- * Take care, that only the following lossless formats are supported
+ * Take care, that only the following lossless formats are supported:
* 1.2.840.10008.1.2.4.57 JPEG Lossless, Nonhierarchical (Processes 14)
* 1.2.840.10008.1.2.4.70 JPEG Lossless, Nonhierarchical (Processes 14 [Selection 1])
*
@@ -26,10 +25,9 @@ import java.io.IOException;
public class JPEGLosslessDecoderWrapper {
/**
- * Converts a byte buffer (containing a jpeg lossless)
- * to an Java BufferedImage
- * Currently the following conversions are supported
- * - 24Bit, RGB -> BufferedImage.TYPE_INT_RGB
+ * Decodes a JPEG Lossless stream to a {@code BufferedImage}.
+ * Currently the following conversions are supported:
+ * - 24Bit, RGB -> BufferedImage.TYPE_3BYTE_BGR
* - 8Bit, Grayscale -> BufferedImage.TYPE_BYTE_GRAY
* - 16Bit, Grayscale -> BufferedImage.TYPE_USHORT_GRAY
*
@@ -47,9 +45,9 @@ public class JPEGLosslessDecoderWrapper {
if (decoder.getNumComponents() == 1) {
switch (decoder.getPrecision()) {
case 8:
- return read8Bit1ComponentGrayScale(decoded, width, height);
+ return to8Bit1ComponentGrayScale(decoded, width, height);
case 16:
- return read16Bit1ComponentGrayScale(decoded, width, height);
+ return to16Bit1ComponentGrayScale(decoded, width, height);
default:
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and 1 component cannot be decoded");
}
@@ -58,7 +56,7 @@ public class JPEGLosslessDecoderWrapper {
if (decoder.getNumComponents() == 3) {
switch (decoder.getPrecision()) {
case 8:
- return read24Bit3ComponentRGB(decoded, width, height);
+ return to24Bit3ComponentRGB(decoded, width, height);
default:
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and 3 components cannot be decoded");
@@ -66,15 +64,15 @@ public class JPEGLosslessDecoderWrapper {
}
throw new IOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and " + decoder.getNumComponents() + " component(s) cannot be decoded");
-
}
public Raster readRaster(final ImageInputStream input) throws IOException {
+ // TODO: Can perhaps be implemented faster
return readImage(input).getRaster();
}
/**
- * converts the decoded buffer into a BufferedImage
+ * Converts the decoded buffer into a BufferedImage.
* precision: 16 bit, componentCount = 1
*
* @param decoded data buffer
@@ -82,18 +80,19 @@ public class JPEGLosslessDecoderWrapper {
* @param height of the image
* @return a BufferedImage.TYPE_USHORT_GRAY
*/
- private BufferedImage read16Bit1ComponentGrayScale(int[][] decoded, int width, int height) {
+ private BufferedImage to16Bit1ComponentGrayScale(int[][] decoded, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
short[] imageBuffer = ((DataBufferUShort) image.getRaster().getDataBuffer()).getData();
for (int i = 0; i < imageBuffer.length; i++) {
imageBuffer[i] = (short) decoded[0][i];
}
+
return image;
}
/**
- * converts the decoded buffer into a BufferedImage
+ * Converts the decoded buffer into a BufferedImage.
* precision: 8 bit, componentCount = 1
*
* @param decoded data buffer
@@ -101,34 +100,37 @@ public class JPEGLosslessDecoderWrapper {
* @param height of the image
* @return a BufferedImage.TYPE_BYTE_GRAY
*/
- private BufferedImage read8Bit1ComponentGrayScale(int[][] decoded, int width, int height) {
+ private BufferedImage to8Bit1ComponentGrayScale(int[][] decoded, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
byte[] imageBuffer = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
for (int i = 0; i < imageBuffer.length; i++) {
imageBuffer[i] = (byte) decoded[0][i];
}
+
return image;
}
/**
- * converts the decoded buffer into a BufferedImage
- * precision: 24 bit, componentCount = 3
+ * Converts the decoded buffer into a BufferedImage.
+ * precision: 8 bit, componentCount = 3
*
* @param decoded data buffer
* @param width of the image
* @param height of the image
- * @return a BufferedImage.TYPE_INT_RGB
+ * @return a BufferedImage.TYPE_3BYTE_RGB
*/
- private BufferedImage read24Bit3ComponentRGB(int[][] decoded, int width, int height) {
- // TODO: Consider 3_BYTE_BGR as this is more common?
- BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- int[] imageBuffer = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ private BufferedImage to24Bit3ComponentRGB(int[][] decoded, int width, int height) {
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+ byte[] imageBuffer = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
- for (int i = 0; i < imageBuffer.length; i++) {
- //convert to RGB
- imageBuffer[i] = (decoded[0][i] << 16) | (decoded[1][i] << 8) | (decoded[2][i]);
+ for (int i = 0; i < imageBuffer.length / 3; i++) {
+ // Convert to RGB (BGR)
+ imageBuffer[i * 3 + 2] = (byte) decoded[0][i];
+ imageBuffer[i * 3 + 1] = (byte) decoded[1][i];
+ imageBuffer[i * 3] = (byte) decoded[2][i];
}
+
return image;
}
diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFIFThumbnailReaderTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFIFThumbnailReaderTest.java
index 77b69653..4adf6fea 100644
--- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFIFThumbnailReaderTest.java
+++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFIFThumbnailReaderTest.java
@@ -36,6 +36,7 @@ import org.mockito.InOrder;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
+import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
@@ -60,7 +61,8 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertNotNull(segments);
assertFalse(segments.isEmpty());
- return new JFIFThumbnailReader(progressListener, imageIndex, thumbnailIndex, JFIFSegment.read(segments.get(0).data()));
+ JPEGSegment segment = segments.get(0);
+ return new JFIFThumbnailReader(progressListener, imageIndex, thumbnailIndex, JFIF.read(new DataInputStream(segment.segmentData()), segment.segmentLength()));
}
@Test
diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFXXThumbnailReaderTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFXXThumbnailReaderTest.java
index 0b8a6402..9b88bb9b 100644
--- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFXXThumbnailReaderTest.java
+++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JFXXThumbnailReaderTest.java
@@ -37,6 +37,7 @@ import org.mockito.InOrder;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
+import java.io.DataInputStream;
import java.io.IOException;
import java.util.List;
@@ -64,7 +65,7 @@ public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertFalse(segments.isEmpty());
JPEGSegment jfxx = segments.get(0);
- return new JFXXThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("jpeg").next(), imageIndex, thumbnailIndex, JFXXSegment.read(jfxx.data(), jfxx.length()));
+ return new JFXXThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("jpeg").next(), imageIndex, thumbnailIndex, JFXX.read(new DataInputStream(jfxx.data()), jfxx.length()));
}
@Test
diff --git a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java
index 2156710b..4db02c31 100644
--- a/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java
+++ b/imageio/imageio-jpeg/src/test/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGImageReaderTest.java
@@ -95,7 +95,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest();
+ segments = new ArrayList<>();
}
segments.add(segment);