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