| Index: java/org/libjpegturbo/turbojpeg/TJDecompressor.java
|
| diff --git a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bd0e6943d977aa8243360efb181f9e2230475f48
|
| --- /dev/null
|
| +++ b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java
|
| @@ -0,0 +1,909 @@
|
| +/*
|
| + * Copyright (C)2011-2015 D. R. Commander. All Rights Reserved.
|
| + * Copyright (C)2015 Viktor Szathmáry. 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 of the libjpeg-turbo Project 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 HOLDERS 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 org.libjpegturbo.turbojpeg;
|
| +
|
| +import java.awt.image.*;
|
| +import java.nio.*;
|
| +import java.io.*;
|
| +
|
| +/**
|
| + * TurboJPEG decompressor
|
| + */
|
| +public class TJDecompressor implements Closeable {
|
| +
|
| + private static final String NO_ASSOC_ERROR =
|
| + "No JPEG image is associated with this instance";
|
| +
|
| + /**
|
| + * Create a TurboJPEG decompresssor instance.
|
| + */
|
| + public TJDecompressor() throws TJException {
|
| + init();
|
| + }
|
| +
|
| + /**
|
| + * Create a TurboJPEG decompressor instance and associate the JPEG source
|
| + * image stored in <code>jpegImage</code> with the newly created instance.
|
| + *
|
| + * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
|
| + * be the length of the array.) This buffer is not modified.
|
| + */
|
| + public TJDecompressor(byte[] jpegImage) throws TJException {
|
| + init();
|
| + setSourceImage(jpegImage, jpegImage.length);
|
| + }
|
| +
|
| + /**
|
| + * Create a TurboJPEG decompressor instance and associate the JPEG source
|
| + * image of length <code>imageSize</code> bytes stored in
|
| + * <code>jpegImage</code> with the newly created instance.
|
| + *
|
| + * @param jpegImage JPEG image buffer. This buffer is not modified.
|
| + *
|
| + * @param imageSize size of the JPEG image (in bytes)
|
| + */
|
| + public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
|
| + init();
|
| + setSourceImage(jpegImage, imageSize);
|
| + }
|
| +
|
| + /**
|
| + * Create a TurboJPEG decompressor instance and associate the YUV planar
|
| + * source image stored in <code>yuvImage</code> with the newly created
|
| + * instance.
|
| + *
|
| + * @param yuvImage {@link YUVImage} instance containing a YUV planar
|
| + * image to be decoded. This image is not modified.
|
| + */
|
| + public TJDecompressor(YUVImage yuvImage) throws TJException {
|
| + init();
|
| + setSourceImage(yuvImage);
|
| + }
|
| +
|
| + /**
|
| + * Associate the JPEG image of length <code>imageSize</code> bytes stored in
|
| + * <code>jpegImage</code> with this decompressor instance. This image will
|
| + * be used as the source image for subsequent decompress operations.
|
| + *
|
| + * @param jpegImage JPEG image buffer. This buffer is not modified.
|
| + *
|
| + * @param imageSize size of the JPEG image (in bytes)
|
| + */
|
| + public void setSourceImage(byte[] jpegImage, int imageSize)
|
| + throws TJException {
|
| + if (jpegImage == null || imageSize < 1)
|
| + throw new IllegalArgumentException("Invalid argument in setSourceImage()");
|
| + jpegBuf = jpegImage;
|
| + jpegBufSize = imageSize;
|
| + decompressHeader(jpegBuf, jpegBufSize);
|
| + yuvImage = null;
|
| + }
|
| +
|
| + /**
|
| + * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
|
| + */
|
| + @Deprecated
|
| + public void setJPEGImage(byte[] jpegImage, int imageSize)
|
| + throws TJException {
|
| + setSourceImage(jpegImage, imageSize);
|
| + }
|
| +
|
| + /**
|
| + * Associate the specified YUV planar source image with this decompressor
|
| + * instance. Subsequent decompress operations will decode this image into an
|
| + * RGB or grayscale destination image.
|
| + *
|
| + * @param srcImage {@link YUVImage} instance containing a YUV planar image to
|
| + * be decoded. This image is not modified.
|
| + */
|
| + public void setSourceImage(YUVImage srcImage) {
|
| + if (srcImage == null)
|
| + throw new IllegalArgumentException("Invalid argument in setSourceImage()");
|
| + yuvImage = srcImage;
|
| + jpegBuf = null;
|
| + jpegBufSize = 0;
|
| + }
|
| +
|
| +
|
| + /**
|
| + * Returns the width of the source image (JPEG or YUV) associated with this
|
| + * decompressor instance.
|
| + *
|
| + * @return the width of the source image (JPEG or YUV) associated with this
|
| + * decompressor instance.
|
| + */
|
| + public int getWidth() {
|
| + if (yuvImage != null)
|
| + return yuvImage.getWidth();
|
| + if (jpegWidth < 1)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + return jpegWidth;
|
| + }
|
| +
|
| + /**
|
| + * Returns the height of the source image (JPEG or YUV) associated with this
|
| + * decompressor instance.
|
| + *
|
| + * @return the height of the source image (JPEG or YUV) associated with this
|
| + * decompressor instance.
|
| + */
|
| + public int getHeight() {
|
| + if (yuvImage != null)
|
| + return yuvImage.getHeight();
|
| + if (jpegHeight < 1)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + return jpegHeight;
|
| + }
|
| +
|
| + /**
|
| + * Returns the level of chrominance subsampling used in the source image
|
| + * (JPEG or YUV) associated with this decompressor instance. See
|
| + * {@link TJ#SAMP_444 TJ.SAMP_*}.
|
| + *
|
| + * @return the level of chrominance subsampling used in the source image
|
| + * (JPEG or YUV) associated with this decompressor instance.
|
| + */
|
| + public int getSubsamp() {
|
| + if (yuvImage != null)
|
| + return yuvImage.getSubsamp();
|
| + if (jpegSubsamp < 0)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (jpegSubsamp >= TJ.NUMSAMP)
|
| + throw new IllegalStateException("JPEG header information is invalid");
|
| + return jpegSubsamp;
|
| + }
|
| +
|
| + /**
|
| + * Returns the colorspace used in the source image (JPEG or YUV) associated
|
| + * with this decompressor instance. See {@link TJ#CS_RGB TJ.CS_*}. If the
|
| + * source image is YUV, then this always returns {@link TJ#CS_YCbCr}.
|
| + *
|
| + * @return the colorspace used in the source image (JPEG or YUV) associated
|
| + * with this decompressor instance.
|
| + */
|
| + public int getColorspace() {
|
| + if (yuvImage != null)
|
| + return TJ.CS_YCbCr;
|
| + if (jpegColorspace < 0)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (jpegColorspace >= TJ.NUMCS)
|
| + throw new IllegalStateException("JPEG header information is invalid");
|
| + return jpegColorspace;
|
| + }
|
| +
|
| + /**
|
| + * Returns the JPEG image buffer associated with this decompressor instance.
|
| + *
|
| + * @return the JPEG image buffer associated with this decompressor instance.
|
| + */
|
| + public byte[] getJPEGBuf() {
|
| + if (jpegBuf == null)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + return jpegBuf;
|
| + }
|
| +
|
| + /**
|
| + * Returns the size of the JPEG image (in bytes) associated with this
|
| + * decompressor instance.
|
| + *
|
| + * @return the size of the JPEG image (in bytes) associated with this
|
| + * decompressor instance.
|
| + */
|
| + public int getJPEGSize() {
|
| + if (jpegBufSize < 1)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + return jpegBufSize;
|
| + }
|
| +
|
| + /**
|
| + * Returns the width of the largest scaled-down image that the TurboJPEG
|
| + * decompressor can generate without exceeding the desired image width and
|
| + * height.
|
| + *
|
| + * @param desiredWidth desired width (in pixels) of the decompressed image.
|
| + * Setting this to 0 is the same as setting it to the width of the JPEG image
|
| + * (in other words, the width will not be considered when determining the
|
| + * scaled image size.)
|
| + *
|
| + * @param desiredHeight desired height (in pixels) of the decompressed image.
|
| + * Setting this to 0 is the same as setting it to the height of the JPEG
|
| + * image (in other words, the height will not be considered when determining
|
| + * the scaled image size.)
|
| + *
|
| + * @return the width of the largest scaled-down image that the TurboJPEG
|
| + * decompressor can generate without exceeding the desired image width and
|
| + * height.
|
| + */
|
| + public int getScaledWidth(int desiredWidth, int desiredHeight) {
|
| + if (jpegWidth < 1 || jpegHeight < 1)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (desiredWidth < 0 || desiredHeight < 0)
|
| + throw new IllegalArgumentException("Invalid argument in getScaledWidth()");
|
| + TJScalingFactor[] sf = TJ.getScalingFactors();
|
| + if (desiredWidth == 0)
|
| + desiredWidth = jpegWidth;
|
| + if (desiredHeight == 0)
|
| + desiredHeight = jpegHeight;
|
| + int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
|
| + for (int i = 0; i < sf.length; i++) {
|
| + scaledWidth = sf[i].getScaled(jpegWidth);
|
| + scaledHeight = sf[i].getScaled(jpegHeight);
|
| + if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
|
| + break;
|
| + }
|
| + if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
|
| + throw new IllegalArgumentException("Could not scale down to desired image dimensions");
|
| + return scaledWidth;
|
| + }
|
| +
|
| + /**
|
| + * Returns the height of the largest scaled-down image that the TurboJPEG
|
| + * decompressor can generate without exceeding the desired image width and
|
| + * height.
|
| + *
|
| + * @param desiredWidth desired width (in pixels) of the decompressed image.
|
| + * Setting this to 0 is the same as setting it to the width of the JPEG image
|
| + * (in other words, the width will not be considered when determining the
|
| + * scaled image size.)
|
| + *
|
| + * @param desiredHeight desired height (in pixels) of the decompressed image.
|
| + * Setting this to 0 is the same as setting it to the height of the JPEG
|
| + * image (in other words, the height will not be considered when determining
|
| + * the scaled image size.)
|
| + *
|
| + * @return the height of the largest scaled-down image that the TurboJPEG
|
| + * decompressor can generate without exceeding the desired image width and
|
| + * height.
|
| + */
|
| + public int getScaledHeight(int desiredWidth, int desiredHeight) {
|
| + if (jpegWidth < 1 || jpegHeight < 1)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (desiredWidth < 0 || desiredHeight < 0)
|
| + throw new IllegalArgumentException("Invalid argument in getScaledHeight()");
|
| + TJScalingFactor[] sf = TJ.getScalingFactors();
|
| + if (desiredWidth == 0)
|
| + desiredWidth = jpegWidth;
|
| + if (desiredHeight == 0)
|
| + desiredHeight = jpegHeight;
|
| + int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
|
| + for (int i = 0; i < sf.length; i++) {
|
| + scaledWidth = sf[i].getScaled(jpegWidth);
|
| + scaledHeight = sf[i].getScaled(jpegHeight);
|
| + if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
|
| + break;
|
| + }
|
| + if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
|
| + throw new IllegalArgumentException("Could not scale down to desired image dimensions");
|
| + return scaledHeight;
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image or decode the YUV source image associated
|
| + * with this decompressor instance and output a grayscale, RGB, or CMYK image
|
| + * to the given destination buffer.
|
| + *
|
| + * @param dstBuf buffer that will receive the decompressed/decoded image.
|
| + * If the source image is a JPEG image, then this buffer should normally be
|
| + * <code>pitch * scaledHeight</code> bytes in size, where
|
| + * <code>scaledHeight</code> can be determined by calling <code>
|
| + * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
|
| + * </code> with one of the scaling factors returned from {@link
|
| + * TJ#getScalingFactors} or by calling {@link #getScaledHeight}. If the
|
| + * source image is a YUV image, then this buffer should normally be
|
| + * <code>pitch * height</code> bytes in size, where <code>height</code> is
|
| + * the height of the YUV image. However, the buffer may also be larger than
|
| + * the dimensions of the source image, in which case the <code>x</code>,
|
| + * <code>y</code>, and <code>pitch</code> parameters can be used to specify
|
| + * the region into which the source image should be decompressed/decoded.
|
| + *
|
| + * @param x x offset (in pixels) of the region in the destination image into
|
| + * which the source image should be decompressed/decoded
|
| + *
|
| + * @param y y offset (in pixels) of the region in the destination image into
|
| + * which the source image should be decompressed/decoded
|
| + *
|
| + * @param desiredWidth If the source image is a JPEG image, then this
|
| + * specifies the desired width (in pixels) of the decompressed image (or
|
| + * image region.) If the desired destination image dimensions are different
|
| + * than the source image dimensions, then TurboJPEG will use scaling in the
|
| + * JPEG decompressor to generate the largest possible image that will fit
|
| + * within the desired dimensions. Setting this to 0 is the same as setting
|
| + * it to the width of the JPEG image (in other words, the width will not be
|
| + * considered when determining the scaled image size.) This parameter is
|
| + * ignored if the source image is a YUV image.
|
| + *
|
| + * @param pitch bytes per line of the destination image. Normally, this
|
| + * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
|
| + * the destination image is unpadded, but you can use this to, for instance,
|
| + * pad each line of the destination image to a 4-byte boundary or to
|
| + * decompress/decode the source image into a region of a larger image. NOTE:
|
| + * if the source image is a JPEG image, then <code>scaledWidth</code> can be
|
| + * determined by calling <code>
|
| + * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
|
| + * </code> or by calling {@link #getScaledWidth}. If the source image is a
|
| + * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
|
| + * Setting this parameter to 0 is the equivalent of setting it to
|
| + * <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.
|
| + *
|
| + * @param desiredHeight If the source image is a JPEG image, then this
|
| + * specifies the desired height (in pixels) of the decompressed image (or
|
| + * image region.) If the desired destination image dimensions are different
|
| + * than the source image dimensions, then TurboJPEG will use scaling in the
|
| + * JPEG decompressor to generate the largest possible image that will fit
|
| + * within the desired dimensions. Setting this to 0 is the same as setting
|
| + * it to the height of the JPEG image (in other words, the height will not be
|
| + * considered when determining the scaled image size.) This parameter is
|
| + * ignored if the source image is a YUV image.
|
| + *
|
| + * @param pixelFormat pixel format of the decompressed/decoded image (one of
|
| + * {@link TJ#PF_RGB TJ.PF_*})
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + */
|
| + public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
|
| + int pitch, int desiredHeight, int pixelFormat,
|
| + int flags) throws TJException {
|
| + if (jpegBuf == null && yuvImage == null)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (dstBuf == null || x < 0 || y < 0 || pitch < 0 ||
|
| + (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
|
| + pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompress()");
|
| + if (yuvImage != null)
|
| + decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
|
| + yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
|
| + yuvImage.getWidth(), pitch, yuvImage.getHeight(), pixelFormat,
|
| + flags);
|
| + else {
|
| + if (x > 0 || y > 0)
|
| + decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
|
| + desiredHeight, pixelFormat, flags);
|
| + else
|
| + decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
|
| + desiredHeight, pixelFormat, flags);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * @deprecated Use
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
|
| + */
|
| + @Deprecated
|
| + public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
|
| + int desiredHeight, int pixelFormat, int flags)
|
| + throws TJException {
|
| + decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
|
| + flags);
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image associated with this decompressor
|
| + * instance and return a buffer containing the decompressed image.
|
| + *
|
| + * @param desiredWidth see
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)}
|
| + * for description
|
| + *
|
| + * @param pitch see
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)}
|
| + * for description
|
| + *
|
| + * @param desiredHeight see
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)}
|
| + * for description
|
| + *
|
| + * @param pixelFormat pixel format of the decompressed image (one of
|
| + * {@link TJ#PF_RGB TJ.PF_*})
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + *
|
| + * @return a buffer containing the decompressed image.
|
| + */
|
| + public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
|
| + int pixelFormat, int flags) throws TJException {
|
| + if (pitch < 0 ||
|
| + (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
|
| + pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompress()");
|
| + int pixelSize = TJ.getPixelSize(pixelFormat);
|
| + int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
|
| + int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
|
| + if (pitch == 0)
|
| + pitch = scaledWidth * pixelSize;
|
| + byte[] buf = new byte[pitch * scaledHeight];
|
| + decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
|
| + return buf;
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image associated with this decompressor
|
| + * instance into a YUV planar image and store it in the given
|
| + * <code>YUVImage</code> instance. This method performs JPEG decompression
|
| + * but leaves out the color conversion step, so a planar YUV image is
|
| + * generated instead of an RGB or grayscale image. This method cannot be
|
| + * used to decompress JPEG source images with the CMYK or YCCK colorspace.
|
| + *
|
| + * @param dstImage {@link YUVImage} instance that will receive the YUV planar
|
| + * image. The level of subsampling specified in this <code>YUVImage</code>
|
| + * instance must match that of the JPEG image, and the width and height
|
| + * specified in the <code>YUVImage</code> instance must match one of the
|
| + * scaled image sizes that TurboJPEG is capable of generating from the JPEG
|
| + * source image.
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + */
|
| + public void decompressToYUV(YUVImage dstImage, int flags)
|
| + throws TJException {
|
| + if (jpegBuf == null)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (dstImage == null || flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
|
| + int scaledWidth = getScaledWidth(dstImage.getWidth(),
|
| + dstImage.getHeight());
|
| + int scaledHeight = getScaledHeight(dstImage.getWidth(),
|
| + dstImage.getHeight());
|
| + if (scaledWidth != dstImage.getWidth() ||
|
| + scaledHeight != dstImage.getHeight())
|
| + throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
|
| + if (jpegSubsamp != dstImage.getSubsamp())
|
| + throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
|
| +
|
| + decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
|
| + dstImage.getOffsets(), dstImage.getWidth(),
|
| + dstImage.getStrides(), dstImage.getHeight(), flags);
|
| + }
|
| +
|
| + /**
|
| + * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
|
| + */
|
| + @Deprecated
|
| + public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
|
| + YUVImage dstImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
|
| + jpegSubsamp);
|
| + decompressToYUV(dstImage, flags);
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image associated with this decompressor
|
| + * instance into a set of Y, U (Cb), and V (Cr) image planes and return a
|
| + * <code>YUVImage</code> instance containing the decompressed image planes.
|
| + * This method performs JPEG decompression but leaves out the color
|
| + * conversion step, so a planar YUV image is generated instead of an RGB or
|
| + * grayscale image. This method cannot be used to decompress JPEG source
|
| + * images with the CMYK or YCCK colorspace.
|
| + *
|
| + * @param desiredWidth desired width (in pixels) of the YUV image. If the
|
| + * desired image dimensions are different than the dimensions of the JPEG
|
| + * image being decompressed, then TurboJPEG will use scaling in the JPEG
|
| + * decompressor to generate the largest possible image that will fit within
|
| + * the desired dimensions. Setting this to 0 is the same as setting it to
|
| + * the width of the JPEG image (in other words, the width will not be
|
| + * considered when determining the scaled image size.)
|
| + *
|
| + * @param strides an array of integers, each specifying the number of bytes
|
| + * per line in the corresponding plane of the output image. Setting the
|
| + * stride for any plane to 0 is the same as setting it to the scaled
|
| + * component width of the plane. If <tt>strides</tt> is NULL, then the
|
| + * strides for all planes will be set to their respective scaled component
|
| + * widths. You can adjust the strides in order to add an arbitrary amount of
|
| + * line padding to each plane.
|
| + *
|
| + * @param desiredHeight desired height (in pixels) of the YUV image. If the
|
| + * desired image dimensions are different than the dimensions of the JPEG
|
| + * image being decompressed, then TurboJPEG will use scaling in the JPEG
|
| + * decompressor to generate the largest possible image that will fit within
|
| + * the desired dimensions. Setting this to 0 is the same as setting it to
|
| + * the height of the JPEG image (in other words, the height will not be
|
| + * considered when determining the scaled image size.)
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + *
|
| + * @return a YUV planar image.
|
| + */
|
| + public YUVImage decompressToYUV(int desiredWidth, int[] strides,
|
| + int desiredHeight,
|
| + int flags) throws TJException {
|
| + if (flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
|
| + if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (jpegSubsamp >= TJ.NUMSAMP)
|
| + throw new IllegalStateException("JPEG header information is invalid");
|
| + if (yuvImage != null)
|
| + throw new IllegalStateException("Source image is the wrong type");
|
| +
|
| + int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
|
| + int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
|
| + YUVImage yuvImage = new YUVImage(scaledWidth, null, scaledHeight,
|
| + jpegSubsamp);
|
| + decompressToYUV(yuvImage, flags);
|
| + return yuvImage;
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image associated with this decompressor
|
| + * instance into a unified YUV planar image buffer and return a
|
| + * <code>YUVImage</code> instance containing the decompressed image. This
|
| + * method performs JPEG decompression but leaves out the color conversion
|
| + * step, so a planar YUV image is generated instead of an RGB or grayscale
|
| + * image. This method cannot be used to decompress JPEG source images with
|
| + * the CMYK or YCCK colorspace.
|
| + *
|
| + * @param desiredWidth desired width (in pixels) of the YUV image. If the
|
| + * desired image dimensions are different than the dimensions of the JPEG
|
| + * image being decompressed, then TurboJPEG will use scaling in the JPEG
|
| + * decompressor to generate the largest possible image that will fit within
|
| + * the desired dimensions. Setting this to 0 is the same as setting it to
|
| + * the width of the JPEG image (in other words, the width will not be
|
| + * considered when determining the scaled image size.)
|
| + *
|
| + * @param pad the width of each line in each plane of the YUV image will be
|
| + * padded to the nearest multiple of this number of bytes (must be a power of
|
| + * 2.)
|
| + *
|
| + * @param desiredHeight desired height (in pixels) of the YUV image. If the
|
| + * desired image dimensions are different than the dimensions of the JPEG
|
| + * image being decompressed, then TurboJPEG will use scaling in the JPEG
|
| + * decompressor to generate the largest possible image that will fit within
|
| + * the desired dimensions. Setting this to 0 is the same as setting it to
|
| + * the height of the JPEG image (in other words, the height will not be
|
| + * considered when determining the scaled image size.)
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + *
|
| + * @return a YUV planar image.
|
| + */
|
| + public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
|
| + int flags) throws TJException {
|
| + if (flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
|
| + if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (jpegSubsamp >= TJ.NUMSAMP)
|
| + throw new IllegalStateException("JPEG header information is invalid");
|
| + if (yuvImage != null)
|
| + throw new IllegalStateException("Source image is the wrong type");
|
| +
|
| + int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
|
| + int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
|
| + YUVImage yuvImage = new YUVImage(scaledWidth, pad, scaledHeight,
|
| + jpegSubsamp);
|
| + decompressToYUV(yuvImage, flags);
|
| + return yuvImage;
|
| + }
|
| +
|
| + /**
|
| + * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
|
| + */
|
| + @Deprecated
|
| + public byte[] decompressToYUV(int flags) throws TJException {
|
| + YUVImage dstImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
|
| + decompressToYUV(dstImage, flags);
|
| + return dstImage.getBuf();
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image or decode the YUV source image associated
|
| + * with this decompressor instance and output a grayscale, RGB, or CMYK image
|
| + * to the given destination buffer.
|
| + *
|
| + * @param dstBuf buffer that will receive the decompressed/decoded image.
|
| + * If the source image is a JPEG image, then this buffer should normally be
|
| + * <code>stride * scaledHeight</code> pixels in size, where
|
| + * <code>scaledHeight</code> can be determined by calling <code>
|
| + * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
|
| + * </code> with one of the scaling factors returned from {@link
|
| + * TJ#getScalingFactors} or by calling {@link #getScaledHeight}. If the
|
| + * source image is a YUV image, then this buffer should normally be
|
| + * <code>stride * height</code> pixels in size, where <code>height</code> is
|
| + * the height of the YUV image. However, the buffer may also be larger than
|
| + * the dimensions of the JPEG image, in which case the <code>x</code>,
|
| + * <code>y</code>, and <code>stride</code> parameters can be used to specify
|
| + * the region into which the source image should be decompressed.
|
| + *
|
| + * @param x x offset (in pixels) of the region in the destination image into
|
| + * which the source image should be decompressed/decoded
|
| + *
|
| + * @param y y offset (in pixels) of the region in the destination image into
|
| + * which the source image should be decompressed/decoded
|
| + *
|
| + * @param desiredWidth If the source image is a JPEG image, then this
|
| + * specifies the desired width (in pixels) of the decompressed image (or
|
| + * image region.) If the desired destination image dimensions are different
|
| + * than the source image dimensions, then TurboJPEG will use scaling in the
|
| + * JPEG decompressor to generate the largest possible image that will fit
|
| + * within the desired dimensions. Setting this to 0 is the same as setting
|
| + * it to the width of the JPEG image (in other words, the width will not be
|
| + * considered when determining the scaled image size.) This parameter is
|
| + * ignored if the source image is a YUV image.
|
| + *
|
| + * @param stride pixels per line of the destination image. Normally, this
|
| + * should be set to <code>scaledWidth</code>, but you can use this to, for
|
| + * instance, decompress the JPEG image into a region of a larger image.
|
| + * NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
|
| + * can be determined by calling <code>
|
| + * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
|
| + * </code> or by calling {@link #getScaledWidth}. If the source image is a
|
| + * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
|
| + * Setting this parameter to 0 is the equivalent of setting it to
|
| + * <code>scaledWidth</code>.
|
| + *
|
| + * @param desiredHeight If the source image is a JPEG image, then this
|
| + * specifies the desired height (in pixels) of the decompressed image (or
|
| + * image region.) If the desired destination image dimensions are different
|
| + * than the source image dimensions, then TurboJPEG will use scaling in the
|
| + * JPEG decompressor to generate the largest possible image that will fit
|
| + * within the desired dimensions. Setting this to 0 is the same as setting
|
| + * it to the height of the JPEG image (in other words, the height will not be
|
| + * considered when determining the scaled image size.) This parameter is
|
| + * ignored if the source image is a YUV image.
|
| + *
|
| + * @param pixelFormat pixel format of the decompressed image (one of
|
| + * {@link TJ#PF_RGB TJ.PF_*})
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + */
|
| + public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
|
| + int stride, int desiredHeight, int pixelFormat,
|
| + int flags) throws TJException {
|
| + if (jpegBuf == null && yuvImage == null)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
|
| + (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
|
| + pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompress()");
|
| + if (yuvImage != null)
|
| + decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
|
| + yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
|
| + yuvImage.getWidth(), stride, yuvImage.getHeight(), pixelFormat,
|
| + flags);
|
| + else
|
| + decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
|
| + desiredHeight, pixelFormat, flags);
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image or decode the YUV source image associated
|
| + * with this decompressor instance and output a decompressed/decoded image to
|
| + * the given <code>BufferedImage</code> instance.
|
| + *
|
| + * @param dstImage a <code>BufferedImage</code> instance that will receive
|
| + * the decompressed/decoded image. If the source image is a JPEG image, then
|
| + * the width and height of the <code>BufferedImage</code> instance must match
|
| + * one of the scaled image sizes that TurboJPEG is capable of generating from
|
| + * the JPEG image. If the source image is a YUV image, then the width and
|
| + * height of the <code>BufferedImage</code> instance must match the width and
|
| + * height of the YUV image.
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + */
|
| + public void decompress(BufferedImage dstImage, int flags)
|
| + throws TJException {
|
| + if (dstImage == null || flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompress()");
|
| + int desiredWidth = dstImage.getWidth();
|
| + int desiredHeight = dstImage.getHeight();
|
| + int scaledWidth, scaledHeight;
|
| +
|
| + if (yuvImage != null) {
|
| + if (desiredWidth != yuvImage.getWidth() ||
|
| + desiredHeight != yuvImage.getHeight())
|
| + throw new IllegalArgumentException("BufferedImage dimensions do not match the dimensions of the source image.");
|
| + scaledWidth = yuvImage.getWidth();
|
| + scaledHeight = yuvImage.getHeight();
|
| + } else {
|
| + scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
|
| + scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
|
| + if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
|
| + throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
|
| + }
|
| + int pixelFormat; boolean intPixels = false;
|
| + if (byteOrder == null)
|
| + byteOrder = ByteOrder.nativeOrder();
|
| + switch(dstImage.getType()) {
|
| + case BufferedImage.TYPE_3BYTE_BGR:
|
| + pixelFormat = TJ.PF_BGR; break;
|
| + case BufferedImage.TYPE_4BYTE_ABGR:
|
| + case BufferedImage.TYPE_4BYTE_ABGR_PRE:
|
| + pixelFormat = TJ.PF_XBGR; break;
|
| + case BufferedImage.TYPE_BYTE_GRAY:
|
| + pixelFormat = TJ.PF_GRAY; break;
|
| + case BufferedImage.TYPE_INT_BGR:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + pixelFormat = TJ.PF_XBGR;
|
| + else
|
| + pixelFormat = TJ.PF_RGBX;
|
| + intPixels = true; break;
|
| + case BufferedImage.TYPE_INT_RGB:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + pixelFormat = TJ.PF_XRGB;
|
| + else
|
| + pixelFormat = TJ.PF_BGRX;
|
| + intPixels = true; break;
|
| + case BufferedImage.TYPE_INT_ARGB:
|
| + case BufferedImage.TYPE_INT_ARGB_PRE:
|
| + if (byteOrder == ByteOrder.BIG_ENDIAN)
|
| + pixelFormat = TJ.PF_ARGB;
|
| + else
|
| + pixelFormat = TJ.PF_BGRA;
|
| + intPixels = true; break;
|
| + default:
|
| + throw new IllegalArgumentException("Unsupported BufferedImage format");
|
| + }
|
| + WritableRaster wr = dstImage.getRaster();
|
| + if (intPixels) {
|
| + SinglePixelPackedSampleModel sm =
|
| + (SinglePixelPackedSampleModel)dstImage.getSampleModel();
|
| + int stride = sm.getScanlineStride();
|
| + DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
|
| + int[] buf = db.getData();
|
| + if (yuvImage != null)
|
| + decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
|
| + yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
|
| + yuvImage.getWidth(), stride, yuvImage.getHeight(),
|
| + pixelFormat, flags);
|
| + else {
|
| + if (jpegBuf == null)
|
| + throw new IllegalStateException(NO_ASSOC_ERROR);
|
| + decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
|
| + scaledHeight, pixelFormat, flags);
|
| + }
|
| + } else {
|
| + ComponentSampleModel sm =
|
| + (ComponentSampleModel)dstImage.getSampleModel();
|
| + int pixelSize = sm.getPixelStride();
|
| + if (pixelSize != TJ.getPixelSize(pixelFormat))
|
| + throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
|
| + int pitch = sm.getScanlineStride();
|
| + DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
|
| + byte[] buf = db.getData();
|
| + decompress(buf, 0, 0, scaledWidth, pitch, scaledHeight, pixelFormat,
|
| + flags);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Decompress the JPEG source image or decode the YUV source image associated
|
| + * with this decompressor instance and return a <code>BufferedImage</code>
|
| + * instance containing the decompressed/decoded image.
|
| + *
|
| + * @param desiredWidth see
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
|
| + * description
|
| + *
|
| + * @param desiredHeight see
|
| + * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
|
| + * description
|
| + *
|
| + * @param bufferedImageType the image type of the <code>BufferedImage</code>
|
| + * instance that will be created (for instance,
|
| + * <code>BufferedImage.TYPE_INT_RGB</code>)
|
| + *
|
| + * @param flags the bitwise OR of one or more of
|
| + * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
|
| + *
|
| + * @return a <code>BufferedImage</code> instance containing the
|
| + * decompressed/decoded image.
|
| + */
|
| + public BufferedImage decompress(int desiredWidth, int desiredHeight,
|
| + int bufferedImageType, int flags)
|
| + throws TJException {
|
| + if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
|
| + flags < 0)
|
| + throw new IllegalArgumentException("Invalid argument in decompress()");
|
| + int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
|
| + int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
|
| + BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
|
| + bufferedImageType);
|
| + decompress(img, flags);
|
| + return img;
|
| + }
|
| +
|
| + /**
|
| + * Free the native structures associated with this decompressor instance.
|
| + */
|
| + @Override
|
| + public void close() throws TJException {
|
| + if (handle != 0)
|
| + destroy();
|
| + }
|
| +
|
| + @Override
|
| + protected void finalize() throws Throwable {
|
| + try {
|
| + close();
|
| + } catch(TJException e) {
|
| + } finally {
|
| + super.finalize();
|
| + }
|
| + };
|
| +
|
| + private native void init() throws TJException;
|
| +
|
| + private native void destroy() throws TJException;
|
| +
|
| + private native void decompressHeader(byte[] srcBuf, int size)
|
| + throws TJException;
|
| +
|
| + @Deprecated
|
| + private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
|
| + int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
|
| + throws TJException;
|
| +
|
| + private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
|
| + int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
|
| + int flags) throws TJException;
|
| +
|
| + @Deprecated
|
| + private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
|
| + int desiredWidth, int stride, int desiredHeight, int pixelFormat,
|
| + int flags) throws TJException;
|
| +
|
| + private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
|
| + int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
|
| + int flags) throws TJException;
|
| +
|
| + @Deprecated
|
| + private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
|
| + int flags) throws TJException;
|
| +
|
| + private native void decompressToYUV(byte[] srcBuf, int size,
|
| + byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
|
| + int desiredheight, int flags) throws TJException;
|
| +
|
| + private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
|
| + int[] srcStrides, int subsamp, byte[] dstBuf, int x, int y, int width,
|
| + int pitch, int height, int pixelFormat, int flags) throws TJException;
|
| +
|
| + private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
|
| + int[] srcStrides, int subsamp, int[] dstBuf, int x, int y, int width,
|
| + int stride, int height, int pixelFormat, int flags) throws TJException;
|
| +
|
| + static {
|
| + TJLoader.load();
|
| + }
|
| +
|
| + protected long handle = 0;
|
| + protected byte[] jpegBuf = null;
|
| + protected int jpegBufSize = 0;
|
| + protected YUVImage yuvImage = null;
|
| + protected int jpegWidth = 0;
|
| + protected int jpegHeight = 0;
|
| + protected int jpegSubsamp = -1;
|
| + protected int jpegColorspace = -1;
|
| + private ByteOrder byteOrder = null;
|
| +}
|
|
|