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