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 compressor 38 */ 39 public class TJCompressor implements Closeable { 40 41 private static final String NO_ASSOC_ERROR = 42 "No source image is associated with this instance"; 43 44 /** 45 * Create a TurboJPEG compressor instance. 46 */ TJCompressor()47 public TJCompressor() throws TJException { 48 init(); 49 } 50 51 /** 52 * Create a TurboJPEG compressor instance and associate the uncompressed 53 * source image stored in <code>srcImage</code> with the newly created 54 * instance. 55 * 56 * @param srcImage see {@link #setSourceImage} for description 57 * 58 * @param x see {@link #setSourceImage} for description 59 * 60 * @param y see {@link #setSourceImage} for description 61 * 62 * @param width see {@link #setSourceImage} for description 63 * 64 * @param pitch see {@link #setSourceImage} for description 65 * 66 * @param height see {@link #setSourceImage} for description 67 * 68 * @param pixelFormat pixel format of the source image (one of 69 * {@link TJ#PF_RGB TJ.PF_*}) 70 */ TJCompressor(byte[] srcImage, int x, int y, int width, int pitch, int height, int pixelFormat)71 public TJCompressor(byte[] srcImage, int x, int y, int width, int pitch, 72 int height, int pixelFormat) throws TJException { 73 setSourceImage(srcImage, x, y, width, pitch, height, pixelFormat); 74 } 75 76 /** 77 * @deprecated Use 78 * {@link #TJCompressor(byte[], int, int, int, int, int, int)} instead. 79 */ 80 @Deprecated TJCompressor(byte[] srcImage, int width, int pitch, int height, int pixelFormat)81 public TJCompressor(byte[] srcImage, int width, int pitch, int height, 82 int pixelFormat) throws TJException { 83 setSourceImage(srcImage, width, pitch, height, pixelFormat); 84 } 85 86 /** 87 * Create a TurboJPEG compressor instance and associate the uncompressed 88 * source image stored in <code>srcImage</code> with the newly created 89 * instance. 90 * 91 * @param srcImage see 92 * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description 93 * 94 * @param x see 95 * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description 96 * 97 * @param y see 98 * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description 99 * 100 * @param width see 101 * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description 102 * 103 * @param height see 104 * {@link #setSourceImage(BufferedImage, int, int, int, int)} for description 105 */ TJCompressor(BufferedImage srcImage, int x, int y, int width, int height)106 public TJCompressor(BufferedImage srcImage, int x, int y, int width, 107 int height) throws TJException { 108 setSourceImage(srcImage, x, y, width, height); 109 } 110 111 /** 112 * Associate an uncompressed RGB, grayscale, or CMYK source image with this 113 * compressor instance. 114 * 115 * @param srcImage image buffer containing RGB, grayscale, or CMYK pixels to 116 * be compressed or encoded. This buffer is not modified. 117 * 118 * @param x x offset (in pixels) of the region in the source image from which 119 * the JPEG or YUV image should be compressed/encoded 120 * 121 * @param y y offset (in pixels) of the region in the source image from which 122 * the JPEG or YUV image should be compressed/encoded 123 * 124 * @param width width (in pixels) of the region in the source image from 125 * which the JPEG or YUV image should be compressed/encoded 126 * 127 * @param pitch bytes per line of the source image. Normally, this should be 128 * <code>width * TJ.pixelSize(pixelFormat)</code> if the source image is 129 * unpadded, but you can use this parameter to, for instance, specify that 130 * the scanlines in the source image are padded to a 4-byte boundary or to 131 * compress/encode a JPEG or YUV image from a region of a larger source 132 * image. You can also be clever and use this parameter to skip lines, etc. 133 * Setting this parameter to 0 is the equivalent of setting it to 134 * <code>width * TJ.pixelSize(pixelFormat)</code>. 135 * 136 * @param height height (in pixels) of the region in the source image from 137 * which the JPEG or YUV image should be compressed/encoded 138 * 139 * @param pixelFormat pixel format of the source image (one of 140 * {@link TJ#PF_RGB TJ.PF_*}) 141 */ setSourceImage(byte[] srcImage, int x, int y, int width, int pitch, int height, int pixelFormat)142 public void setSourceImage(byte[] srcImage, int x, int y, int width, 143 int pitch, int height, int pixelFormat) 144 throws TJException { 145 if (handle == 0) init(); 146 if (srcImage == null || x < 0 || y < 0 || width < 1 || height < 1 || 147 pitch < 0 || pixelFormat < 0 || pixelFormat >= TJ.NUMPF) 148 throw new IllegalArgumentException("Invalid argument in setSourceImage()"); 149 srcBuf = srcImage; 150 srcWidth = width; 151 if (pitch == 0) 152 srcPitch = width * TJ.getPixelSize(pixelFormat); 153 else 154 srcPitch = pitch; 155 srcHeight = height; 156 srcPixelFormat = pixelFormat; 157 srcX = x; 158 srcY = y; 159 srcBufInt = null; 160 srcYUVImage = null; 161 } 162 163 /** 164 * @deprecated Use 165 * {@link #setSourceImage(byte[], int, int, int, int, int, int)} instead. 166 */ 167 @Deprecated setSourceImage(byte[] srcImage, int width, int pitch, int height, int pixelFormat)168 public void setSourceImage(byte[] srcImage, int width, int pitch, 169 int height, int pixelFormat) throws TJException { 170 setSourceImage(srcImage, 0, 0, width, pitch, height, pixelFormat); 171 srcX = srcY = -1; 172 } 173 174 /** 175 * Associate an uncompressed RGB or grayscale source image with this 176 * compressor instance. 177 * 178 * @param srcImage a <code>BufferedImage</code> instance containing RGB or 179 * grayscale pixels to be compressed or encoded. This image is not modified. 180 * 181 * @param x x offset (in pixels) of the region in the source image from which 182 * the JPEG or YUV image should be compressed/encoded 183 * 184 * @param y y offset (in pixels) of the region in the source image from which 185 * the JPEG or YUV image should be compressed/encoded 186 * 187 * @param width width (in pixels) of the region in the source image from 188 * which the JPEG or YUV image should be compressed/encoded (0 = use the 189 * width of the source image) 190 * 191 * @param height height (in pixels) of the region in the source image from 192 * which the JPEG or YUV image should be compressed/encoded (0 = use the 193 * height of the source image) 194 */ setSourceImage(BufferedImage srcImage, int x, int y, int width, int height)195 public void setSourceImage(BufferedImage srcImage, int x, int y, int width, 196 int height) throws TJException { 197 if (handle == 0) init(); 198 if (srcImage == null || x < 0 || y < 0 || width < 0 || height < 0) 199 throw new IllegalArgumentException("Invalid argument in setSourceImage()"); 200 srcX = x; 201 srcY = y; 202 srcWidth = (width == 0) ? srcImage.getWidth(): width; 203 srcHeight = (height == 0) ? srcImage.getHeight() : height; 204 if (x + width > srcImage.getWidth() || y + height > srcImage.getHeight()) 205 throw new IllegalArgumentException("Compression region exceeds the bounds of the source image"); 206 207 int pixelFormat; 208 boolean intPixels = false; 209 if (byteOrder == null) 210 byteOrder = ByteOrder.nativeOrder(); 211 switch(srcImage.getType()) { 212 case BufferedImage.TYPE_3BYTE_BGR: 213 pixelFormat = TJ.PF_BGR; break; 214 case BufferedImage.TYPE_4BYTE_ABGR: 215 case BufferedImage.TYPE_4BYTE_ABGR_PRE: 216 pixelFormat = TJ.PF_XBGR; break; 217 case BufferedImage.TYPE_BYTE_GRAY: 218 pixelFormat = TJ.PF_GRAY; break; 219 case BufferedImage.TYPE_INT_BGR: 220 if (byteOrder == ByteOrder.BIG_ENDIAN) 221 pixelFormat = TJ.PF_XBGR; 222 else 223 pixelFormat = TJ.PF_RGBX; 224 intPixels = true; break; 225 case BufferedImage.TYPE_INT_RGB: 226 case BufferedImage.TYPE_INT_ARGB: 227 case BufferedImage.TYPE_INT_ARGB_PRE: 228 if (byteOrder == ByteOrder.BIG_ENDIAN) 229 pixelFormat = TJ.PF_XRGB; 230 else 231 pixelFormat = TJ.PF_BGRX; 232 intPixels = true; break; 233 default: 234 throw new IllegalArgumentException("Unsupported BufferedImage format"); 235 } 236 srcPixelFormat = pixelFormat; 237 238 WritableRaster wr = srcImage.getRaster(); 239 if (intPixels) { 240 SinglePixelPackedSampleModel sm = 241 (SinglePixelPackedSampleModel)srcImage.getSampleModel(); 242 srcStride = sm.getScanlineStride(); 243 DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); 244 srcBufInt = db.getData(); 245 srcBuf = null; 246 } else { 247 ComponentSampleModel sm = 248 (ComponentSampleModel)srcImage.getSampleModel(); 249 int pixelSize = sm.getPixelStride(); 250 if (pixelSize != TJ.getPixelSize(pixelFormat)) 251 throw new IllegalArgumentException("Inconsistency between pixel format and pixel size in BufferedImage"); 252 srcPitch = sm.getScanlineStride(); 253 DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); 254 srcBuf = db.getData(); 255 srcBufInt = null; 256 } 257 srcYUVImage = null; 258 } 259 260 /** 261 * Associate an uncompressed YUV planar source image with this compressor 262 * instance. 263 * 264 * @param srcImage YUV planar image to be compressed. This image is not 265 * modified. 266 */ setSourceImage(YUVImage srcImage)267 public void setSourceImage(YUVImage srcImage) throws TJException { 268 if (handle == 0) init(); 269 if (srcImage == null) 270 throw new IllegalArgumentException("Invalid argument in setSourceImage()"); 271 srcYUVImage = srcImage; 272 srcBuf = null; 273 srcBufInt = null; 274 } 275 276 /** 277 * Set the level of chrominance subsampling for subsequent compress/encode 278 * operations. When pixels are converted from RGB to YCbCr (see 279 * {@link TJ#CS_YCbCr}) or from CMYK to YCCK (see {@link TJ#CS_YCCK}) as part 280 * of the JPEG compression process, some of the Cb and Cr (chrominance) 281 * components can be discarded or averaged together to produce a smaller 282 * image with little perceptible loss of image clarity (the human eye is more 283 * sensitive to small changes in brightness than to small changes in color.) 284 * This is called "chrominance subsampling". 285 * <p> 286 * NOTE: This method has no effect when compressing a JPEG image from a YUV 287 * planar source. In that case, the level of chrominance subsampling in 288 * the JPEG image is determined by the source. Further, this method has no 289 * effect when encoding to a pre-allocated {@link YUVImage} instance. In 290 * that case, the level of chrominance subsampling is determined by the 291 * destination. 292 * 293 * @param newSubsamp the level of chrominance subsampling to use in 294 * subsequent compress/encode oeprations (one of 295 * {@link TJ#SAMP_444 TJ.SAMP_*}) 296 */ setSubsamp(int newSubsamp)297 public void setSubsamp(int newSubsamp) { 298 if (newSubsamp < 0 || newSubsamp >= TJ.NUMSAMP) 299 throw new IllegalArgumentException("Invalid argument in setSubsamp()"); 300 subsamp = newSubsamp; 301 } 302 303 /** 304 * Set the JPEG image quality level for subsequent compress operations. 305 * 306 * @param quality the new JPEG image quality level (1 to 100, 1 = worst, 307 * 100 = best) 308 */ setJPEGQuality(int quality)309 public void setJPEGQuality(int quality) { 310 if (quality < 1 || quality > 100) 311 throw new IllegalArgumentException("Invalid argument in setJPEGQuality()"); 312 jpegQuality = quality; 313 } 314 315 /** 316 * Compress the uncompressed source image associated with this compressor 317 * instance and output a JPEG image to the given destination buffer. 318 * 319 * @param dstBuf buffer that will receive the JPEG image. Use 320 * {@link TJ#bufSize} to determine the maximum size for this buffer based on 321 * the source image's width and height and the desired level of chrominance 322 * subsampling. 323 * 324 * @param flags the bitwise OR of one or more of 325 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} 326 */ compress(byte[] dstBuf, int flags)327 public void compress(byte[] dstBuf, int flags) throws TJException { 328 if (dstBuf == null || flags < 0) 329 throw new IllegalArgumentException("Invalid argument in compress()"); 330 if (srcBuf == null && srcBufInt == null && srcYUVImage == null) 331 throw new IllegalStateException(NO_ASSOC_ERROR); 332 if (jpegQuality < 0) 333 throw new IllegalStateException("JPEG Quality not set"); 334 if (subsamp < 0 && srcYUVImage == null) 335 throw new IllegalStateException("Subsampling level not set"); 336 337 if (srcYUVImage != null) 338 compressedSize = compressFromYUV(srcYUVImage.getPlanes(), 339 srcYUVImage.getOffsets(), 340 srcYUVImage.getWidth(), 341 srcYUVImage.getStrides(), 342 srcYUVImage.getHeight(), 343 srcYUVImage.getSubsamp(), 344 dstBuf, jpegQuality, flags); 345 else if (srcBuf != null) { 346 if (srcX >= 0 && srcY >= 0) 347 compressedSize = compress(srcBuf, srcX, srcY, srcWidth, srcPitch, 348 srcHeight, srcPixelFormat, dstBuf, subsamp, 349 jpegQuality, flags); 350 else 351 compressedSize = compress(srcBuf, srcWidth, srcPitch, srcHeight, 352 srcPixelFormat, dstBuf, subsamp, jpegQuality, 353 flags); 354 } else if (srcBufInt != null) { 355 if (srcX >= 0 && srcY >= 0) 356 compressedSize = compress(srcBufInt, srcX, srcY, srcWidth, srcStride, 357 srcHeight, srcPixelFormat, dstBuf, subsamp, 358 jpegQuality, flags); 359 else 360 compressedSize = compress(srcBufInt, srcWidth, srcStride, srcHeight, 361 srcPixelFormat, dstBuf, subsamp, jpegQuality, 362 flags); 363 } 364 } 365 366 /** 367 * Compress the uncompressed source image associated with this compressor 368 * instance and return a buffer containing a JPEG image. 369 * 370 * @param flags the bitwise OR of one or more of 371 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} 372 * 373 * @return a buffer containing a JPEG image. The length of this buffer will 374 * not be equal to the size of the JPEG image. Use {@link 375 * #getCompressedSize} to obtain the size of the JPEG image. 376 */ compress(int flags)377 public byte[] compress(int flags) throws TJException { 378 checkSourceImage(); 379 byte[] buf = new byte[TJ.bufSize(srcWidth, srcHeight, subsamp)]; 380 compress(buf, flags); 381 return buf; 382 } 383 384 /** 385 * @deprecated Use 386 * {@link #setSourceImage(BufferedImage, int, int, int, int)} and 387 * {@link #compress(byte[], int)} instead. 388 */ 389 @Deprecated compress(BufferedImage srcImage, byte[] dstBuf, int flags)390 public void compress(BufferedImage srcImage, byte[] dstBuf, int flags) 391 throws TJException { 392 setSourceImage(srcImage, 0, 0, 0, 0); 393 compress(dstBuf, flags); 394 } 395 396 /** 397 * @deprecated Use 398 * {@link #setSourceImage(BufferedImage, int, int, int, int)} and 399 * {@link #compress(int)} instead. 400 */ 401 @Deprecated compress(BufferedImage srcImage, int flags)402 public byte[] compress(BufferedImage srcImage, int flags) 403 throws TJException { 404 setSourceImage(srcImage, 0, 0, 0, 0); 405 return compress(flags); 406 } 407 408 /** 409 * Encode the uncompressed source image associated with this compressor 410 * instance into a YUV planar image and store it in the given 411 * <code>YUVImage</code> instance. This method uses the accelerated color 412 * conversion routines in TurboJPEG's underlying codec but does not execute 413 * any of the other steps in the JPEG compression process. Encoding 414 * CMYK source images to YUV is not supported. 415 * 416 * @param dstImage {@link YUVImage} instance that will receive the YUV planar 417 * image 418 * 419 * @param flags the bitwise OR of one or more of 420 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} 421 */ encodeYUV(YUVImage dstImage, int flags)422 public void encodeYUV(YUVImage dstImage, int flags) throws TJException { 423 if (dstImage == null || flags < 0) 424 throw new IllegalArgumentException("Invalid argument in encodeYUV()"); 425 if (srcBuf == null && srcBufInt == null) 426 throw new IllegalStateException(NO_ASSOC_ERROR); 427 if (srcYUVImage != null) 428 throw new IllegalStateException("Source image is not correct type"); 429 checkSubsampling(); 430 if (srcWidth != dstImage.getWidth() || srcHeight != dstImage.getHeight()) 431 throw new IllegalStateException("Destination image is the wrong size"); 432 433 if (srcBufInt != null) { 434 encodeYUV(srcBufInt, srcX, srcY, srcWidth, srcStride, srcHeight, 435 srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(), 436 dstImage.getStrides(), dstImage.getSubsamp(), flags); 437 } else { 438 encodeYUV(srcBuf, srcX, srcY, srcWidth, srcPitch, srcHeight, 439 srcPixelFormat, dstImage.getPlanes(), dstImage.getOffsets(), 440 dstImage.getStrides(), dstImage.getSubsamp(), flags); 441 } 442 compressedSize = 0; 443 } 444 445 /** 446 * @deprecated Use {@link #encodeYUV(YUVImage, int)} instead. 447 */ 448 @Deprecated encodeYUV(byte[] dstBuf, int flags)449 public void encodeYUV(byte[] dstBuf, int flags) throws TJException { 450 if(dstBuf == null) 451 throw new IllegalArgumentException("Invalid argument in encodeYUV()"); 452 checkSourceImage(); 453 checkSubsampling(); 454 YUVImage yuvImage = new YUVImage(dstBuf, srcWidth, 4, srcHeight, subsamp); 455 encodeYUV(yuvImage, flags); 456 } 457 458 /** 459 * Encode the uncompressed source image associated with this compressor 460 * instance into a unified YUV planar image buffer and return a 461 * <code>YUVImage</code> instance containing the encoded image. This method 462 * uses the accelerated color conversion routines in TurboJPEG's underlying 463 * codec but does not execute any of the other steps in the JPEG compression 464 * process. Encoding CMYK source images to YUV is not supported. 465 * 466 * @param pad the width of each line in each plane of the YUV image will be 467 * padded to the nearest multiple of this number of bytes (must be a power of 468 * 2.) 469 * 470 * @param flags the bitwise OR of one or more of 471 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} 472 * 473 * @return a YUV planar image. 474 */ encodeYUV(int pad, int flags)475 public YUVImage encodeYUV(int pad, int flags) throws TJException { 476 checkSourceImage(); 477 checkSubsampling(); 478 if(pad < 1 || ((pad & (pad - 1)) != 0)) 479 throw new IllegalStateException("Invalid argument in encodeYUV()"); 480 YUVImage yuvImage = new YUVImage(srcWidth, pad, srcHeight, subsamp); 481 encodeYUV(yuvImage, flags); 482 return yuvImage; 483 } 484 485 /** 486 * Encode the uncompressed source image associated with this compressor 487 * instance into separate Y, U (Cb), and V (Cr) image planes and return a 488 * <code>YUVImage</code> instance containing the encoded image planes. This 489 * method uses the accelerated color conversion routines in TurboJPEG's 490 * underlying codec but does not execute any of the other steps in the JPEG 491 * compression process. Encoding CMYK source images to YUV is not supported. 492 * 493 * @param strides an array of integers, each specifying the number of bytes 494 * per line in the corresponding plane of the output image. Setting the 495 * stride for any plane to 0 is the same as setting it to the component width 496 * of the plane. If <code>strides</code> is null, then the strides for all 497 * planes will be set to their respective component widths. You can adjust 498 * the strides in order to add an arbitrary amount of line padding to each 499 * plane. 500 * 501 * @param flags the bitwise OR of one or more of 502 * {@link TJ#FLAG_BOTTOMUP TJ.FLAG_*} 503 * 504 * @return a YUV planar image. 505 */ encodeYUV(int[] strides, int flags)506 public YUVImage encodeYUV(int[] strides, int flags) throws TJException { 507 checkSourceImage(); 508 checkSubsampling(); 509 YUVImage yuvImage = new YUVImage(srcWidth, strides, srcHeight, subsamp); 510 encodeYUV(yuvImage, flags); 511 return yuvImage; 512 } 513 514 /** 515 * @deprecated Use {@link #encodeYUV(int, int)} instead. 516 */ 517 @Deprecated encodeYUV(int flags)518 public byte[] encodeYUV(int flags) throws TJException { 519 checkSourceImage(); 520 checkSubsampling(); 521 YUVImage yuvImage = new YUVImage(srcWidth, 4, srcHeight, subsamp); 522 encodeYUV(yuvImage, flags); 523 return yuvImage.getBuf(); 524 } 525 526 /** 527 * @deprecated Use 528 * {@link #setSourceImage(BufferedImage, int, int, int, int)} and 529 * {@link #encodeYUV(byte[], int)} instead. 530 */ 531 @Deprecated encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags)532 public void encodeYUV(BufferedImage srcImage, byte[] dstBuf, int flags) 533 throws TJException { 534 setSourceImage(srcImage, 0, 0, 0, 0); 535 encodeYUV(dstBuf, flags); 536 } 537 538 /** 539 * @deprecated Use 540 * {@link #setSourceImage(BufferedImage, int, int, int, int)} and 541 * {@link #encodeYUV(int, int)} instead. 542 */ 543 @Deprecated encodeYUV(BufferedImage srcImage, int flags)544 public byte[] encodeYUV(BufferedImage srcImage, int flags) 545 throws TJException { 546 setSourceImage(srcImage, 0, 0, 0, 0); 547 return encodeYUV(flags); 548 } 549 550 /** 551 * Returns the size of the image (in bytes) generated by the most recent 552 * compress operation. 553 * 554 * @return the size of the image (in bytes) generated by the most recent 555 * compress operation. 556 */ getCompressedSize()557 public int getCompressedSize() { 558 return compressedSize; 559 } 560 561 /** 562 * Free the native structures associated with this compressor instance. 563 */ 564 @Override close()565 public void close() throws TJException { 566 if (handle != 0) 567 destroy(); 568 } 569 570 @Override finalize()571 protected void finalize() throws Throwable { 572 try { 573 close(); 574 } catch(TJException e) { 575 } finally { 576 super.finalize(); 577 } 578 }; 579 init()580 private native void init() throws TJException; 581 destroy()582 private native void destroy() throws TJException; 583 584 // JPEG size in bytes is returned 585 @Deprecated compress(byte[] srcBuf, int width, int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, int flags)586 private native int compress(byte[] srcBuf, int width, int pitch, 587 int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, 588 int flags) throws TJException; 589 compress(byte[] srcBuf, int x, int y, int width, int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, int flags)590 private native int compress(byte[] srcBuf, int x, int y, int width, 591 int pitch, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, 592 int jpegQual, int flags) throws TJException; 593 594 @Deprecated compress(int[] srcBuf, int width, int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, int flags)595 private native int compress(int[] srcBuf, int width, int stride, 596 int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, 597 int flags) throws TJException; 598 compress(int[] srcBuf, int x, int y, int width, int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, int jpegQual, int flags)599 private native int compress(int[] srcBuf, int x, int y, int width, 600 int stride, int height, int pixelFormat, byte[] dstBuf, int jpegSubsamp, 601 int jpegQual, int flags) throws TJException; 602 compressFromYUV(byte[][] srcPlanes, int[] srcOffsets, int width, int[] srcStrides, int height, int subsamp, byte[] dstBuf, int jpegQual, int flags)603 private native int compressFromYUV(byte[][] srcPlanes, int[] srcOffsets, 604 int width, int[] srcStrides, int height, int subsamp, byte[] dstBuf, 605 int jpegQual, int flags) 606 throws TJException; 607 608 @Deprecated encodeYUV(byte[] srcBuf, int width, int pitch, int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)609 private native void encodeYUV(byte[] srcBuf, int width, int pitch, 610 int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags) 611 throws TJException; 612 encodeYUV(byte[] srcBuf, int x, int y, int width, int pitch, int height, int pixelFormat, byte[][] dstPlanes, int[] dstOffsets, int[] dstStrides, int subsamp, int flags)613 private native void encodeYUV(byte[] srcBuf, int x, int y, int width, 614 int pitch, int height, int pixelFormat, byte[][] dstPlanes, 615 int[] dstOffsets, int[] dstStrides, int subsamp, int flags) 616 throws TJException; 617 618 @Deprecated encodeYUV(int[] srcBuf, int width, int stride, int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags)619 private native void encodeYUV(int[] srcBuf, int width, int stride, 620 int height, int pixelFormat, byte[] dstBuf, int subsamp, int flags) 621 throws TJException; 622 encodeYUV(int[] srcBuf, int x, int y, int width, int srcStride, int height, int pixelFormat, byte[][] dstPlanes, int[] dstOffsets, int[] dstStrides, int subsamp, int flags)623 private native void encodeYUV(int[] srcBuf, int x, int y, int width, 624 int srcStride, int height, int pixelFormat, byte[][] dstPlanes, 625 int[] dstOffsets, int[] dstStrides, int subsamp, int flags) 626 throws TJException; 627 628 static { TJLoader.load()629 TJLoader.load(); 630 } 631 checkSourceImage()632 private void checkSourceImage() { 633 if (srcWidth < 1 || srcHeight < 1) 634 throw new IllegalStateException(NO_ASSOC_ERROR); 635 } 636 checkSubsampling()637 private void checkSubsampling() { 638 if (subsamp < 0) 639 throw new IllegalStateException("Subsampling level not set"); 640 } 641 642 private long handle = 0; 643 private byte[] srcBuf = null; 644 private int[] srcBufInt = null; 645 private int srcWidth = 0; 646 private int srcHeight = 0; 647 private int srcX = -1; 648 private int srcY = -1; 649 private int srcPitch = 0; 650 private int srcStride = 0; 651 private int srcPixelFormat = -1; 652 private YUVImage srcYUVImage = null; 653 private int subsamp = -1; 654 private int jpegQuality = -1; 655 private int compressedSize = 0; 656 private int yuvPad = 4; 657 private ByteOrder byteOrder = null; 658 } 659