2 * Copyright (C)2011-2015, 2018, 2022 D. R. Commander. All Rights Reserved.
3 * Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
30 package org.libjpegturbo.turbojpeg;
32 import java.awt.image.*;
37 * TurboJPEG decompressor
39 public class TJDecompressor implements Closeable {
41 private static final String NO_ASSOC_ERROR =
42 "No JPEG image is associated with this instance";
45 * Create a TurboJPEG decompresssor instance.
47 public TJDecompressor() throws TJException {
52 * Create a TurboJPEG decompressor instance and associate the JPEG source
53 * image stored in <code>jpegImage</code> with the newly created instance.
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.
58 public TJDecompressor(byte[] jpegImage) throws TJException {
60 setSourceImage(jpegImage, jpegImage.length);
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.
68 * @param jpegImage JPEG image buffer. This buffer is not modified.
70 * @param imageSize size of the JPEG image (in bytes)
72 public TJDecompressor(byte[] jpegImage, int imageSize) throws TJException {
74 setSourceImage(jpegImage, imageSize);
78 * Create a TurboJPEG decompressor instance and associate the YUV planar
79 * source image stored in <code>yuvImage</code> with the newly created
82 * @param yuvImage {@link YUVImage} instance containing a YUV planar
83 * image to be decoded. This image is not modified.
85 @SuppressWarnings("checkstyle:HiddenField")
86 public TJDecompressor(YUVImage yuvImage) throws TJException {
88 setSourceImage(yuvImage);
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.
103 * @param jpegImage buffer containing a JPEG image or an "abbreviated table
104 * specification" (AKA "tables-only") datastream. This buffer is not
107 * @param imageSize size of the JPEG image (in bytes)
109 public void setSourceImage(byte[] jpegImage, int imageSize)
111 if (jpegImage == null || imageSize < 1)
112 throw new IllegalArgumentException("Invalid argument in setSourceImage()");
114 jpegBufSize = imageSize;
115 decompressHeader(jpegBuf, jpegBufSize);
120 * @deprecated Use {@link #setSourceImage(byte[], int)} instead.
122 @SuppressWarnings("checkstyle:JavadocMethod")
124 public void setJPEGImage(byte[] jpegImage, int imageSize)
126 setSourceImage(jpegImage, imageSize);
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.
134 * @param srcImage {@link YUVImage} instance containing a YUV planar image to
135 * be decoded. This image is not modified.
137 public void setSourceImage(YUVImage srcImage) {
138 if (srcImage == null)
139 throw new IllegalArgumentException("Invalid argument in setSourceImage()");
147 * Returns the width of the source image (JPEG or YUV) associated with this
148 * decompressor instance.
150 * @return the width of the source image (JPEG or YUV) associated with this
151 * decompressor instance.
153 public int getWidth() {
154 if (yuvImage != null)
155 return yuvImage.getWidth();
157 throw new IllegalStateException(NO_ASSOC_ERROR);
162 * Returns the height of the source image (JPEG or YUV) associated with this
163 * decompressor instance.
165 * @return the height of the source image (JPEG or YUV) associated with this
166 * decompressor instance.
168 public int getHeight() {
169 if (yuvImage != null)
170 return yuvImage.getHeight();
172 throw new IllegalStateException(NO_ASSOC_ERROR);
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_*}.
181 * @return the level of chrominance subsampling used in the source image
182 * (JPEG or YUV) associated with this decompressor instance.
184 public int getSubsamp() {
185 if (yuvImage != null)
186 return yuvImage.getSubsamp();
188 throw new IllegalStateException(NO_ASSOC_ERROR);
189 if (jpegSubsamp >= TJ.NUMSAMP)
190 throw new IllegalStateException("JPEG header information is invalid");
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}.
199 * @return the colorspace used in the source image (JPEG or YUV) associated
200 * with this decompressor instance.
202 public int getColorspace() {
203 if (yuvImage != null)
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;
213 * Returns the JPEG image buffer associated with this decompressor instance.
215 * @return the JPEG image buffer associated with this decompressor instance.
217 public byte[] getJPEGBuf() {
219 throw new IllegalStateException(NO_ASSOC_ERROR);
224 * Returns the size of the JPEG image (in bytes) associated with this
225 * decompressor instance.
227 * @return the size of the JPEG image (in bytes) associated with this
228 * decompressor instance.
230 public int getJPEGSize() {
232 throw new IllegalStateException(NO_ASSOC_ERROR);
237 * Returns the width of the largest scaled-down image that the TurboJPEG
238 * decompressor can generate without exceeding the desired image width and
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.)
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.)
251 * @return the width of the largest scaled-down image that the TurboJPEG
252 * decompressor can generate without exceeding the desired image width and
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)
272 if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
273 throw new IllegalArgumentException("Could not scale down to desired image dimensions");
278 * Returns the height of the largest scaled-down image that the TurboJPEG
279 * decompressor can generate without exceeding the desired image width and
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.)
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.)
292 * @return the height of the largest scaled-down image that the TurboJPEG
293 * decompressor can generate without exceeding the desired image width and
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)
313 if (scaledWidth > desiredWidth || scaledHeight > desiredHeight)
314 throw new IllegalArgumentException("Could not scale down to desired image dimensions");
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.
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.)
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.
341 * @param x x offset (in pixels) of the region in the destination image into
342 * which the source image should be decompressed/decoded
344 * @param y y offset (in pixels) of the region in the destination image into
345 * which the source image should be decompressed/decoded
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.
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>.
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.
380 * @param pixelFormat pixel format of the decompressed/decoded image (one of
381 * {@link TJ#PF_RGB TJ.PF_*})
383 * @param flags the bitwise OR of one or more of
384 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
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,
402 decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, pitch,
403 desiredHeight, pixelFormat, flags);
405 decompress(jpegBuf, jpegBufSize, dstBuf, desiredWidth, pitch,
406 desiredHeight, pixelFormat, flags);
412 * {@link #decompress(byte[], int, int, int, int, int, int, int)} instead.
414 @SuppressWarnings("checkstyle:JavadocMethod")
416 public void decompress(byte[] dstBuf, int desiredWidth, int pitch,
417 int desiredHeight, int pixelFormat, int flags)
419 decompress(dstBuf, 0, 0, desiredWidth, pitch, desiredHeight, pixelFormat,
424 * Decompress the JPEG source image associated with this decompressor
425 * instance and return a buffer containing the decompressed image.
427 * @param desiredWidth see
428 * {@link #decompress(byte[], int, int, int, int, int, int, int)}
432 * {@link #decompress(byte[], int, int, int, int, int, int, int)}
435 * @param desiredHeight see
436 * {@link #decompress(byte[], int, int, int, int, int, int, int)}
439 * @param pixelFormat pixel format of the decompressed image (one of
440 * {@link TJ#PF_RGB TJ.PF_*})
442 * @param flags the bitwise OR of one or more of
443 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
445 * @return a buffer containing the decompressed image.
447 public byte[] decompress(int desiredWidth, int pitch, int desiredHeight,
448 int pixelFormat, int flags) throws TJException {
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);
457 pitch = scaledWidth * pixelSize;
458 byte[] buf = new byte[pitch * scaledHeight];
459 decompress(buf, desiredWidth, pitch, desiredHeight, pixelFormat, flags);
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.
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.)
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
482 * @param flags the bitwise OR of one or more of
483 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
485 public void decompressToYUV(YUVImage dstImage, int flags)
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");
501 decompressToYUV(jpegBuf, jpegBufSize, dstImage.getPlanes(),
502 dstImage.getOffsets(), dstImage.getWidth(),
503 dstImage.getStrides(), dstImage.getHeight(), flags);
507 * @deprecated Use {@link #decompressToYUV(YUVImage, int)} instead.
509 @SuppressWarnings("checkstyle:JavadocMethod")
511 public void decompressToYUV(byte[] dstBuf, int flags) throws TJException {
512 YUVImage dstYUVImage = new YUVImage(dstBuf, jpegWidth, 4, jpegHeight,
514 decompressToYUV(dstYUVImage, flags);
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.
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.)
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.
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.)
550 * @param flags the bitwise OR of one or more of
551 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
553 * @return a YUV planar image.
555 public YUVImage decompressToYUV(int desiredWidth, int[] strides,
557 int flags) throws TJException {
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");
567 int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
568 int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
569 YUVImage dstYUVImage = new YUVImage(scaledWidth, null, scaledHeight,
571 decompressToYUV(dstYUVImage, flags);
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.
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.)
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
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.)
604 * @param flags the bitwise OR of one or more of
605 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
607 * @return a YUV planar image.
609 public YUVImage decompressToYUV(int desiredWidth, int pad, int desiredHeight,
610 int flags) throws TJException {
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");
620 int scaledWidth = getScaledWidth(desiredWidth, desiredHeight);
621 int scaledHeight = getScaledHeight(desiredWidth, desiredHeight);
622 YUVImage dstYUVImage = new YUVImage(scaledWidth, pad, scaledHeight,
624 decompressToYUV(dstYUVImage, flags);
629 * @deprecated Use {@link #decompressToYUV(int, int, int, int)} instead.
631 @SuppressWarnings("checkstyle:JavadocMethod")
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();
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.
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.)
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.
662 * @param x x offset (in pixels) of the region in the destination image into
663 * which the source image should be decompressed/decoded
665 * @param y y offset (in pixels) of the region in the destination image into
666 * which the source image should be decompressed/decoded
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.
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>.
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.
699 * @param pixelFormat pixel format of the decompressed image (one of
700 * {@link TJ#PF_RGB TJ.PF_*})
702 * @param flags the bitwise OR of one or more of
703 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
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,
720 decompress(jpegBuf, jpegBufSize, dstBuf, x, y, desiredWidth, stride,
721 desiredHeight, pixelFormat, flags);
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.
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.)
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.
741 * @param flags the bitwise OR of one or more of
742 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
744 public void decompress(BufferedImage dstImage, int flags)
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;
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();
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.");
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;
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;
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;
792 pixelFormat = TJ.PF_BGRA;
793 intPixels = true; break;
795 throw new IllegalArgumentException("Unsupported BufferedImage format");
797 WritableRaster wr = dstImage.getRaster();
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(),
811 throw new IllegalStateException(NO_ASSOC_ERROR);
812 decompress(jpegBuf, jpegBufSize, buf, 0, 0, scaledWidth, stride,
813 scaledHeight, pixelFormat, flags);
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,
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.
834 * @param desiredWidth see
835 * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
838 * @param desiredHeight see
839 * {@link #decompress(byte[], int, int, int, int, int, int, int)} for
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>)
846 * @param flags the bitwise OR of one or more of
847 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*}
849 * @return a <code>BufferedImage</code> instance containing the
850 * decompressed/decoded image.
852 public BufferedImage decompress(int desiredWidth, int desiredHeight,
853 int bufferedImageType, int flags)
855 if ((yuvImage == null && (desiredWidth < 0 || desiredHeight < 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,
862 decompress(img, flags);
867 * Free the native structures associated with this decompressor instance.
870 public void close() throws TJException {
875 @SuppressWarnings("checkstyle:DesignForExtension")
877 protected void finalize() throws Throwable {
880 } catch (TJException e) {
886 private native void init() throws TJException;
888 private native void destroy() throws TJException;
890 private native void decompressHeader(byte[] srcBuf, int size)
894 private native void decompress(byte[] srcBuf, int size, byte[] dstBuf,
895 int desiredWidth, int pitch, int desiredHeight, int pixelFormat, int flags)
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;
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;
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;
912 private native void decompressToYUV(byte[] srcBuf, int size, byte[] dstBuf,
913 int flags) throws TJException;
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;
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;
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;
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;