#304 TIFF JPEG Lossless support

This commit is contained in:
Harald Kuhr
2017-01-18 18:59:38 +01:00
parent 2e90e4b897
commit 3b76d9fcfd
11 changed files with 214 additions and 49 deletions

View File

@@ -148,7 +148,7 @@ class JPEGImage10Metadata extends AbstractMetadata {
if (segment instanceof Frame) {
Frame sofSegment = (Frame) segment;
IIOMetadataNode colorSpaceType = new IIOMetadataNode("ColorSpaceType");
colorSpaceType.setAttribute("name", sofSegment.componentsInFrame() == 1 ? "Gray" : "RGB"); // TODO YCC, YCCK, CMYK etc
colorSpaceType.setAttribute("name", sofSegment.componentsInFrame() == 1 ? "GRAY" : "RGB"); // TODO YCC, YCCK, CMYK etc
chroma.appendChild(colorSpaceType);
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");

View File

@@ -352,10 +352,24 @@ public final class JPEGImageReader extends ImageReaderBase {
JPEGColorSpace sourceCSType = getSourceCSType(getJFIF(), adobeDCT, sof);
if (sof.marker == JPEG.SOF3) {
// Read image as lossless
if (DEBUG) {
System.out.println("Reading using Lossless decoder");
}
// TODO: What about stream position?
// TODO: Param handling: Source region, offset, subsampling, destination, destination type, etc....
// Read image as lossless
return new JPEGLosslessDecoderWrapper(this).readImage(segments, imageInput);
BufferedImage bufferedImage = new JPEGLosslessDecoderWrapper(this).readImage(segments, imageInput);
// TODO: This is QnD, move param handling to lossless wrapper
// TODO: Create test!
BufferedImage destination = param != null ? param.getDestination() : null;
if (destination != null) {
destination.getRaster().setDataElements(0, 0, bufferedImage.getRaster());
return destination;
}
return bufferedImage;
}
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
@@ -382,6 +396,18 @@ public final class JPEGImageReader extends ImageReaderBase {
return delegate.read(imageIndex, param);
}
static void drawOnto(final BufferedImage pDestination, final Image pSource) {
Graphics2D g = pDestination.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
g.drawImage(pSource, 0, 0, null);
}
finally {
g.dispose();
}
}
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, Frame startOfFrame, JPEGColorSpace csType, ICC_Profile profile) throws IOException {
int origWidth = getWidth(imageIndex);
int origHeight = getHeight(imageIndex);

View File

@@ -33,10 +33,9 @@ import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
import javax.imageio.IIOException;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferUShort;
import java.awt.image.Raster;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.*;
import java.io.IOException;
import java.util.List;
@@ -71,7 +70,7 @@ final class JPEGLosslessDecoderWrapper {
* - 16Bit, Grayscale -> BufferedImage.TYPE_USHORT_GRAY
*
* @param segments segments
* @param input input stream which contains a jpeg lossless data
* @param input input stream which contains JPEG Lossless data
* @return if successfully a BufferedImage is returned
* @throws IOException is thrown if the decoder failed or a conversion is not supported
*/
@@ -92,8 +91,11 @@ final class JPEGLosslessDecoderWrapper {
switch (decoder.getPrecision()) {
case 8:
return to8Bit1ComponentGrayScale(decoded, width, height);
case 10:
case 12:
case 14:
case 16:
return to16Bit1ComponentGrayScale(decoded, width, height);
return to16Bit1ComponentGrayScale(decoded, decoder.getPrecision(), width, height);
}
}
// 3 components, assumed to be RGB
@@ -121,12 +123,20 @@ final class JPEGLosslessDecoderWrapper {
* precision: 16 bit, componentCount = 1
*
* @param decoded data buffer
* @param precision
* @param width of the image
* @param height of the image
* @return a BufferedImage.TYPE_USHORT_GRAY
* @param height of the image @return a BufferedImage.TYPE_USHORT_GRAY
*/
private BufferedImage to16Bit1ComponentGrayScale(int[][] decoded, int width, int height) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
private BufferedImage to16Bit1ComponentGrayScale(int[][] decoded, int precision, int width, int height) {
BufferedImage image;
if (precision == 16) {
image = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_GRAY);
}
else {
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), new int[] {precision}, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
image = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(width, height), colorModel.isAlphaPremultiplied(), null);
}
short[] imageBuffer = ((DataBufferUShort) image.getRaster().getDataBuffer()).getData();
for (int i = 0; i < imageBuffer.length; i++) {