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