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