Home | History | Annotate | Download | only in turbojpeg
      1 /*
      2  * Copyright (C)2011-2015 D. R. Commander.  All Rights Reserved.
      3  * Copyright (C)2015 Viktor Szathmry.  All Rights Reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  * - Redistributions of source code must retain the above copyright notice,
      9  *   this list of conditions and the following disclaimer.
     10  * - Redistributions in binary form must reproduce the above copyright notice,
     11  *   this list of conditions and the following disclaimer in the documentation
     12  *   and/or other materials provided with the distribution.
     13  * - Neither the name of the libjpeg-turbo Project nor the names of its
     14  *   contributors may be used to endorse or promote products derived from this
     15  *   software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
     18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
     21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 package org.libjpegturbo.turbojpeg;
     31 
     32 import java.awt.image.*;
     33 import java.nio.*;
     34 import java.io.*;
     35 
     36 /**
     37  * TurboJPEG decompressor
     38  */
     39 public class TJDecompressor implements Closeable {
     40 
     41   private static final String NO_ASSOC_ERROR =
     42     "No JPEG image is associated with this instance";
     43 
     44   /**
     45    * Create a TurboJPEG decompresssor instance.
     46    */
     47   public TJDecompressor() throws TJException {
     48     init();
     49   }
     50 
     51   /**
     52    * Create a TurboJPEG decompressor instance and associate the JPEG source
     53    * image stored in <code>jpegImage</code> with the newly created instance.
     54    *
     55    * @param jpegImage JPEG image buffer (size of the JPEG image is assumed to
     56    * be the length of the array.)  This buffer is not modified.
     57    */
     58   public TJDecompressor(byte[] jpegImage) throws TJException {
     59     init();
     60     setSourceImage(jpegImage, jpegImage.length);
     61   }
     62 
     63   /**
     64    * Create a TurboJPEG decompressor instance and associate the JPEG source
     65    * image of length <code>imageSize</code> bytes stored in
     66    * <code>jpegImage</code> with the newly created instance.
     67    *
     68    * @param jpegImage JPEG image buffer.  This buffer is not modified.
     69    *
     70    * @param imageSize size of the JPEG image (in bytes)
     71    */
     72   public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
     73     init();
     74     setSourceImage(jpegImage, imageSize);
     75   }
     76 
     77   /**
     78    * Create a TurboJPEG decompressor instance and associate the YUV planar
     79    * source image stored in <code>yuvImage</code> with the newly created
     80    * instance.
     81    *
     82    * @param yuvImage {@link YUVImage} instance containing a YUV planar
     83    * image to be decoded.  This image is not modified.
     84    */
     85   public TJDecompressor(YUVImage yuvImage) throws TJException {
     86     init();
     87     setSourceImage(yuvImage);
     88   }
     89 
     90   /**
     91    * Associate the JPEG image of length <code>imageSize</code> bytes stored in
     92    * <code>jpegImage</code> with this decompressor instance.  This image will
     93    * be used as the source image for subsequent decompress operations.
     94    *
     95    * @param jpegImage JPEG image buffer.  This buffer is not modified.
     96    *
     97    * @param imageSize size of the JPEG image (in bytes)
     98    */
     99   public void setSourceImage(byte[] jpegImage, int imageSize)
    100                              throws TJException {
    101     if (jpegImage == null || imageSize < 1)
    102       throw new IllegalArgumentException("Invalid argument in setSourceImage()");
    103     jpegBuf = jpegImage;
    104     jpegBufSize = imageSize;
    105     decompressHeader(jpegBuf, jpegBufSize);
    106     yuvImage = null;
    107   }
    108 
    109   /**
    110    * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
    111    */
    112   @Deprecated
    113   public void setJPEGImage(byte[] jpegImage, int imageSize)
    114                            throws TJException {
    115     setSourceImage(jpegImage, imageSize);
    116   }
    117 
    118   /**
    119    * Associate the specified YUV planar source image with this decompressor
    120    * instance.  Subsequent decompress operations will decode this image into an
    121    * RGB or grayscale destination image.
    122    *
    123    * @param srcImage {@link YUVImage} instance containing a YUV planar image to
    124    * be decoded.  This image is not modified.
    125    */
    126   public void setSourceImage(YUVImage srcImage) {
    127     if (srcImage == null)
    128       throw new IllegalArgumentException("Invalid argument in setSourceImage()");
    129     yuvImage = srcImage;
    130     jpegBuf = null;
    131     jpegBufSize = 0;
    132   }
    133 
    134 
    135   /**
    136    * Returns the width of the source image (JPEG or YUV) associated with this
    137    * decompressor instance.
    138    *
    139    * @return the width of the source image (JPEG or YUV) associated with this
    140    * decompressor instance.
    141    */
    142   public int getWidth() {
    143     if (yuvImage != null)
    144       return yuvImage.getWidth();
    145     if (jpegWidth < 1)
    146       throw new IllegalStateException(NO_ASSOC_ERROR);
    147     return jpegWidth;
    148   }
    149 
    150   /**
    151    * Returns the height of the source image (JPEG or YUV) associated with this
    152    * decompressor instance.
    153    *
    154    * @return the height of the source image (JPEG or YUV) associated with this
    155    * decompressor instance.
    156    */
    157   public int getHeight() {
    158     if (yuvImage != null)
    159       return yuvImage.getHeight();
    160     if (jpegHeight < 1)
    161       throw new IllegalStateException(NO_ASSOC_ERROR);
    162     return jpegHeight;
    163   }
    164 
    165   /**
    166    * Returns the level of chrominance subsampling used in the source image
    167    * (JPEG or YUV) associated with this decompressor instance.  See
    168    * {@link TJ#SAMP_444 TJ.SAMP_*}.
    169    *
    170    * @return the level of chrominance subsampling used in the source image
    171    * (JPEG or YUV) associated with this decompressor instance.
    172    */
    173   public int getSubsamp() {
    174     if (yuvImage != null)
    175       return yuvImage.getSubsamp();
    176     if (jpegSubsamp < 0)
    177       throw new IllegalStateException(NO_ASSOC_ERROR);
    178     if (jpegSubsamp >= TJ.NUMSAMP)
    179       throw new IllegalStateException("JPEG header information is invalid");
    180     return jpegSubsamp;
    181   }
    182 
    183   /**
    184    * Returns the colorspace used in the source image (JPEG or YUV) associated
    185    * with this decompressor instance.  See {@link TJ#CS_RGB TJ.CS_*}.  If the
    186    * source image is YUV, then this always returns {@link TJ#CS_YCbCr}.
    187    *
    188    * @return the colorspace used in the source image (JPEG or YUV) associated
    189    * with this decompressor instance.
    190    */
    191   public int getColorspace() {
    192     if (yuvImage != null)
    193       return TJ.CS_YCbCr;
    194     if (jpegColorspace < 0)
    195       throw new IllegalStateException(NO_ASSOC_ERROR);
    196     if (jpegColorspace >= TJ.NUMCS)
    197       throw new IllegalStateException("JPEG header information is invalid");
    198     return jpegColorspace;
    199   }
    200 
    201   /**
    202    * Returns the JPEG image buffer associated with this decompressor instance.
    203    *
    204    * @return the JPEG image buffer associated with this decompressor instance.
    205    */
    206   public byte[] getJPEGBuf() {
    207     if (jpegBuf == null)
    208       throw new IllegalStateException(NO_ASSOC_ERROR);
    209     return jpegBuf;
    210   }
    211 
    212   /**
    213    * Returns the size of the JPEG image (in bytes) associated with this
    214    * decompressor instance.
    215    *
    216    * @return the size of the JPEG image (in bytes) associated with this
    217    * decompressor instance.
    218    */
    219   public int getJPEGSize() {
    220     if (jpegBufSize < 1)
    221       throw new IllegalStateException(NO_ASSOC_ERROR);
    222     return jpegBufSize;
    223   }
    224 
    225   /**
    226    * Returns the width of the largest scaled-down image that the TurboJPEG
    227    * decompressor can generate without exceeding the desired image width and
    228    * height.
    229    *
    230    * @param desiredWidth desired width (in pixels) of the decompressed image.
    231    * Setting this to 0 is the same as setting it to the width of the JPEG image
    232    * (in other words, the width will not be considered when determining the
    233    * scaled image size.)
    234    *
    235    * @param desiredHeight desired height (in pixels) of the decompressed image.
    236    * Setting this to 0 is the same as setting it to the height of the JPEG
    237    * image (in other words, the height will not be considered when determining
    238    * the scaled image size.)
    239    *
    240    * @return the width of the largest scaled-down image that the TurboJPEG
    241    * decompressor can generate without exceeding the desired image width and
    242    * height.
    243    */
    244   public int getScaledWidth(int desiredWidth, int desiredHeight) {
    245     if (jpegWidth < 1 || jpegHeight < 1)
    246       throw new IllegalStateException(NO_ASSOC_ERROR);
    247     if (desiredWidth < 0 || desiredHeight < 0)
    248       throw new IllegalArgumentException("Invalid argument in getScaledWidth()");
    249     TJScalingFactor[] sf = TJ.getScalingFactors();
    250     if (desiredWidth == 0)
    251       desiredWidth = jpegWidth;
    252     if (desiredHeight == 0)
    253       desiredHeight = jpegHeight;
    254     int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
    255     for (int i = 0; i < sf.length; i++) {
    256       scaledWidth = sf[i].getScaled(jpegWidth);
    257       scaledHeight = sf[i].getScaled(jpegHeight);
    258       if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
    259         break;
    260     }
    261     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
    262       throw new IllegalArgumentException("Could not scale down to desired image dimensions");
    263     return scaledWidth;
    264   }
    265 
    266   /**
    267    * Returns the height of the largest scaled-down image that the TurboJPEG
    268    * decompressor can generate without exceeding the desired image width and
    269    * height.
    270    *
    271    * @param desiredWidth desired width (in pixels) of the decompressed image.
    272    * Setting this to 0 is the same as setting it to the width of the JPEG image
    273    * (in other words, the width will not be considered when determining the
    274    * scaled image size.)
    275    *
    276    * @param desiredHeight desired height (in pixels) of the decompressed image.
    277    * Setting this to 0 is the same as setting it to the height of the JPEG
    278    * image (in other words, the height will not be considered when determining
    279    * the scaled image size.)
    280    *
    281    * @return the height of the largest scaled-down image that the TurboJPEG
    282    * decompressor can generate without exceeding the desired image width and
    283    * height.
    284    */
    285   public int getScaledHeight(int desiredWidth, int desiredHeight) {
    286     if (jpegWidth < 1 || jpegHeight < 1)
    287       throw new IllegalStateException(NO_ASSOC_ERROR);
    288     if (desiredWidth < 0 || desiredHeight < 0)
    289       throw new IllegalArgumentException("Invalid argument in getScaledHeight()");
    290     TJScalingFactor[] sf = TJ.getScalingFactors();
    291     if (desiredWidth == 0)
    292       desiredWidth = jpegWidth;
    293     if (desiredHeight == 0)
    294       desiredHeight = jpegHeight;
    295     int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
    296     for (int i = 0; i < sf.length; i++) {
    297       scaledWidth = sf[i].getScaled(jpegWidth);
    298       scaledHeight = sf[i].getScaled(jpegHeight);
    299       if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
    300         break;
    301     }
    302     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
    303       throw new IllegalArgumentException("Could not scale down to desired image dimensions");
    304     return scaledHeight;
    305   }
    306 
    307   /**
    308    * Decompress the JPEG source image or decode the YUV source image associated
    309    * with this decompressor instance and output a grayscale, RGB, or CMYK image
    310    * to the given destination buffer.
    311    *
    312    * @param dstBuf buffer that will receive the decompressed/decoded image.
    313    * If the source image is a JPEG image, then this buffer should normally be
    314    * <code>pitch * scaledHeight</code> bytes in size, where
    315    * <code>scaledHeight</code> can be determined by calling <code>
    316    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
    317    * </code> with one of the scaling factors returned from {@link
    318    * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  If the
    319    * source image is a YUV image, then this buffer should normally be
    320    * <code>pitch * height</code> bytes in size, where <code>height</code> is
    321    * the height of the YUV image.  However, the buffer may also be larger than
    322    * the dimensions of the source image, in which case the <code>x</code>,
    323    * <code>y</code>, and <code>pitch</code> parameters can be used to specify
    324    * the region into which the source image should be decompressed/decoded.
    325    *
    326    * @param x x offset (in pixels) of the region in the destination image into
    327    * which the source image should be decompressed/decoded
    328    *
    329    * @param y y offset (in pixels) of the region in the destination image into
    330    * which the source image should be decompressed/decoded
    331    *
    332    * @param desiredWidth If the source image is a JPEG image, then this
    333    * specifies the desired width (in pixels) of the decompressed image (or
    334    * image region.)  If the desired destination image dimensions are different
    335    * than the source image dimensions, then TurboJPEG will use scaling in the
    336    * JPEG decompressor to generate the largest possible image that will fit
    337    * within the desired dimensions.  Setting this to 0 is the same as setting
    338    * it to the width of the JPEG image (in other words, the width will not be
    339    * considered when determining the scaled image size.)  This parameter is
    340    * ignored if the source image is a YUV image.
    341    *
    342    * @param pitch bytes per line of the destination image.  Normally, this
    343    * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
    344    * the destination image is unpadded, but you can use this to, for instance,
    345    * pad each line of the destination image to a 4-byte boundary or to
    346    * decompress/decode the source image into a region of a larger image.  NOTE:
    347    * if the source image is a JPEG image, then <code>scaledWidth</code> can be
    348    * determined by calling <code>
    349    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
    350    * </code> or by calling {@link #getScaledWidth}.  If the source image is a
    351    * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
    352    * Setting this parameter to 0 is the equivalent of setting it to
    353    * <code>scaledWidth * TJ.pixelSize(pixelFormat)</code>.
    354    *
    355    * @param desiredHeight If the source image is a JPEG image, then this
    356    * specifies the desired height (in pixels) of the decompressed image (or
    357    * image region.)  If the desired destination image dimensions are different
    358    * than the source image dimensions, then TurboJPEG will use scaling in the
    359    * JPEG decompressor to generate the largest possible image that will fit
    360    * within the desired dimensions.  Setting this to 0 is the same as setting
    361    * it to the height of the JPEG image (in other words, the height will not be
    362    * considered when determining the scaled image size.)  This parameter is
    363    * ignored if the source image is a YUV image.
    364    *
    365    * @param pixelFormat pixel format of the decompressed/decoded image (one of
    366    * {@link TJ#PF_RGB TJ.PF_*})
    367    *
    368    * @param flags the bitwise OR of one or more of
    369    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    370    */
    371   public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
    372                          int pitch, int desiredHeight, int pixelFormat,
    373                          int flags) throws TJException {
    374     if (jpegBuf == null && yuvImage == null)
    375       throw new IllegalStateException(NO_ASSOC_ERROR);
    376     if (dstBuf == null || x < 0 || y < 0 || pitch < 0 ||
    377         (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
    378         pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
    379       throw new IllegalArgumentException("Invalid argument in decompress()");
    380     if (yuvImage != null)
    381       decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
    382                 yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
    383                 yuvImage.getWidth(), pitch, yuvImage.getHeight(), pixelFormat,
    384                 flags);
    385     else {
    386       if (x > 0 || y > 0)
    387         decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
    388                    desiredHeight, pixelFormat, flags);
    389       else
    390         decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
    391                    desiredHeight, pixelFormat, flags);
    392     }
    393   }
    394 
    395   /**
    396    * @deprecated Use
    397    * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
    398    */
    399   @Deprecated
    400   public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
    401                          int desiredHeight, int pixelFormat, int flags)
    402                          throws TJException {
    403     decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
    404                flags);
    405   }
    406 
    407   /**
    408    * Decompress the JPEG source image associated with this decompressor
    409    * instance and return a buffer containing the decompressed image.
    410    *
    411    * @param desiredWidth see
    412    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
    413    * for description
    414    *
    415    * @param pitch see
    416    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
    417    * for description
    418    *
    419    * @param desiredHeight see
    420    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
    421    * for description
    422    *
    423    * @param pixelFormat pixel format of the decompressed image (one of
    424    * {@link TJ#PF_RGB TJ.PF_*})
    425    *
    426    * @param flags the bitwise OR of one or more of
    427    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    428    *
    429    * @return a buffer containing the decompressed image.
    430    */
    431   public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
    432                            int pixelFormat, int flags) throws TJException {
    433     if (pitch < 0 ||
    434         (yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
    435         pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
    436       throw new IllegalArgumentException("Invalid argument in decompress()");
    437     int pixelSize = TJ.getPixelSize(pixelFormat);
    438     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
    439     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
    440     if (pitch == 0)
    441       pitch = scaledWidth * pixelSize;
    442     byte[] buf = new byte[pitch * scaledHeight];
    443     decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
    444     return buf;
    445   }
    446 
    447   /**
    448    * Decompress the JPEG source image associated with this decompressor
    449    * instance into a YUV planar image and store it in the given
    450    * <code>YUVImage</code> instance.  This method performs JPEG decompression
    451    * but leaves out the color conversion step, so a planar YUV image is
    452    * generated instead of an RGB or grayscale image.  This method cannot be
    453    * used to decompress JPEG source images with the CMYK or YCCK colorspace.
    454    *
    455    * @param dstImage {@link YUVImage} instance that will receive the YUV planar
    456    * image.  The level of subsampling specified in this <code>YUVImage</code>
    457    * instance must match that of the JPEG image, and the width and height
    458    * specified in the <code>YUVImage</code> instance must match one of the
    459    * scaled image sizes that TurboJPEG is capable of generating from the JPEG
    460    * source image.
    461    *
    462    * @param flags the bitwise OR of one or more of
    463    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    464    */
    465   public void decompressToYUV(YUVImage dstImage, int flags)
    466                               throws TJException {
    467     if (jpegBuf == null)
    468       throw new IllegalStateException(NO_ASSOC_ERROR);
    469     if (dstImage == null || flags < 0)
    470       throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
    471     int scaledWidth = getScaledWidth(dstImage.getWidth(),
    472                                      dstImage.getHeight());
    473     int scaledHeight = getScaledHeight(dstImage.getWidth(),
    474                                        dstImage.getHeight());
    475     if (scaledWidth != dstImage.getWidth() ||
    476         scaledHeight != dstImage.getHeight())
    477       throw new IllegalArgumentException("YUVImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
    478     if (jpegSubsamp != dstImage.getSubsamp())
    479       throw new IllegalArgumentException("YUVImage subsampling level does not match that of the JPEG image");
    480 
    481     decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
    482                     dstImage.getOffsets(), dstImage.getWidth(),
    483                     dstImage.getStrides(), dstImage.getHeight(), flags);
    484   }
    485 
    486   /**
    487    * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
    488    */
    489   @Deprecated
    490   public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
    491     YUVImage dstImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
    492                                      jpegSubsamp);
    493     decompressToYUV(dstImage, flags);
    494   }
    495 
    496   /**
    497    * Decompress the JPEG source image associated with this decompressor
    498    * instance into a set of Y, U (Cb), and V (Cr) image planes and return a
    499    * <code>YUVImage</code> instance containing the decompressed image planes.
    500    * This method performs JPEG decompression but leaves out the color
    501    * conversion step, so a planar YUV image is generated instead of an RGB or
    502    * grayscale image.  This method cannot be used to decompress JPEG source
    503    * images with the CMYK or YCCK colorspace.
    504    *
    505    * @param desiredWidth desired width (in pixels) of the YUV image.  If the
    506    * desired image dimensions are different than the dimensions of the JPEG
    507    * image being decompressed, then TurboJPEG will use scaling in the JPEG
    508    * decompressor to generate the largest possible image that will fit within
    509    * the desired dimensions.  Setting this to 0 is the same as setting it to
    510    * the width of the JPEG image (in other words, the width will not be
    511    * considered when determining the scaled image size.)
    512    *
    513    * @param strides an array of integers, each specifying the number of bytes
    514    * per line in the corresponding plane of the output image.  Setting the
    515    * stride for any plane to 0 is the same as setting it to the scaled
    516    * component width of the plane.  If <tt>strides</tt> is NULL, then the
    517    * strides for all planes will be set to their respective scaled component
    518    * widths.  You can adjust the strides in order to add an arbitrary amount of
    519    * line padding to each plane.
    520    *
    521    * @param desiredHeight desired height (in pixels) of the YUV image.  If the
    522    * desired image dimensions are different than the dimensions of the JPEG
    523    * image being decompressed, then TurboJPEG will use scaling in the JPEG
    524    * decompressor to generate the largest possible image that will fit within
    525    * the desired dimensions.  Setting this to 0 is the same as setting it to
    526    * the height of the JPEG image (in other words, the height will not be
    527    * considered when determining the scaled image size.)
    528    *
    529    * @param flags the bitwise OR of one or more of
    530    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    531    *
    532    * @return a YUV planar image.
    533    */
    534   public YUVImage decompressToYUV(int desiredWidth, int[] strides,
    535                                   int desiredHeight,
    536                                   int flags) throws TJException {
    537     if (flags < 0)
    538       throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
    539     if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
    540       throw new IllegalStateException(NO_ASSOC_ERROR);
    541     if (jpegSubsamp >= TJ.NUMSAMP)
    542       throw new IllegalStateException("JPEG header information is invalid");
    543     if (yuvImage != null)
    544       throw new IllegalStateException("Source image is the wrong type");
    545 
    546     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
    547     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
    548     YUVImage yuvImage = new YUVImage(scaledWidth, null, scaledHeight,
    549                                      jpegSubsamp);
    550     decompressToYUV(yuvImage, flags);
    551     return yuvImage;
    552   }
    553 
    554   /**
    555    * Decompress the JPEG source image associated with this decompressor
    556    * instance into a unified YUV planar image buffer and return a
    557    * <code>YUVImage</code> instance containing the decompressed image.  This
    558    * method performs JPEG decompression but leaves out the color conversion
    559    * step, so a planar YUV image is generated instead of an RGB or grayscale
    560    * image.  This method cannot be used to decompress JPEG source images with
    561    * the CMYK or YCCK colorspace.
    562    *
    563    * @param desiredWidth desired width (in pixels) of the YUV image.  If the
    564    * desired image dimensions are different than the dimensions of the JPEG
    565    * image being decompressed, then TurboJPEG will use scaling in the JPEG
    566    * decompressor to generate the largest possible image that will fit within
    567    * the desired dimensions.  Setting this to 0 is the same as setting it to
    568    * the width of the JPEG image (in other words, the width will not be
    569    * considered when determining the scaled image size.)
    570    *
    571    * @param pad the width of each line in each plane of the YUV image will be
    572    * padded to the nearest multiple of this number of bytes (must be a power of
    573    * 2.)
    574    *
    575    * @param desiredHeight desired height (in pixels) of the YUV image.  If the
    576    * desired image dimensions are different than the dimensions of the JPEG
    577    * image being decompressed, then TurboJPEG will use scaling in the JPEG
    578    * decompressor to generate the largest possible image that will fit within
    579    * the desired dimensions.  Setting this to 0 is the same as setting it to
    580    * the height of the JPEG image (in other words, the height will not be
    581    * considered when determining the scaled image size.)
    582    *
    583    * @param flags the bitwise OR of one or more of
    584    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    585    *
    586    * @return a YUV planar image.
    587    */
    588   public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
    589                                   int flags) throws TJException {
    590     if (flags < 0)
    591       throw new IllegalArgumentException("Invalid argument in decompressToYUV()");
    592     if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
    593       throw new IllegalStateException(NO_ASSOC_ERROR);
    594     if (jpegSubsamp >= TJ.NUMSAMP)
    595       throw new IllegalStateException("JPEG header information is invalid");
    596     if (yuvImage != null)
    597       throw new IllegalStateException("Source image is the wrong type");
    598 
    599     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
    600     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
    601     YUVImage yuvImage = new YUVImage(scaledWidth, pad, scaledHeight,
    602                                      jpegSubsamp);
    603     decompressToYUV(yuvImage, flags);
    604     return yuvImage;
    605   }
    606 
    607   /**
    608    * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
    609    */
    610   @Deprecated
    611   public byte[] decompressToYUV(int flags) throws TJException {
    612     YUVImage dstImage = new YUVImage(jpegWidth, 4, jpegHeight, jpegSubsamp);
    613     decompressToYUV(dstImage, flags);
    614     return dstImage.getBuf();
    615   }
    616 
    617   /**
    618    * Decompress the JPEG source image or decode the YUV source image associated
    619    * with this decompressor instance and output a grayscale, RGB, or CMYK image
    620    * to the given destination buffer.
    621    *
    622    * @param dstBuf buffer that will receive the decompressed/decoded image.
    623    * If the source image is a JPEG image, then this buffer should normally be
    624    * <code>stride * scaledHeight</code> pixels in size, where
    625    * <code>scaledHeight</code> can be determined by calling <code>
    626    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
    627    * </code> with one of the scaling factors returned from {@link
    628    * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  If the
    629    * source image is a YUV image, then this buffer should normally be
    630    * <code>stride * height</code> pixels in size, where <code>height</code> is
    631    * the height of the YUV image.  However, the buffer may also be larger than
    632    * the dimensions of the JPEG image, in which case the <code>x</code>,
    633    * <code>y</code>, and <code>stride</code> parameters can be used to specify
    634    * the region into which the source image should be decompressed.
    635    *
    636    * @param x x offset (in pixels) of the region in the destination image into
    637    * which the source image should be decompressed/decoded
    638    *
    639    * @param y y offset (in pixels) of the region in the destination image into
    640    * which the source image should be decompressed/decoded
    641    *
    642    * @param desiredWidth If the source image is a JPEG image, then this
    643    * specifies the desired width (in pixels) of the decompressed image (or
    644    * image region.)  If the desired destination image dimensions are different
    645    * than the source image dimensions, then TurboJPEG will use scaling in the
    646    * JPEG decompressor to generate the largest possible image that will fit
    647    * within the desired dimensions.  Setting this to 0 is the same as setting
    648    * it to the width of the JPEG image (in other words, the width will not be
    649    * considered when determining the scaled image size.)  This parameter is
    650    * ignored if the source image is a YUV image.
    651    *
    652    * @param stride pixels per line of the destination image.  Normally, this
    653    * should be set to <code>scaledWidth</code>, but you can use this to, for
    654    * instance, decompress the JPEG image into a region of a larger image.
    655    * NOTE: if the source image is a JPEG image, then <code>scaledWidth</code>
    656    * can be determined by calling <code>
    657    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
    658    * </code> or by calling {@link #getScaledWidth}.  If the source image is a
    659    * YUV image, then <code>scaledWidth</code> is the width of the YUV image.
    660    * Setting this parameter to 0 is the equivalent of setting it to
    661    * <code>scaledWidth</code>.
    662    *
    663    * @param desiredHeight If the source image is a JPEG image, then this
    664    * specifies the desired height (in pixels) of the decompressed image (or
    665    * image region.)  If the desired destination image dimensions are different
    666    * than the source image dimensions, then TurboJPEG will use scaling in the
    667    * JPEG decompressor to generate the largest possible image that will fit
    668    * within the desired dimensions.  Setting this to 0 is the same as setting
    669    * it to the height of the JPEG image (in other words, the height will not be
    670    * considered when determining the scaled image size.)  This parameter is
    671    * ignored if the source image is a YUV image.
    672    *
    673    * @param pixelFormat pixel format of the decompressed image (one of
    674    * {@link TJ#PF_RGB TJ.PF_*})
    675    *
    676    * @param flags the bitwise OR of one or more of
    677    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    678    */
    679   public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
    680                          int stride, int desiredHeight, int pixelFormat,
    681                          int flags) throws TJException {
    682     if (jpegBuf == null && yuvImage == null)
    683       throw new IllegalStateException(NO_ASSOC_ERROR);
    684     if (dstBuf == null || x < 0 || y < 0 || stride < 0 ||
    685         (yuvImage != null && (desiredWidth < 0 || desiredHeight < 0)) ||
    686         pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
    687       throw new IllegalArgumentException("Invalid argument in decompress()");
    688     if (yuvImage != null)
    689       decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
    690                 yuvImage.getStrides(), yuvImage.getSubsamp(), dstBuf, x, y,
    691                 yuvImage.getWidth(), stride, yuvImage.getHeight(), pixelFormat,
    692                 flags);
    693     else
    694       decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
    695                  desiredHeight, pixelFormat, flags);
    696   }
    697 
    698   /**
    699    * Decompress the JPEG source image or decode the YUV source image associated
    700    * with this decompressor instance and output a decompressed/decoded image to
    701    * the given <code>BufferedImage</code> instance.
    702    *
    703    * @param dstImage a <code>BufferedImage</code> instance that will receive
    704    * the decompressed/decoded image.  If the source image is a JPEG image, then
    705    * the width and height of the <code>BufferedImage</code> instance must match
    706    * one of the scaled image sizes that TurboJPEG is capable of generating from
    707    * the JPEG image.  If the source image is a YUV image, then the width and
    708    * height of the <code>BufferedImage</code> instance must match the width and
    709    * height of the YUV image.
    710    *
    711    * @param flags the bitwise OR of one or more of
    712    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    713    */
    714   public void decompress(BufferedImage dstImage, int flags)
    715                          throws TJException {
    716     if (dstImage == null || flags < 0)
    717       throw new IllegalArgumentException("Invalid argument in decompress()");
    718     int desiredWidth = dstImage.getWidth();
    719     int desiredHeight = dstImage.getHeight();
    720     int scaledWidth, scaledHeight;
    721 
    722     if (yuvImage != null) {
    723       if (desiredWidth != yuvImage.getWidth() ||
    724           desiredHeight != yuvImage.getHeight())
    725         throw new IllegalArgumentException("BufferedImage dimensions do not match the dimensions of the source image.");
    726       scaledWidth = yuvImage.getWidth();
    727       scaledHeight = yuvImage.getHeight();
    728     } else {
    729       scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
    730       scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
    731       if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
    732         throw new IllegalArgumentException("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
    733     }
    734     int pixelFormat;  boolean intPixels = false;
    735     if (byteOrder == null)
    736       byteOrder = ByteOrder.nativeOrder();
    737     switch(dstImage.getType()) {
    738       case BufferedImage.TYPE_3BYTE_BGR:
    739         pixelFormat = TJ.PF_BGR;  break;
    740       case BufferedImage.TYPE_4BYTE_ABGR:
    741       case BufferedImage.TYPE_4BYTE_ABGR_PRE:
    742         pixelFormat = TJ.PF_XBGR;  break;
    743       case BufferedImage.TYPE_BYTE_GRAY:
    744         pixelFormat = TJ.PF_GRAY;  break;
    745       case BufferedImage.TYPE_INT_BGR:
    746         if (byteOrder == ByteOrder.BIG_ENDIAN)
    747           pixelFormat = TJ.PF_XBGR;
    748         else
    749           pixelFormat = TJ.PF_RGBX;
    750         intPixels = true;  break;
    751       case BufferedImage.TYPE_INT_RGB:
    752         if (byteOrder == ByteOrder.BIG_ENDIAN)
    753           pixelFormat = TJ.PF_XRGB;
    754         else
    755           pixelFormat = TJ.PF_BGRX;
    756         intPixels = true;  break;
    757       case BufferedImage.TYPE_INT_ARGB:
    758       case BufferedImage.TYPE_INT_ARGB_PRE:
    759         if (byteOrder == ByteOrder.BIG_ENDIAN)
    760           pixelFormat = TJ.PF_ARGB;
    761         else
    762           pixelFormat = TJ.PF_BGRA;
    763         intPixels = true;  break;
    764       default:
    765         throw new IllegalArgumentException("Unsupported BufferedImage format");
    766     }
    767     WritableRaster wr = dstImage.getRaster();
    768     if (intPixels) {
    769       SinglePixelPackedSampleModel sm =
    770         (SinglePixelPackedSampleModel)dstImage.getSampleModel();
    771       int stride = sm.getScanlineStride();
    772       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
    773       int[] buf = db.getData();
    774       if (yuvImage != null)
    775         decodeYUV(yuvImage.getPlanes(), yuvImage.getOffsets(),
    776                   yuvImage.getStrides(), yuvImage.getSubsamp(), buf, 0, 0,
    777                   yuvImage.getWidth(), stride, yuvImage.getHeight(),
    778                   pixelFormat, flags);
    779       else {
    780         if (jpegBuf == null)
    781           throw new IllegalStateException(NO_ASSOC_ERROR);
    782         decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
    783                    scaledHeight, pixelFormat, flags);
    784       }
    785     } else {
    786       ComponentSampleModel sm =
    787         (ComponentSampleModel)dstImage.getSampleModel();
    788       int pixelSize = sm.getPixelStride();
    789       if (pixelSize != TJ.getPixelSize(pixelFormat))
    790         throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage");
    791       int pitch = sm.getScanlineStride();
    792       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
    793       byte[] buf = db.getData();
    794       decompress(buf, 0, 0, scaledWidth, pitch, scaledHeight, pixelFormat,
    795                  flags);
    796     }
    797   }
    798 
    799   /**
    800    * Decompress the JPEG source image or decode the YUV source image associated
    801    * with this decompressor instance and return a <code>BufferedImage</code>
    802    * instance containing the decompressed/decoded image.
    803    *
    804    * @param desiredWidth see
    805    * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
    806    * description
    807    *
    808    * @param desiredHeight see
    809    * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
    810    * description
    811    *
    812    * @param bufferedImageType the image type of the <code>BufferedImage</code>
    813    * instance that will be created (for instance,
    814    * <code>BufferedImage.TYPE_INT_RGB</code>)
    815    *
    816    * @param flags the bitwise OR of one or more of
    817    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
    818    *
    819    * @return a <code>BufferedImage</code> instance containing the
    820    * decompressed/decoded image.
    821    */
    822   public BufferedImage decompress(int desiredWidth, int desiredHeight,
    823                                   int bufferedImageType, int flags)
    824                                   throws TJException {
    825     if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 0)) ||
    826         flags < 0)
    827       throw new IllegalArgumentException("Invalid argument in decompress()");
    828     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
    829     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
    830     BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
    831                                           bufferedImageType);
    832     decompress(img, flags);
    833     return img;
    834   }
    835 
    836   /**
    837    * Free the native structures associated with this decompressor instance.
    838    */
    839   @Override
    840   public void close() throws TJException {
    841     if (handle != 0)
    842       destroy();
    843   }
    844 
    845   @Override
    846   protected void finalize() throws Throwable {
    847     try {
    848       close();
    849     } catch(TJException e) {
    850     } finally {
    851       super.finalize();
    852     }
    853   };
    854 
    855   private native void init() throws TJException;
    856 
    857   private native void destroy() throws TJException;
    858 
    859   private native void decompressHeader(byte[] srcBuf, int size)
    860     throws TJException;
    861 
    862   @Deprecated
    863   private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
    864     int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
    865     throws TJException;
    866 
    867   private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
    868     int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
    869     int flags) throws TJException;
    870 
    871   @Deprecated
    872   private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
    873     int desiredWidth, int stride, int desiredHeight, int pixelFormat,
    874     int flags) throws TJException;
    875 
    876   private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
    877     int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
    878     int flags) throws TJException;
    879 
    880   @Deprecated
    881   private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
    882     int flags) throws TJException;
    883 
    884   private native void decompressToYUV(byte[] srcBuf, int size,
    885     byte[][] dstPlanes, int[] dstOffsets, int desiredWidth, int[] dstStrides,
    886     int desiredheight, int flags) throws TJException;
    887 
    888   private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
    889     int[] srcStrides, int subsamp, byte[] dstBuf, int x, int y, int width,
    890     int pitch, int height, int pixelFormat, int flags) throws TJException;
    891 
    892   private native void decodeYUV(byte[][] srcPlanes, int[] srcOffsets,
    893     int[] srcStrides, int subsamp, int[] dstBuf, int x, int y, int width,
    894     int stride, int height, int pixelFormat, int flags) throws TJException;
    895 
    896   static {
    897     TJLoader.load();
    898   }
    899 
    900   protected long handle = 0;
    901   protected byte[] jpegBuf = null;
    902   protected int jpegBufSize = 0;
    903   protected YUVImage yuvImage = null;
    904   protected int jpegWidth = 0;
    905   protected int jpegHeight = 0;
    906   protected int jpegSubsamp = -1;
    907   protected int jpegColorspace = -1;
    908   private ByteOrder byteOrder = null;
    909 }
    910