Imported Upstream version 1.3.1
[platform/upstream/libjpeg-turbo.git] / java / org / libjpegturbo / turbojpeg / TJDecompressor.java
1 /*
2  * Copyright (C)2011-2014 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 image
51    * 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)
55    */
56   public TJDecompressor(byte[] jpegImage) throws Exception {
57     init();
58     setJPEGImage(jpegImage, jpegImage.length);
59   }
60
61   /**
62    * Create a TurboJPEG decompressor instance and associate the JPEG image
63    * of length <code>imageSize</code> bytes stored in <code>jpegImage</code>
64    * with the newly created instance.
65    *
66    * @param jpegImage JPEG image buffer
67    *
68    * @param imageSize size of the JPEG image (in bytes)
69    */
70   public TJDecompressor(byte[] jpegImage, int imageSize) throws Exception {
71     init();
72     setJPEGImage(jpegImage, imageSize);
73   }
74
75   /**
76    * Associate the JPEG image of length <code>imageSize</code> bytes stored in
77    * <code>jpegImage</code> with this decompressor instance.  This image will
78    * be used as the source image for subsequent decompress operations.
79    *
80    * @param jpegImage JPEG image buffer
81    *
82    * @param imageSize size of the JPEG image (in bytes)
83    */
84   public void setJPEGImage(byte[] jpegImage, int imageSize) throws Exception {
85     if (jpegImage == null || imageSize < 1)
86       throw new Exception("Invalid argument in setJPEGImage()");
87     jpegBuf = jpegImage;
88     jpegBufSize = imageSize;
89     decompressHeader(jpegBuf, jpegBufSize);
90   }
91
92   /**
93    * Returns the width of the JPEG image associated with this decompressor
94    * instance.
95    *
96    * @return the width of the JPEG image associated with this decompressor
97    * instance
98    */
99   public int getWidth() throws Exception {
100     if (jpegWidth < 1)
101       throw new Exception(NO_ASSOC_ERROR);
102     return jpegWidth;
103   }
104
105   /**
106    * Returns the height of the JPEG image associated with this decompressor
107    * instance.
108    *
109    * @return the height of the JPEG image associated with this decompressor
110    * instance
111    */
112   public int getHeight() throws Exception {
113     if (jpegHeight < 1)
114       throw new Exception(NO_ASSOC_ERROR);
115     return jpegHeight;
116   }
117
118   /**
119    * Returns the level of chrominance subsampling used in the JPEG image
120    * associated with this decompressor instance.  See {@link TJ TJ.SAMP_*}.
121    *
122    * @return the level of chrominance subsampling used in the JPEG image
123    * associated with this decompressor instance
124    */
125   public int getSubsamp() throws Exception {
126     if (jpegSubsamp < 0)
127       throw new Exception(NO_ASSOC_ERROR);
128     if (jpegSubsamp >= TJ.NUMSAMP)
129       throw new Exception("JPEG header information is invalid");
130     return jpegSubsamp;
131   }
132
133   /**
134    * Returns the JPEG image buffer associated with this decompressor instance.
135    *
136    * @return the JPEG image buffer associated with this decompressor instance
137    */
138   public byte[] getJPEGBuf() throws Exception {
139     if (jpegBuf == null)
140       throw new Exception(NO_ASSOC_ERROR);
141     return jpegBuf;
142   }
143
144   /**
145    * Returns the size of the JPEG image (in bytes) associated with this
146    * decompressor instance.
147    *
148    * @return the size of the JPEG image (in bytes) associated with this
149    * decompressor instance
150    */
151   public int getJPEGSize() throws Exception {
152     if (jpegBufSize < 1)
153       throw new Exception(NO_ASSOC_ERROR);
154     return jpegBufSize;
155   }
156
157   /**
158    * Returns the width of the largest scaled-down image that the TurboJPEG
159    * decompressor can generate without exceeding the desired image width and
160    * height.
161    *
162    * @param desiredWidth desired width (in pixels) of the decompressed image.
163    * Setting this to 0 is the same as setting it to the width of the JPEG image
164    * (in other words, the width will not be considered when determining the
165    * scaled image size.)
166    *
167    * @param desiredHeight desired height (in pixels) of the decompressed image.
168    * Setting this to 0 is the same as setting it to the height of the JPEG
169    * image (in other words, the height will not be considered when determining
170    * the scaled image size.)
171    *
172    * @return the width of the largest scaled-down image that the TurboJPEG
173    * decompressor can generate without exceeding the desired image width and
174    * height
175    */
176   public int getScaledWidth(int desiredWidth, int desiredHeight)
177                             throws Exception {
178     if (jpegWidth < 1 || jpegHeight < 1)
179       throw new Exception(NO_ASSOC_ERROR);
180     if (desiredWidth < 0 || desiredHeight < 0)
181       throw new Exception("Invalid argument in getScaledWidth()");
182     TJScalingFactor[] sf = TJ.getScalingFactors();
183     if (desiredWidth == 0)
184       desiredWidth = jpegWidth;
185     if (desiredHeight == 0)
186       desiredHeight = jpegHeight;
187     int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
188     for (int i = 0; i < sf.length; i++) {
189       scaledWidth = sf[i].getScaled(jpegWidth);
190       scaledHeight = sf[i].getScaled(jpegHeight);
191       if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
192         break;
193     }
194     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
195       throw new Exception("Could not scale down to desired image dimensions");
196     return scaledWidth;
197   }
198
199   /**
200    * Returns the height of the largest scaled-down image that the TurboJPEG
201    * decompressor can generate without exceeding the desired image width and
202    * height.
203    *
204    * @param desiredWidth desired width (in pixels) of the decompressed image.
205    * Setting this to 0 is the same as setting it to the width of the JPEG image
206    * (in other words, the width will not be considered when determining the
207    * scaled image size.)
208    *
209    * @param desiredHeight desired height (in pixels) of the decompressed image.
210    * Setting this to 0 is the same as setting it to the height of the JPEG
211    * image (in other words, the height will not be considered when determining
212    * the scaled image size.)
213    *
214    * @return the height of the largest scaled-down image that the TurboJPEG
215    * decompressor can generate without exceeding the desired image width and
216    * height
217    */
218   public int getScaledHeight(int desiredWidth, int desiredHeight)
219                              throws Exception {
220     if (jpegWidth < 1 || jpegHeight < 1)
221       throw new Exception(NO_ASSOC_ERROR);
222     if (desiredWidth < 0 || desiredHeight < 0)
223       throw new Exception("Invalid argument in getScaledHeight()");
224     TJScalingFactor[] sf = TJ.getScalingFactors();
225     if (desiredWidth == 0)
226       desiredWidth = jpegWidth;
227     if (desiredHeight == 0)
228       desiredHeight = jpegHeight;
229     int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
230     for (int i = 0; i < sf.length; i++) {
231       scaledWidth = sf[i].getScaled(jpegWidth);
232       scaledHeight = sf[i].getScaled(jpegHeight);
233       if (scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
234         break;
235     }
236     if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
237       throw new Exception("Could not scale down to desired image dimensions");
238     return scaledHeight;
239   }
240
241   /**
242    * Decompress the JPEG source image associated with this decompressor
243    * instance and output a decompressed image to the given destination buffer.
244    *
245    * @param dstBuf buffer that will receive the decompressed image.  This
246    * buffer should normally be <code>pitch * scaledHeight</code> bytes in size,
247    * where <code>scaledHeight</code> can be determined by calling <code>
248    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
249    * </code> with one of the scaling factors returned from {@link
250    * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  However,
251    * the buffer may also be larger than the dimensions of the JPEG image, in
252    * which case the <code>x</code>, <code>y</code>, and <code>pitch</code>
253    * parameters can be used to specify the region into which the JPEG image
254    * should be decompressed.
255    *
256    * @param x x offset (in pixels) of the region into which the JPEG image
257    * should be decompressed, relative to the start of <code>dstBuf</code>.
258    *
259    * @param y y offset (in pixels) of the region into which the JPEG image
260    * should be decompressed, relative to the start of <code>dstBuf</code>.
261    *
262    * @param desiredWidth desired width (in pixels) of the decompressed image
263    * (or image region.)  If the desired image dimensions are different than the
264    * dimensions of the JPEG image being decompressed, then TurboJPEG will use
265    * scaling in the JPEG decompressor to generate the largest possible image
266    * that will fit within the desired dimensions.  Setting this to 0 is the
267    * same as setting it to the width of the JPEG image (in other words, the
268    * width will not be considered when determining the scaled image size.)
269    *
270    * @param pitch bytes per line of the destination image.  Normally, this
271    * should be set to <code>scaledWidth * TJ.pixelSize(pixelFormat)</code> if
272    * the decompressed image is unpadded, but you can use this to, for instance,
273    * pad each line of the decompressed image to a 4-byte boundary or to
274    * decompress the JPEG image into a region of a larger image.  NOTE:
275    * <code>scaledWidth</code> can be determined by calling <code>
276    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
277    * </code> or by calling {@link #getScaledWidth}.  Setting this parameter to
278    * 0 is the equivalent of setting it to <code>scaledWidth *
279    * TJ.pixelSize(pixelFormat)</code>.
280    *
281    * @param desiredHeight desired height (in pixels) of the decompressed image
282    * (or image region.)  If the desired image dimensions are different than the
283    * dimensions of the JPEG image being decompressed, then TurboJPEG will use
284    * scaling in the JPEG decompressor to generate the largest possible image
285    * that will fit within the desired dimensions.  Setting this to 0 is the
286    * same as setting it to the height of the JPEG image (in other words, the
287    * height will not be considered when determining the scaled image size.)
288    *
289    * @param pixelFormat pixel format of the decompressed/decoded image (one of
290    * {@link TJ#PF_RGB TJ.PF_*})
291    *
292    * @param flags the bitwise OR of one or more of
293    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
294    */
295   public void decompress(byte[] dstBuf, int x, int y, int desiredWidth,
296                          int pitch, int desiredHeight, int pixelFormat,
297                          int flags) throws Exception {
298     if (jpegBuf == null)
299       throw new Exception(NO_ASSOC_ERROR);
300     if (dstBuf == null || x < 0 || y < 0 || desiredWidth < 0 || pitch < 0 ||
301         desiredHeight < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF ||
302         flags < 0)
303       throw new Exception("Invalid argument in decompress()");
304     if (x > 0 || y > 0)
305       decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
306                  desiredHeight, pixelFormat, flags);
307     else
308       decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
309                  desiredHeight, pixelFormat, flags);
310   }
311
312   /**
313    * @deprecated Use
314    * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
315    */
316   @Deprecated
317   public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
318                          int desiredHeight, int pixelFormat, int flags)
319                          throws Exception {
320     decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
321                flags);
322   }
323
324   /**
325    * Decompress the JPEG source image associated with this decompressor
326    * instance and return a buffer containing the decompressed image.
327    *
328    * @param desiredWidth see
329    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
330    * for description
331    *
332    * @param pitch see
333    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
334    * for description
335    *
336    * @param desiredHeight see
337    * {@link #decompress(byte[], int, int, int, int, int, int, int)}
338    * for description
339    *
340    * @param pixelFormat pixel format of the decompressed image (one of
341    * {@link TJ#PF_RGB TJ.PF_*})
342    *
343    * @param flags the bitwise OR of one or more of
344    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
345    *
346    * @return a buffer containing the decompressed image
347    */
348   public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
349                            int pixelFormat, int flags) throws Exception {
350     if (desiredWidth < 0 || pitch < 0 || desiredHeight < 0 ||
351         pixelFormat < 0 || pixelFormat >= TJ.NUMPF || flags < 0)
352       throw new Exception("Invalid argument in decompress()");
353     int pixelSize = TJ.getPixelSize(pixelFormat);
354     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
355     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
356     if (pitch == 0)
357       pitch = scaledWidth * pixelSize;
358     byte[] buf = new byte[pitch * scaledHeight];
359     decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
360     return buf;
361   }
362
363   /**
364    * Decompress the JPEG source image associated with this decompressor
365    * instance and output a YUV planar image to the given destination buffer.
366    * This method performs JPEG decompression but leaves out the color
367    * conversion step, so a planar YUV image is generated instead of an RGB
368    * image.  The padding of the planes in this image is the same as in the
369    * images generated by {@link TJCompressor#encodeYUV(byte[], int)}.
370    * <p>
371    * NOTE: Technically, the JPEG format uses the YCbCr colorspace, but per the
372    * convention of the digital video community, the TurboJPEG API uses "YUV" to
373    * refer to an image format consisting of Y, Cb, and Cr image planes.
374    *
375    * @param dstBuf buffer that will receive the YUV planar image.  Use
376    * {@link TJ#bufSizeYUV} to determine the appropriate size for this buffer
377    * based on the image width, height, and level of chrominance subsampling.
378    *
379    * @param flags the bitwise OR of one or more of
380    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
381    */
382   public void decompressToYUV(byte[] dstBuf, int flags) throws Exception {
383     if (jpegBuf == null)
384       throw new Exception(NO_ASSOC_ERROR);
385     if (dstBuf == null || flags < 0)
386       throw new Exception("Invalid argument in decompressToYUV()");
387     decompressToYUV(jpegBuf, jpegBufSize, dstBuf, flags);
388   }
389
390
391   /**
392    * Decompress the JPEG source image associated with this decompressor
393    * instance and return a buffer containing a YUV planar image.  See {@link
394    * #decompressToYUV(byte[], int)} for more detail.
395    *
396    * @param flags the bitwise OR of one or more of
397    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
398    *
399    * @return a buffer containing a YUV planar image
400    */
401   public byte[] decompressToYUV(int flags) throws Exception {
402     if (flags < 0)
403       throw new Exception("Invalid argument in decompressToYUV()");
404     if (jpegWidth < 1 || jpegHeight < 1 || jpegSubsamp < 0)
405       throw new Exception(NO_ASSOC_ERROR);
406     if (jpegSubsamp >= TJ.NUMSAMP)
407       throw new Exception("JPEG header information is invalid");
408     byte[] buf = new byte[TJ.bufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)];
409     decompressToYUV(buf, flags);
410     return buf;
411   }
412
413   /**
414    * Decompress the JPEG source image associated with this decompressor
415    * instance and output a decompressed image to the given destination buffer.
416    *
417    * @param dstBuf buffer that will receive the decompressed image.  This
418    * buffer should normally be <code>stride * scaledHeight</code> pixels in
419    * size, where <code>scaledHeight</code> can be determined by calling <code>
420    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegHeight)
421    * </code> with one of the scaling factors returned from {@link
422    * TJ#getScalingFactors} or by calling {@link #getScaledHeight}.  However,
423    * the buffer may also be larger than the dimensions of the JPEG image, in
424    * which case the <code>x</code>, <code>y</code>, and <code>stride</code>
425    * parameters can be used to specify the region into which the JPEG image
426    * should be decompressed.
427    *
428    * @param x x offset (in pixels) of the region into which the JPEG image
429    * should be decompressed, relative to the start of <code>dstBuf</code>.
430    *
431    * @param y y offset (in pixels) of the region into which the JPEG image
432    * should be decompressed, relative to the start of <code>dstBuf</code>.
433    *
434    * @param desiredWidth desired width (in pixels) of the decompressed image
435    * (or image region.)  If the desired image dimensions are different than the
436    * dimensions of the JPEG image being decompressed, then TurboJPEG will use
437    * scaling in the JPEG decompressor to generate the largest possible image
438    * that will fit within the desired dimensions.  Setting this to 0 is the
439    * same as setting it to the width of the JPEG image (in other words, the
440    * width will not be considered when determining the scaled image size.)
441    *
442    * @param stride pixels per line of the destination image.  Normally, this
443    * should be set to <code>scaledWidth</code>, but you can use this to, for
444    * instance, decompress the JPEG image into a region of a larger image.
445    * NOTE: <code>scaledWidth</code> can be determined by calling <code>
446    * scalingFactor.{@link TJScalingFactor#getScaled getScaled}(jpegWidth)
447    * </code> or by calling {@link #getScaledWidth}.  Setting this parameter to
448    * 0 is the equivalent of setting it to <code>scaledWidth</code>.
449    *
450    * @param desiredHeight desired height (in pixels) of the decompressed image
451    * (or image region.)  If the desired image dimensions are different than the
452    * dimensions of the JPEG image being decompressed, then TurboJPEG will use
453    * scaling in the JPEG decompressor to generate the largest possible image
454    * that will fit within the desired dimensions.  Setting this to 0 is the
455    * same as setting it to the height of the JPEG image (in other words, the
456    * height will not be considered when determining the scaled image size.)
457    *
458    * @param pixelFormat pixel format of the decompressed image (one of
459    * {@link TJ#PF_RGB TJ.PF_*})
460    *
461    * @param flags the bitwise OR of one or more of
462    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
463    */
464   public void decompress(int[] dstBuf, int x, int y, int desiredWidth,
465                          int stride, int desiredHeight, int pixelFormat,
466                          int flags) throws Exception {
467     if (jpegBuf == null)
468       throw new Exception(NO_ASSOC_ERROR);
469     if (dstBuf == null || x < 0 || y < 0 || desiredWidth < 0 || stride < 0 ||
470         desiredHeight < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF ||
471         flags < 0)
472       throw new Exception("Invalid argument in decompress()");
473     decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
474                desiredHeight, pixelFormat, flags);
475   }
476
477   /**
478    * Decompress the JPEG source image associated with this decompressor
479    * instance and output a decompressed image to the given
480    * <code>BufferedImage</code> instance.
481    *
482    * @param dstImage a <code>BufferedImage</code> instance that will receive
483    * the decompressed image.  The width and height of the
484    * <code>BufferedImage</code> instance must match one of the scaled image
485    * sizes that TurboJPEG is capable of generating from the JPEG image.
486    *
487    *
488    * @param flags the bitwise OR of one or more of
489    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
490    */
491   public void decompress(BufferedImage dstImage, int flags) throws Exception {
492     if (dstImage == null || flags < 0)
493       throw new Exception("Invalid argument in decompress()");
494     int desiredWidth = dstImage.getWidth();
495     int desiredHeight = dstImage.getHeight();
496     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
497     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
498     if (scaledWidth != desiredWidth || scaledHeight != desiredHeight)
499       throw new Exception("BufferedImage dimensions do not match one of the scaled image sizes that TurboJPEG is capable of generating.");
500     int pixelFormat;  boolean intPixels = false;
501     if (byteOrder == null)
502       byteOrder = ByteOrder.nativeOrder();
503     switch(dstImage.getType()) {
504       case BufferedImage.TYPE_3BYTE_BGR:
505         pixelFormat = TJ.PF_BGR;  break;
506       case BufferedImage.TYPE_4BYTE_ABGR:
507       case BufferedImage.TYPE_4BYTE_ABGR_PRE:
508         pixelFormat = TJ.PF_XBGR;  break;
509       case BufferedImage.TYPE_BYTE_GRAY:
510         pixelFormat = TJ.PF_GRAY;  break;
511       case BufferedImage.TYPE_INT_BGR:
512         if (byteOrder == ByteOrder.BIG_ENDIAN)
513           pixelFormat = TJ.PF_XBGR;
514         else
515           pixelFormat = TJ.PF_RGBX;
516         intPixels = true;  break;
517       case BufferedImage.TYPE_INT_RGB:
518         if (byteOrder == ByteOrder.BIG_ENDIAN)
519           pixelFormat = TJ.PF_XRGB;
520         else
521           pixelFormat = TJ.PF_BGRX;
522         intPixels = true;  break;
523       case BufferedImage.TYPE_INT_ARGB:
524       case BufferedImage.TYPE_INT_ARGB_PRE:
525         if (byteOrder == ByteOrder.BIG_ENDIAN)
526           pixelFormat = TJ.PF_ARGB;
527         else
528           pixelFormat = TJ.PF_BGRA;
529         intPixels = true;  break;
530       default:
531         throw new Exception("Unsupported BufferedImage format");
532     }
533     WritableRaster wr = dstImage.getRaster();
534     if (intPixels) {
535       SinglePixelPackedSampleModel sm =
536         (SinglePixelPackedSampleModel)dstImage.getSampleModel();
537       int stride = sm.getScanlineStride();
538       DataBufferInt db = (DataBufferInt)wr.getDataBuffer();
539       int[] buf = db.getData();
540       if (jpegBuf == null)
541         throw new Exception(NO_ASSOC_ERROR);
542       decompress(jpegBuf, jpegBufSize, buf, scaledWidth, stride, scaledHeight,
543                  pixelFormat, flags);
544     } else {
545       ComponentSampleModel sm =
546         (ComponentSampleModel)dstImage.getSampleModel();
547       int pixelSize = sm.getPixelStride();
548       if (pixelSize != TJ.getPixelSize(pixelFormat))
549         throw new Exception("Inconsistency between pixel format and pixel size in BufferedImage");
550       int pitch = sm.getScanlineStride();
551       DataBufferByte db = (DataBufferByte)wr.getDataBuffer();
552       byte[] buf = db.getData();
553       decompress(buf, scaledWidth, pitch, scaledHeight, pixelFormat, flags);
554     }
555   }
556
557   /**
558    * Decompress the JPEG source image associated with this decompressor
559    * instance and return a <code>BufferedImage</code> instance containing the
560    * decompressed image.
561    *
562    * @param desiredWidth see
563    * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
564    * description
565    *
566    * @param desiredHeight see
567    * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
568    * description
569    *
570    * @param bufferedImageType the image type of the <code>BufferedImage</code>
571    * instance that will be created (for instance,
572    * <code>BufferedImage.TYPE_INT_RGB</code>)
573    *
574    * @param flags the bitwise OR of one or more of
575    * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
576    *
577    * @return a <code>BufferedImage</code> instance containing the
578    * decompressed image
579    */
580   public BufferedImage decompress(int desiredWidth, int desiredHeight,
581                                   int bufferedImageType, int flags)
582                                   throws Exception {
583     if (desiredWidth < 0 || desiredHeight < 0 || flags < 0)
584       throw new Exception("Invalid argument in decompress()");
585     int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
586     int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
587     BufferedImage img = new BufferedImage(scaledWidth, scaledHeight,
588                                           bufferedImageType);
589     decompress(img, flags);
590     return img;
591   }
592
593   /**
594    * Free the native structures associated with this decompressor instance.
595    */
596   public void close() throws Exception {
597     destroy();
598   }
599
600   protected void finalize() throws Throwable {
601     try {
602       close();
603     } catch(Exception e) {
604     } finally {
605       super.finalize();
606     }
607   };
608
609   private native void init() throws Exception;
610
611   private native void destroy() throws Exception;
612
613   private native void decompressHeader(byte[] srcBuf, int size)
614     throws Exception;
615
616   private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
617     int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
618     throws Exception; // deprecated
619
620   private native void decompress(byte[] srcBuf, int size, byte[] dstBuf, int x,
621     int y, int desiredWidth, int pitch, int desiredHeight, int pixelFormat,
622     int flags) throws Exception;
623
624   private native void decompress(byte[] srcBuf, int size, int[] dstBuf,
625     int desiredWidth, int stride, int desiredHeight, int pixelFormat,
626     int flags) throws Exception; // deprecated
627
628   private native void decompress(byte[] srcBuf, int size, int[] dstBuf, int x,
629     int y, int desiredWidth, int stride, int desiredHeight, int pixelFormat,
630     int flags) throws Exception;
631
632   private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
633     int flags) throws Exception;
634
635   static {
636     TJLoader.load();
637   }
638
639   protected long handle = 0;
640   protected byte[] jpegBuf = null;
641   protected int jpegBufSize = 0;
642   protected int jpegWidth = 0;
643   protected int jpegHeight = 0;
644   protected int jpegSubsamp = -1;
645   private ByteOrder byteOrder = null;
646 };