| /* |
| * Copyright (C)2011-2014 D. R. Commander. 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.*; |
| |
| /** |
| * TurboJPEG decompressor |
| */ |
| public class TJDecompressor { |
| |
| private static final String NO_ASSOC_ERROR = |
| "No JPEG image is associated with this instance"; |
| |
| /** |
| * Create a TurboJPEG decompresssor instance. |
| */ |
| public TJDecompressor() throws Exception { |
| init(); |
| } |
| |
| /** |
| * Create a TurboJPEG decompressor instance and associate the JPEG 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) |
| */ |
| public TJDecompressor(byte[] jpegImage) throws Exception { |
| init(); |
| setJPEGImage(jpegImage, jpegImage.length); |
| } |
| |
| /** |
| * Create a TurboJPEG decompressor instance and associate the JPEG image |
| * of length <code>imageSize</code> bytes stored in <code>jpegImage</code> |
| * with the newly created instance. |
| * |
| * @param jpegImage JPEG image buffer |
| * |
| * @param imageSize size of the JPEG image (in bytes) |
| */ |
| public TJDecompressor(byte[] jpegImage, int imageSize) throws Exception { |
| init(); |
| setJPEGImage(jpegImage, imageSize); |
| } |
| |
| /** |
| * 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 |
| * |
| * @param imageSize size of the JPEG image (in bytes) |
| */ |
| public void setJPEGImage(byte[] jpegImage, int imageSize) throws Exception { |
| if (jpegImage == null || imageSize < 1) |
| throw new Exception("Invalid argument in setJPEGImage()"); |
| jpegBuf = jpegImage; |
| jpegBufSize = imageSize; |
| decompressHeader(jpegBuf, jpegBufSize); |
| } |
| |
| /** |
| * Returns the width of the JPEG image associated with this decompressor |
| * instance. |
| * |
| * @return the width of the JPEG image associated with this decompressor |
| * instance |
| */ |
| public int getWidth() throws Exception { |
| if (jpegWidth < 1) |
| throw new Exception(NO_ASSOC_ERROR); |
| return jpegWidth; |
| } |
| |
| /** |
| * Returns the height of the JPEG image associated with this decompressor |
| * instance. |
| * |
| * @return the height of the JPEG image associated with this decompressor |
| * instance |
| */ |
| public int getHeight() throws Exception { |
| if (jpegHeight < 1) |
| throw new Exception(NO_ASSOC_ERROR); |
| return jpegHeight; |
| } |
| |
| /** |
| * Returns the level of chrominance subsampling used in the JPEG image |
| * associated with this decompressor instance. See {@link TJ TJ.SAMP_*}. |
| * |
| * @return the level of chrominance subsampling used in the JPEG image |
| * associated with this decompressor instance |
| */ |
| public int getSubsamp() throws Exception { |
| if (jpegSubsamp < 0) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (jpegSubsamp >= TJ.NUMSAMP) |
| throw new Exception("JPEG header information is invalid"); |
| return jpegSubsamp; |
| } |
| |
| /** |
| * Returns the JPEG image buffer associated with this decompressor instance. |
| * |
| * @return the JPEG image buffer associated with this decompressor instance |
| */ |
| public byte[] getJPEGBuf() throws Exception { |
| if (jpegBuf == null) |
| throw new Exception(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() throws Exception { |
| if (jpegBufSize < 1) |
| throw new Exception(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) |
| throws Exception { |
| if (jpegWidth < 1 || jpegHeight < 1) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (desiredWidth < 0 || desiredHeight < 0) |
| throw new Exception("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 Exception("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) |
| throws Exception { |
| if (jpegWidth < 1 || jpegHeight < 1) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (desiredWidth < 0 || desiredHeight < 0) |
| throw new Exception("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 Exception("Could not scale down to desired image dimensions"); |
| return scaledHeight; |
| } |
| |
| /** |
| * Decompress the JPEG source image associated with this decompressor |
| * instance and output a decompressed image to the given destination buffer. |
| * |
| * @param dstBuf buffer that will receive the decompressed image. 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}. 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>pitch</code> |
| * parameters can be used to specify the region into which the JPEG image |
| * should be decompressed. |
| * |
| * @param x x offset (in pixels) of the region into which the JPEG image |
| * should be decompressed, relative to the start of <code>dstBuf</code>. |
| * |
| * @param y y offset (in pixels) of the region into which the JPEG image |
| * should be decompressed, relative to the start of <code>dstBuf</code>. |
| * |
| * @param desiredWidth desired width (in pixels) of the decompressed image |
| * (or image region.) 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 pitch bytes per line of the destination image. Normally, this |
| * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if |
| * the decompressed image is unpadded, but you can use this to, for instance, |
| * pad each line of the decompressed image to a 4-byte boundary or to |
| * decompress the JPEG image into a region of a larger image. NOTE: |
| * <code>scaledWidth</code> can be determined by calling <code> |
| * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth) |
| * </code> or by calling {@link #getScaledWidth}. Setting this parameter to |
| * 0 is the equivalent of setting it to <code>scaledWidth * |
| * TJ.pixelSize(pixelFormat)</code>. |
| * |
| * @param desiredHeight desired height (in pixels) of the decompressed image |
| * (or image region.) 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 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 Exception { |
| if (jpegBuf == null) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (dstBuf == null || x < 0 || y < 0 || desiredWidth < 0 || pitch < 0 || |
| desiredHeight < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF || |
| flags < 0) |
| throw new Exception("Invalid argument in decompress()"); |
| 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 Exception { |
| 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 Exception { |
| if (desiredWidth < 0 || pitch < 0 || desiredHeight < 0 || |
| pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0) |
| throw new Exception("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 and output a YUV planar image to the given destination buffer. |
| * This method performs JPEG decompression but leaves out the color |
| * conversion step, so a planar YUV image is generated instead of an RGB |
| * image. The padding of the planes in this image is the same as in the |
| * images generated by {@link TJCompressor#encodeYUV(byte[], int)}. |
| * <p> |
| * NOTE: Technically, the JPEG format uses the YCbCr colorspace, but per the |
| * convention of the digital video community, the TurboJPEG API uses "YUV" to |
| * refer to an image format consisting of Y, Cb, and Cr image planes. |
| * |
| * @param dstBuf buffer that will receive the YUV planar image. Use |
| * {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer |
| * based on the image width, height, and level of chrominance subsampling. |
| * |
| * @param flags the bitwise OR of one or more of |
| * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} |
| */ |
| public void decompressToYUV(byte[] dstBuf, int flags) throws Exception { |
| if (jpegBuf == null) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (dstBuf == null || flags < 0) |
| throw new Exception("Invalid argument in decompressToYUV()"); |
| decompressToYUV(jpegBuf, jpegBufSize, dstBuf, flags); |
| } |
| |
| |
| /** |
| * Decompress the JPEG source image associated with this decompressor |
| * instance and return a buffer containing a YUV planar image. See {@link |
| * #decompressToYUV(byte[], int)} for more detail. |
| * |
| * @param flags the bitwise OR of one or more of |
| * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} |
| * |
| * @return a buffer containing a YUV planar image |
| */ |
| public byte[] decompressToYUV(int flags) throws Exception { |
| if (flags < 0) |
| throw new Exception("Invalid argument in decompressToYUV()"); |
| if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (jpegSubsamp >= TJ.NUMSAMP) |
| throw new Exception("JPEG header information is invalid"); |
| byte[] buf = new byte[TJ.bufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)]; |
| decompressToYUV(buf, flags); |
| return buf; |
| } |
| |
| /** |
| * Decompress the JPEG source image associated with this decompressor |
| * instance and output a decompressed image to the given destination buffer. |
| * |
| * @param dstBuf buffer that will receive the decompressed image. 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}. 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 JPEG image |
| * should be decompressed. |
| * |
| * @param x x offset (in pixels) of the region into which the JPEG image |
| * should be decompressed, relative to the start of <code>dstBuf</code>. |
| * |
| * @param y y offset (in pixels) of the region into which the JPEG image |
| * should be decompressed, relative to the start of <code>dstBuf</code>. |
| * |
| * @param desiredWidth desired width (in pixels) of the decompressed image |
| * (or image region.) 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 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: <code>scaledWidth</code> can be determined by calling <code> |
| * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth) |
| * </code> or by calling {@link #getScaledWidth}. Setting this parameter to |
| * 0 is the equivalent of setting it to <code>scaledWidth</code>. |
| * |
| * @param desiredHeight desired height (in pixels) of the decompressed image |
| * (or image region.) 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 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 Exception { |
| if (jpegBuf == null) |
| throw new Exception(NO_ASSOC_ERROR); |
| if (dstBuf == null || x < 0 || y < 0 || desiredWidth < 0 || stride < 0 || |
| desiredHeight < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF || |
| flags < 0) |
| throw new Exception("Invalid argument in decompress()"); |
| decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride, |
| desiredHeight, pixelFormat, flags); |
| } |
| |
| /** |
| * Decompress the JPEG source image associated with this decompressor |
| * instance and output a decompressed image to the given |
| * <code>BufferedImage</code> instance. |
| * |
| * @param dstImage a <code>BufferedImage</code> instance that will receive |
| * the decompressed image. 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. |
| * |
| * |
| * @param flags the bitwise OR of one or more of |
| * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} |
| */ |
| public void decompress(BufferedImage dstImage, int flags) throws Exception { |
| if (dstImage == null || flags < 0) |
| throw new Exception("Invalid argument in decompress()"); |
| int desiredWidth = dstImage.getWidth(); |
| int desiredHeight = dstImage.getHeight(); |
| int scaledWidth = getScaledWidth(desiredWidth, desiredHeight); |
| int scaledHeight = getScaledHeight(desiredWidth, desiredHeight); |
| if (scaledWidth != desiredWidth || scaledHeight != desiredHeight) |
| throw new Exception("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 Exception("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 (jpegBuf == null) |
| throw new Exception(NO_ASSOC_ERROR); |
| decompress(jpegBuf, jpegBufSize, buf, scaledWidth, stride, scaledHeight, |
| pixelFormat, flags); |
| } else { |
| ComponentSampleModel sm = |
| (ComponentSampleModel)dstImage.getSampleModel(); |
| int pixelSize = sm.getPixelStride(); |
| if (pixelSize != TJ.getPixelSize(pixelFormat)) |
| throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage"); |
| int pitch = sm.getScanlineStride(); |
| DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); |
| byte[] buf = db.getData(); |
| decompress(buf, scaledWidth, pitch, scaledHeight, pixelFormat, flags); |
| } |
| } |
| |
| /** |
| * Decompress the JPEG source image associated with this decompressor |
| * instance and return a <code>BufferedImage</code> instance containing the |
| * decompressed 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 image |
| */ |
| public BufferedImage decompress(int desiredWidth, int desiredHeight, |
| int bufferedImageType, int flags) |
| throws Exception { |
| if (desiredWidth < 0 || desiredHeight < 0 || flags < 0) |
| throw new Exception("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. |
| */ |
| public void close() throws Exception { |
| if (handle != 0) |
| destroy(); |
| } |
| |
| protected void finalize() throws Throwable { |
| try { |
| close(); |
| } catch(Exception e) { |
| } finally { |
| super.finalize(); |
| } |
| }; |
| |
| private native void init() throws Exception; |
| |
| private native void destroy() throws Exception; |
| |
| private native void decompressHeader(byte[] srcBuf, int size) |
| throws Exception; |
| |
| private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, |
| int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags) |
| throws Exception; // deprecated |
| |
| 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 Exception; |
| |
| private native void decompress(byte[] srcBuf, int size, int[] dstBuf, |
| int desiredWidth, int stride, int desiredHeight, int pixelFormat, |
| int flags) throws Exception; // deprecated |
| |
| 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 Exception; |
| |
| private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf, |
| int flags) throws Exception; |
| |
| static { |
| TJLoader.load(); |
| } |
| |
| protected long handle = 0; |
| protected byte[] jpegBuf = null; |
| protected int jpegBufSize = 0; |
| protected int jpegWidth = 0; |
| protected int jpegHeight = 0; |
| protected int jpegSubsamp = -1; |
| private ByteOrder byteOrder = null; |
| }; |