diff --git a/imageio/imageio-cr2/src/main/java/com/twelvemonkeys/imageio/plugins/cr2/CR2ImageReader.java b/imageio/imageio-cr2/src/main/java/com/twelvemonkeys/imageio/plugins/cr2/CR2ImageReader.java index cd0bc6c6..f9d4a9bd 100644 --- a/imageio/imageio-cr2/src/main/java/com/twelvemonkeys/imageio/plugins/cr2/CR2ImageReader.java +++ b/imageio/imageio-cr2/src/main/java/com/twelvemonkeys/imageio/plugins/cr2/CR2ImageReader.java @@ -36,6 +36,8 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment; import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil; import com.twelvemonkeys.imageio.metadata.tiff.TIFF; import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader; +import com.twelvemonkeys.imageio.plugins.jpeg.Slice; +import com.twelvemonkeys.imageio.plugins.jpeg.SliceContext; import com.twelvemonkeys.imageio.stream.SubImageInputStream; import javax.imageio.IIOException; @@ -432,17 +434,20 @@ public final class CR2ImageReader extends ImageReaderBase { int stripByteCounts = getValueAsInt(TIFF.TAG_STRIP_BYTE_COUNTS, "StripByteCounts"); long[] slices = getValueAsLongArray(50752, "Slices", true); - // Format of this array, is slices[0] = N, slices[1] = slice0.width ... slices[N + 1] = sliceN.width - if (slices[0] != slices.length - 2) { - throw new IIOException("Unexpected slices array: " + Arrays.toString(slices)); + try { + final Slice slice = Slice.createSlice(slices); + SliceContext.set(slice); + + // TODO: Get correct dimensions (sensor size?) + int width = getWidth(0); + int height = getHeight(0); + + imageInput.seek(stripOffsets); + return ImageIO.read(new SubImageInputStream(imageInput, stripByteCounts)); + } finally { + SliceContext.remove(); } - // TODO: We really have multiple slices... - // TODO: Get correct dimensions (sensor size?) - int width = getWidth(0); - int height = getHeight(0); - - imageInput.seek(stripOffsets); // byte[] data = new LosslessJPEGDecoder().decompress(new SubImageInputStream(imageInput, stripByteCounts), null); // // // TODO: We really have 2 bytes/sample @@ -477,7 +482,7 @@ public final class CR2ImageReader extends ImageReaderBase { for (int i = 0; i < numImages; i++) { int numThumbnails = reader.getNumThumbnails(i); for (int n = 0; n < numThumbnails; n++) { - showIt(reader.readThumbnail(i, n), arg + " image thumbnail" + n); + showIt(reader.readThumbnail(i, n), arg + " image " + i + " thumbnail " + n); } showIt(reader.read(i), arg + " image " + i); diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGLosslessDecoderWrapper.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGLosslessDecoderWrapper.java index 8c44f21c..47a6cf75 100644 --- a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGLosslessDecoderWrapper.java +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/JPEGLosslessDecoderWrapper.java @@ -86,6 +86,22 @@ final class JPEGLosslessDecoderWrapper { int width = decoder.getDimX(); int height = decoder.getDimY(); + if (SliceContext.isPresent()) { //QnD + final int[][] unsliced = new int[1][]; + final int componentCount = decoder.getNumComponents(); + final Slice slice = SliceContext.get(); + unsliced[0] = slice.unslice(decoded, componentCount, height); + switch (decoder.getPrecision()) { + case 8: + return to8Bit1ComponentGrayScale(unsliced, width * componentCount, height); + case 10: + case 12: + case 14: + case 16: + return to16Bit1ComponentGrayScale(unsliced, decoder.getPrecision(), width * componentCount, height); + } + } + // Single component, assumed to be Gray if (decoder.getNumComponents() == 1) { switch (decoder.getPrecision()) { diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Slice.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Slice.java new file mode 100644 index 00000000..93092202 --- /dev/null +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/Slice.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018, Oleg Ermolaev + * 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 javax.imageio.IIOException; +import java.util.Arrays; + +/** + * For CR2 RAW image. + * + * @author Oleg Ermolaev Date: 05.05.2018 2:04 + */ +public class Slice { + public static final int FIRST_WIDTH_COUNT_INDEX = 0; + public static final int FIRST_WIDTH_INDEX = 1; + public static final int LAST_WIDTH_INDEX = 2; + + private final int firstWidthCount; + private final int firstWidth; + private final int lastWidth; + + public Slice(int firstWidthCount, int firstWidth, int lastWidth) { + this.firstWidthCount = firstWidthCount; + this.firstWidth = firstWidth; + this.lastWidth = lastWidth; + } + + public static Slice createSlice(long[] values) throws IIOException { + if (values == null || values.length != 3) { + throw new IIOException("Unexpected slices array: " + Arrays.toString(values)); + } + final long firstWidthCount = values[FIRST_WIDTH_COUNT_INDEX]; + final long firstWidth = values[FIRST_WIDTH_INDEX]; + final long lastWidth = values[LAST_WIDTH_INDEX]; + if (!(0 < firstWidthCount && firstWidthCount <= Integer.MAX_VALUE) || + !(0 < firstWidth && firstWidth <= Integer.MAX_VALUE) || + !(0 < lastWidth && lastWidth <= Integer.MAX_VALUE) || + firstWidthCount * firstWidth + lastWidth > Integer.MAX_VALUE) { + throw new IIOException("Unexpected slices array: " + Arrays.toString(values)); + } + return new Slice((int) firstWidthCount, (int) firstWidth, (int) lastWidth); + } + + public int getFirstWidthCount() { + return firstWidthCount; + } + + public int getFirstWidth() { + return firstWidth; + } + + public int getLastWidth() { + return lastWidth; + } + + private int getWidth() { + return firstWidthCount * firstWidth + lastWidth; + } + + public int[] unslice(int[][] data, int componentCount, int height) throws IIOException { + final int width = getWidth(); + final int[] result = new int[width * height]; + + for (int componentIndex = 0; componentIndex < componentCount; componentIndex++) { + if (result.length != data[componentIndex].length * componentCount) { + throw new IIOException(String.format("Invalid array size for component #%d", componentIndex)); + } + } + + int position = 0; + int currentWidth = firstWidth / componentCount; + for (int sliceIndex = 0; sliceIndex < firstWidthCount + 1; ++sliceIndex) { + if (sliceIndex == firstWidthCount) { + currentWidth = lastWidth / componentCount; + } + final int sliceOffset = sliceIndex * firstWidth; + for (int y = 0; y < height; ++y) { + final int yOffset = y * width; + for (int x = 0; x < currentWidth; ++x) { + final int xOffset = x * componentCount; + for (int componentIndex = 0; componentIndex < componentCount; componentIndex++) { + result[sliceOffset + yOffset + xOffset + componentIndex] = data[componentIndex][position]; + } + position++; + } + } + } + + return result; + } +} diff --git a/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SliceContext.java b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SliceContext.java new file mode 100644 index 00000000..b431335d --- /dev/null +++ b/imageio/imageio-jpeg/src/main/java/com/twelvemonkeys/imageio/plugins/jpeg/SliceContext.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018, Oleg Ermolaev + * 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; + +/** + * QnD + * + * @author Oleg Ermolaev Date: 05.05.2018 2:13 + */ +public class SliceContext { + private static final ThreadLocal CONTEXT = new ThreadLocal<>(); + + public static boolean isPresent() { + return get() != null; + } + + public static Slice get() { + return CONTEXT.get(); + } + + public static void set(Slice slice) { + CONTEXT.set(slice); + } + + public static void remove() { + CONTEXT.remove(); + } +}