1 /* 2 * Copyright (C)2011-2014 D. R. Commander. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * - Redistributions of source code must retain the above copyright notice, 8 * this list of conditions and the following disclaimer. 9 * - Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * - Neither the name of the libjpeg-turbo Project nor the names of its 13 * contributors may be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdlib.h> 30 #include <string.h> 31 #include "turbojpeg.h" 32 #ifdef WIN32 33 #include "tjutil.h" 34 #endif 35 #include <jni.h> 36 #include "java/org_libjpegturbo_turbojpeg_TJCompressor.h" 37 #include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h" 38 #include "java/org_libjpegturbo_turbojpeg_TJ.h" 39 40 #define PAD(v, p) ((v+(p)-1)&(~((p)-1))) 41 42 #define _throw(msg) { \ 43 jclass _exccls=(*env)->FindClass(env, "java/lang/Exception"); \ 44 if(!_exccls) goto bailout; \ 45 (*env)->ThrowNew(env, _exccls, msg); \ 46 goto bailout; \ 47 } 48 49 #define bailif0(f) {if(!(f)) { \ 50 char temps[80]; \ 51 snprintf(temps, 80, "Unexpected NULL condition in line %d", __LINE__); \ 52 _throw(temps); \ 53 }} 54 55 #define gethandle() \ 56 jclass _cls=(*env)->GetObjectClass(env, obj); \ 57 jfieldID _fid; \ 58 if(!_cls) goto bailout; \ 59 bailif0(_fid=(*env)->GetFieldID(env, _cls, "handle", "J")); \ 60 handle=(tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid); \ 61 62 #ifdef _WIN32 63 #define setenv(envvar, value, dummy) _putenv_s(envvar, value) 64 #endif 65 66 #define prop2env(property, envvar) \ 67 { \ 68 if((jName=(*env)->NewStringUTF(env, property))!=NULL \ 69 && (jValue=(*env)->CallStaticObjectMethod(env, cls, mid, jName))!=NULL) \ 70 { \ 71 if((value=(*env)->GetStringUTFChars(env, jValue, 0))!=NULL) \ 72 { \ 73 setenv(envvar, value, 1); \ 74 (*env)->ReleaseStringUTFChars(env, jValue, value); \ 75 } \ 76 } \ 77 } 78 79 int ProcessSystemProperties(JNIEnv *env) 80 { 81 jclass cls; jmethodID mid; 82 jstring jName, jValue; 83 const char *value; 84 85 bailif0(cls=(*env)->FindClass(env, "java/lang/System")); 86 bailif0(mid=(*env)->GetStaticMethodID(env, cls, "getProperty", 87 "(Ljava/lang/String;)Ljava/lang/String;")); 88 89 prop2env("turbojpeg.optimize", "TJ_OPTIMIZE"); 90 prop2env("turbojpeg.arithmetic", "TJ_ARITHMETIC"); 91 prop2env("turbojpeg.restart", "TJ_RESTART"); 92 prop2env("turbojpeg.progressive", "TJ_PROGRESSIVE"); 93 return 0; 94 95 bailout: 96 return -1; 97 } 98 99 /* TurboJPEG 1.2.x: TJ::bufSize() */ 100 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize 101 (JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp) 102 { 103 jint retval=(jint)tjBufSize(width, height, jpegSubsamp); 104 if(retval==-1) _throw(tjGetErrorStr()); 105 106 bailout: 107 return retval; 108 } 109 110 /* TurboJPEG 1.4.x: TJ::bufSizeYUV() */ 111 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII 112 (JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp) 113 { 114 jint retval=(jint)tjBufSizeYUV2(width, pad, height, subsamp); 115 if(retval==-1) _throw(tjGetErrorStr()); 116 117 bailout: 118 return retval; 119 } 120 121 /* TurboJPEG 1.2.x: TJ::bufSizeYUV() */ 122 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III 123 (JNIEnv *env, jclass cls, jint width, jint height, jint subsamp) 124 { 125 return Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII(env, cls, width, 126 4, height, subsamp); 127 } 128 129 /* TurboJPEG 1.4.x: TJ::planeSizeYUV() */ 130 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII 131 (JNIEnv *env, jclass cls, jint componentID, jint width, jint stride, 132 jint height, jint subsamp) 133 { 134 jint retval=(jint)tjPlaneSizeYUV(componentID, width, stride, height, 135 subsamp); 136 if(retval==-1) _throw(tjGetErrorStr()); 137 138 bailout: 139 return retval; 140 } 141 142 /* TurboJPEG 1.4.x: TJ::planeWidth() */ 143 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III 144 (JNIEnv *env, jclass cls, jint componentID, jint width, jint subsamp) 145 { 146 jint retval=(jint)tjPlaneWidth(componentID, width, subsamp); 147 if(retval==-1) _throw(tjGetErrorStr()); 148 149 bailout: 150 return retval; 151 } 152 153 /* TurboJPEG 1.4.x: TJ::planeHeight() */ 154 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III 155 (JNIEnv *env, jclass cls, jint componentID, jint height, jint subsamp) 156 { 157 jint retval=(jint)tjPlaneHeight(componentID, height, subsamp); 158 if(retval==-1) _throw(tjGetErrorStr()); 159 160 bailout: 161 return retval; 162 } 163 164 /* TurboJPEG 1.2.x: TJCompressor::init() */ 165 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init 166 (JNIEnv *env, jobject obj) 167 { 168 jclass cls; 169 jfieldID fid; 170 tjhandle handle; 171 172 if((handle=tjInitCompress())==NULL) 173 _throw(tjGetErrorStr()); 174 175 bailif0(cls=(*env)->GetObjectClass(env, obj)); 176 bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J")); 177 (*env)->SetLongField(env, obj, fid, (size_t)handle); 178 179 bailout: 180 return; 181 } 182 183 static jint TJCompressor_compress 184 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y, 185 jint width, jint pitch, jint height, jint pf, jbyteArray dst, 186 jint jpegSubsamp, jint jpegQual, jint flags) 187 { 188 tjhandle handle=0; 189 unsigned long jpegSize=0; 190 jsize arraySize=0, actualPitch; 191 unsigned char *srcBuf=NULL, *jpegBuf=NULL; 192 193 gethandle(); 194 195 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 196 || pitch<0) 197 _throw("Invalid argument in compress()"); 198 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) 199 _throw("Mismatch between Java and C API"); 200 201 actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; 202 arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; 203 if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize) 204 _throw("Source buffer is not large enough"); 205 jpegSize=tjBufSize(width, height, jpegSubsamp); 206 if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize) 207 _throw("Destination buffer is not large enough"); 208 209 bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 210 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 211 212 if(ProcessSystemProperties(env)<0) goto bailout; 213 214 if(tjCompress2(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]], width, 215 pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp, jpegQual, 216 flags|TJFLAG_NOREALLOC)==-1) 217 _throw(tjGetErrorStr()); 218 219 bailout: 220 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); 221 if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); 222 return (jint)jpegSize; 223 } 224 225 /* TurboJPEG 1.3.x: TJCompressor::compress() byte source */ 226 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII 227 (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width, 228 jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp, 229 jint jpegQual, jint flags) 230 { 231 return TJCompressor_compress(env, obj, src, 1, x, y, width, pitch, height, 232 pf, dst, jpegSubsamp, jpegQual, flags); 233 } 234 235 /* TurboJPEG 1.2.x: TJCompressor::compress() byte source */ 236 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII 237 (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch, 238 jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, 239 jint flags) 240 { 241 return TJCompressor_compress(env, obj, src, 1, 0, 0, width, pitch, height, 242 pf, dst, jpegSubsamp, jpegQual, flags); 243 } 244 245 /* TurboJPEG 1.3.x: TJCompressor::compress() int source */ 246 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII 247 (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width, 248 jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp, 249 jint jpegQual, jint flags) 250 { 251 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 252 _throw("Invalid argument in compress()"); 253 if(tjPixelSize[pf]!=sizeof(jint)) 254 _throw("Pixel format must be 32-bit when compressing from an integer buffer."); 255 256 return TJCompressor_compress(env, obj, src, sizeof(jint), x, y, width, 257 stride*sizeof(jint), height, pf, dst, jpegSubsamp, jpegQual, flags); 258 259 bailout: 260 return 0; 261 } 262 263 /* TurboJPEG 1.2.x: TJCompressor::compress() int source */ 264 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII 265 (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride, 266 jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, 267 jint flags) 268 { 269 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 270 _throw("Invalid argument in compress()"); 271 if(tjPixelSize[pf]!=sizeof(jint)) 272 _throw("Pixel format must be 32-bit when compressing from an integer buffer."); 273 274 return TJCompressor_compress(env, obj, src, sizeof(jint), 0, 0, width, 275 stride*sizeof(jint), height, pf, dst, jpegSubsamp, jpegQual, flags); 276 277 bailout: 278 return 0; 279 } 280 281 /* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */ 282 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII 283 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, 284 jint width, jintArray jSrcStrides, jint height, jint subsamp, 285 jbyteArray dst, jint jpegQual, jint flags) 286 { 287 tjhandle handle=0; 288 unsigned long jpegSize=0; 289 jbyteArray jSrcPlanes[3]={NULL, NULL, NULL}; 290 unsigned char *srcPlanes[3], *jpegBuf=NULL; 291 int *srcOffsets=NULL, *srcStrides=NULL; 292 int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i; 293 294 gethandle(); 295 296 if(subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP) 297 _throw("Invalid argument in compressFromYUV()"); 298 if(org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP) 299 _throw("Mismatch between Java and C API"); 300 301 if((*env)->GetArrayLength(env, srcobjs)<nc) 302 _throw("Planes array is too small for the subsampling type"); 303 if((*env)->GetArrayLength(env, jSrcOffsets)<nc) 304 _throw("Offsets array is too small for the subsampling type"); 305 if((*env)->GetArrayLength(env, jSrcStrides)<nc) 306 _throw("Strides array is too small for the subsampling type"); 307 308 jpegSize=tjBufSize(width, height, subsamp); 309 if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize) 310 _throw("Destination buffer is not large enough"); 311 312 bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); 313 bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); 314 for(i=0; i<nc; i++) 315 { 316 int planeSize=tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); 317 int pw=tjPlaneWidth(i, width, subsamp); 318 319 if(planeSize<0 || pw<0) 320 _throw(tjGetErrorStr()); 321 322 if(srcOffsets[i]<0) 323 _throw("Invalid argument in compressFromYUV()"); 324 if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0) 325 _throw("Negative plane stride would cause memory to be accessed below plane boundary"); 326 327 bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i)); 328 if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize) 329 _throw("Source plane is not large enough"); 330 331 bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 332 0)); 333 srcPlanes[i]=&srcPlanes[i][srcOffsets[i]]; 334 } 335 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 336 337 if(ProcessSystemProperties(env)<0) goto bailout; 338 339 if(tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height, 340 subsamp, &jpegBuf, &jpegSize, jpegQual, flags|TJFLAG_NOREALLOC)==-1) 341 _throw(tjGetErrorStr()); 342 343 bailout: 344 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); 345 for(i=0; i<nc; i++) 346 { 347 if(srcPlanes[i] && jSrcPlanes[i]) 348 (*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i], 349 0); 350 } 351 if(srcStrides) 352 (*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0); 353 if(srcOffsets) 354 (*env)->ReleasePrimitiveArrayCritical(env, jSrcOffsets, srcOffsets, 0); 355 return (jint)jpegSize; 356 } 357 358 static void TJCompressor_encodeYUV 359 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y, 360 jint width, jint pitch, jint height, jint pf, jobjectArray dstobjs, 361 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags) 362 { 363 tjhandle handle=0; 364 jsize arraySize=0, actualPitch; 365 jbyteArray jDstPlanes[3]={NULL, NULL, NULL}; 366 unsigned char *srcBuf=NULL, *dstPlanes[3]; 367 int *dstOffsets=NULL, *dstStrides=NULL; 368 int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i; 369 370 gethandle(); 371 372 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 373 || pitch<0 || subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP) 374 _throw("Invalid argument in encodeYUV()"); 375 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF 376 || org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP) 377 _throw("Mismatch between Java and C API"); 378 379 if((*env)->GetArrayLength(env, dstobjs)<nc) 380 _throw("Planes array is too small for the subsampling type"); 381 if((*env)->GetArrayLength(env, jDstOffsets)<nc) 382 _throw("Offsets array is too small for the subsampling type"); 383 if((*env)->GetArrayLength(env, jDstStrides)<nc) 384 _throw("Strides array is too small for the subsampling type"); 385 386 actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; 387 arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; 388 if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize) 389 _throw("Source buffer is not large enough"); 390 391 bailif0(dstOffsets=(*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0)); 392 bailif0(dstStrides=(*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0)); 393 for(i=0; i<nc; i++) 394 { 395 int planeSize=tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp); 396 int pw=tjPlaneWidth(i, width, subsamp); 397 398 if(planeSize<0 || pw<0) 399 _throw(tjGetErrorStr()); 400 401 if(dstOffsets[i]<0) 402 _throw("Invalid argument in encodeYUV()"); 403 if(dstStrides[i]<0 && dstOffsets[i]-planeSize+pw<0) 404 _throw("Negative plane stride would cause memory to be accessed below plane boundary"); 405 406 bailif0(jDstPlanes[i]=(*env)->GetObjectArrayElement(env, dstobjs, i)); 407 if((*env)->GetArrayLength(env, jDstPlanes[i])<dstOffsets[i]+planeSize) 408 _throw("Destination plane is not large enough"); 409 410 bailif0(dstPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 411 0)); 412 dstPlanes[i]=&dstPlanes[i][dstOffsets[i]]; 413 } 414 bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 415 416 if(tjEncodeYUVPlanes(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]], 417 width, pitch, height, pf, dstPlanes, dstStrides, subsamp, flags)==-1) 418 _throw(tjGetErrorStr()); 419 420 bailout: 421 if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); 422 for(i=0; i<nc; i++) 423 { 424 if(dstPlanes[i] && jDstPlanes[i]) 425 (*env)->ReleasePrimitiveArrayCritical(env, jDstPlanes[i], dstPlanes[i], 426 0); 427 } 428 if(dstStrides) 429 (*env)->ReleasePrimitiveArrayCritical(env, jDstStrides, dstStrides, 0); 430 if(dstOffsets) 431 (*env)->ReleasePrimitiveArrayCritical(env, jDstOffsets, dstOffsets, 0); 432 return; 433 } 434 435 /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */ 436 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III 437 (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width, 438 jint pitch, jint height, jint pf, jobjectArray dstobjs, 439 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags) 440 { 441 TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf, 442 dstobjs, jDstOffsets, jDstStrides, subsamp, flags); 443 } 444 445 /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */ 446 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III 447 (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width, 448 jint stride, jint height, jint pf, jobjectArray dstobjs, 449 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags) 450 { 451 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 452 _throw("Invalid argument in encodeYUV()"); 453 if(tjPixelSize[pf]!=sizeof(jint)) 454 _throw("Pixel format must be 32-bit when encoding from an integer buffer."); 455 456 TJCompressor_encodeYUV(env, obj, src, sizeof(jint), x, y, width, 457 stride*sizeof(jint), height, pf, dstobjs, jDstOffsets, jDstStrides, 458 subsamp, flags); 459 460 bailout: 461 return; 462 } 463 464 JNIEXPORT void JNICALL TJCompressor_encodeYUV_12 465 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width, 466 jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags) 467 { 468 tjhandle handle=0; 469 jsize arraySize=0; 470 unsigned char *srcBuf=NULL, *dstBuf=NULL; 471 472 gethandle(); 473 474 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 475 || pitch<0) 476 _throw("Invalid argument in encodeYUV()"); 477 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) 478 _throw("Mismatch between Java and C API"); 479 480 arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height; 481 if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize) 482 _throw("Source buffer is not large enough"); 483 if((*env)->GetArrayLength(env, dst) 484 <(jsize)tjBufSizeYUV(width, height, subsamp)) 485 _throw("Destination buffer is not large enough"); 486 487 bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 488 bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 489 490 if(tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp, 491 flags)==-1) 492 _throw(tjGetErrorStr()); 493 494 bailout: 495 if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); 496 if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); 497 return; 498 } 499 500 /* TurboJPEG 1.2.x: TJCompressor::encodeYUV() byte source */ 501 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII 502 (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch, 503 jint height, jint pf, jbyteArray dst, jint subsamp, jint flags) 504 { 505 TJCompressor_encodeYUV_12(env, obj, src, 1, width, pitch, height, pf, dst, 506 subsamp, flags); 507 } 508 509 /* TurboJPEG 1.2.x: TJCompressor::encodeYUV() int source */ 510 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII 511 (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride, 512 jint height, jint pf, jbyteArray dst, jint subsamp, jint flags) 513 { 514 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 515 _throw("Invalid argument in encodeYUV()"); 516 if(tjPixelSize[pf]!=sizeof(jint)) 517 _throw("Pixel format must be 32-bit when encoding from an integer buffer."); 518 519 TJCompressor_encodeYUV_12(env, obj, src, sizeof(jint), width, 520 stride*sizeof(jint), height, pf, dst, subsamp, flags); 521 522 bailout: 523 return; 524 } 525 526 /* TurboJPEG 1.2.x: TJCompressor::destroy() */ 527 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy 528 (JNIEnv *env, jobject obj) 529 { 530 tjhandle handle=0; 531 532 gethandle(); 533 534 if(tjDestroy(handle)==-1) _throw(tjGetErrorStr()); 535 (*env)->SetLongField(env, obj, _fid, 0); 536 537 bailout: 538 return; 539 } 540 541 /* TurboJPEG 1.2.x: TJDecompressor::init() */ 542 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init 543 (JNIEnv *env, jobject obj) 544 { 545 jclass cls; 546 jfieldID fid; 547 tjhandle handle; 548 549 if((handle=tjInitDecompress())==NULL) _throw(tjGetErrorStr()); 550 551 bailif0(cls=(*env)->GetObjectClass(env, obj)); 552 bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J")); 553 (*env)->SetLongField(env, obj, fid, (size_t)handle); 554 555 bailout: 556 return; 557 } 558 559 /* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */ 560 JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors 561 (JNIEnv *env, jclass cls) 562 { 563 jclass sfcls=NULL; jfieldID fid=0; 564 tjscalingfactor *sf=NULL; int n=0, i; 565 jobject sfobj=NULL; 566 jobjectArray sfjava=NULL; 567 568 if((sf=tjGetScalingFactors(&n))==NULL || n==0) 569 _throw(tjGetErrorStr()); 570 571 bailif0(sfcls=(*env)->FindClass(env, "org/libjpegturbo/turbojpeg/TJScalingFactor")); 572 bailif0(sfjava=(jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0)); 573 574 for(i=0; i<n; i++) 575 { 576 bailif0(sfobj=(*env)->AllocObject(env, sfcls)); 577 bailif0(fid=(*env)->GetFieldID(env, sfcls, "num", "I")); 578 (*env)->SetIntField(env, sfobj, fid, sf[i].num); 579 bailif0(fid=(*env)->GetFieldID(env, sfcls, "denom", "I")); 580 (*env)->SetIntField(env, sfobj, fid, sf[i].denom); 581 (*env)->SetObjectArrayElement(env, sfjava, i, sfobj); 582 } 583 584 bailout: 585 return sfjava; 586 } 587 588 /* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */ 589 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader 590 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize) 591 { 592 tjhandle handle=0; 593 unsigned char *jpegBuf=NULL; 594 int width=0, height=0, jpegSubsamp=-1, jpegColorspace=-1; 595 596 gethandle(); 597 598 if((*env)->GetArrayLength(env, src)<jpegSize) 599 _throw("Source buffer is not large enough"); 600 601 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 602 603 if(tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, 604 &width, &height, &jpegSubsamp, &jpegColorspace)==-1) 605 _throw(tjGetErrorStr()); 606 607 (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); jpegBuf=NULL; 608 609 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); 610 (*env)->SetIntField(env, obj, _fid, jpegSubsamp); 611 if((_fid=(*env)->GetFieldID(env, _cls, "jpegColorspace", "I"))==0) 612 (*env)->ExceptionClear(env); 613 else 614 (*env)->SetIntField(env, obj, _fid, jpegColorspace); 615 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); 616 (*env)->SetIntField(env, obj, _fid, width); 617 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); 618 (*env)->SetIntField(env, obj, _fid, height); 619 620 bailout: 621 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); 622 return; 623 } 624 625 static void TJDecompressor_decompress 626 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst, 627 jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height, 628 jint pf, jint flags) 629 { 630 tjhandle handle=0; 631 jsize arraySize=0, actualPitch; 632 unsigned char *jpegBuf=NULL, *dstBuf=NULL; 633 634 gethandle(); 635 636 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 637 _throw("Invalid argument in decompress()"); 638 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) 639 _throw("Mismatch between Java and C API"); 640 641 if((*env)->GetArrayLength(env, src)<jpegSize) 642 _throw("Source buffer is not large enough"); 643 actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; 644 arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; 645 if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize) 646 _throw("Destination buffer is not large enough"); 647 648 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 649 bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 650 651 if(tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize, 652 &dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf, 653 flags)==-1) 654 _throw(tjGetErrorStr()); 655 656 bailout: 657 if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); 658 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); 659 return; 660 } 661 662 /* TurboJPEG 1.3.x: TJDecompressor::decompress() byte destination */ 663 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII 664 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst, 665 jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags) 666 { 667 TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width, 668 pitch, height, pf, flags); 669 } 670 671 /* TurboJPEG 1.2.x: TJDecompressor::decompress() byte destination */ 672 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII 673 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst, 674 jint width, jint pitch, jint height, jint pf, jint flags) 675 { 676 TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width, 677 pitch, height, pf, flags); 678 } 679 680 /* TurboJPEG 1.3.x: TJDecompressor::decompress() int destination */ 681 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII 682 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst, 683 jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags) 684 { 685 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 686 _throw("Invalid argument in decompress()"); 687 if(tjPixelSize[pf]!=sizeof(jint)) 688 _throw("Pixel format must be 32-bit when decompressing to an integer buffer."); 689 690 TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), x, y, 691 width, stride*sizeof(jint), height, pf, flags); 692 693 bailout: 694 return; 695 } 696 697 /* TurboJPEG 1.2.x: TJDecompressor::decompress() int destination */ 698 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII 699 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst, 700 jint width, jint stride, jint height, jint pf, jint flags) 701 { 702 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 703 _throw("Invalid argument in decompress()"); 704 if(tjPixelSize[pf]!=sizeof(jint)) 705 _throw("Pixel format must be 32-bit when decompressing to an integer buffer."); 706 707 TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 0, 0, 708 width, stride*sizeof(jint), height, pf, flags); 709 710 bailout: 711 return; 712 713 } 714 715 /* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */ 716 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III 717 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, 718 jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth, 719 jintArray jDstStrides, jint desiredHeight, jint flags) 720 { 721 tjhandle handle=0; 722 jbyteArray jDstPlanes[3]={NULL, NULL, NULL}; 723 unsigned char *jpegBuf=NULL, *dstPlanes[3]; 724 int *dstOffsets=NULL, *dstStrides=NULL; 725 int jpegSubsamp=-1, jpegWidth=0, jpegHeight=0; 726 int nc=0, i, width, height, scaledWidth, scaledHeight, nsf=0; 727 tjscalingfactor *sf; 728 729 730 gethandle(); 731 732 if((*env)->GetArrayLength(env, src)<jpegSize) 733 _throw("Source buffer is not large enough"); 734 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); 735 jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); 736 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); 737 jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); 738 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); 739 jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); 740 741 nc=(jpegSubsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3); 742 743 width=desiredWidth; height=desiredHeight; 744 if(width==0) width=jpegWidth; 745 if(height==0) height=jpegHeight; 746 sf=tjGetScalingFactors(&nsf); 747 if(!sf || nsf<1) 748 _throw(tjGetErrorStr()); 749 for(i=0; i<nsf; i++) 750 { 751 scaledWidth=TJSCALED(jpegWidth, sf[i]); 752 scaledHeight=TJSCALED(jpegHeight, sf[i]); 753 if(scaledWidth<=width && scaledHeight<=height) 754 break; 755 } 756 757 bailif0(dstOffsets=(*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0)); 758 bailif0(dstStrides=(*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0)); 759 for(i=0; i<nc; i++) 760 { 761 int planeSize=tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight, 762 jpegSubsamp); 763 int pw=tjPlaneWidth(i, scaledWidth, jpegSubsamp); 764 765 if(planeSize<0 || pw<0) 766 _throw(tjGetErrorStr()); 767 768 if(dstOffsets[i]<0) 769 _throw("Invalid argument in decompressToYUV()"); 770 if(dstStrides[i]<0 && dstOffsets[i]-planeSize+pw<0) 771 _throw("Negative plane stride would cause memory to be accessed below plane boundary"); 772 773 bailif0(jDstPlanes[i]=(*env)->GetObjectArrayElement(env, dstobjs, i)); 774 if((*env)->GetArrayLength(env, jDstPlanes[i])<dstOffsets[i]+planeSize) 775 _throw("Destination plane is not large enough"); 776 777 bailif0(dstPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 778 0)); 779 dstPlanes[i]=&dstPlanes[i][dstOffsets[i]]; 780 } 781 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 782 783 if(tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize, 784 dstPlanes, desiredWidth, dstStrides, desiredHeight, flags)==-1) 785 _throw(tjGetErrorStr()); 786 787 bailout: 788 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); 789 for(i=0; i<nc; i++) 790 { 791 if(dstPlanes[i] && jDstPlanes[i]) 792 (*env)->ReleasePrimitiveArrayCritical(env, jDstPlanes[i], dstPlanes[i], 793 0); 794 } 795 if(dstStrides) 796 (*env)->ReleasePrimitiveArrayCritical(env, jDstStrides, dstStrides, 0); 797 if(dstOffsets) 798 (*env)->ReleasePrimitiveArrayCritical(env, jDstOffsets, dstOffsets, 0); 799 return; 800 } 801 802 /* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */ 803 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI 804 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst, 805 jint flags) 806 { 807 tjhandle handle=0; 808 unsigned char *jpegBuf=NULL, *dstBuf=NULL; 809 int jpegSubsamp=-1, jpegWidth=0, jpegHeight=0; 810 811 gethandle(); 812 813 if((*env)->GetArrayLength(env, src)<jpegSize) 814 _throw("Source buffer is not large enough"); 815 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); 816 jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); 817 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); 818 jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); 819 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); 820 jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); 821 if((*env)->GetArrayLength(env, dst) 822 <(jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)) 823 _throw("Destination buffer is not large enough"); 824 825 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); 826 bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 827 828 if(tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf, 829 flags)==-1) 830 _throw(tjGetErrorStr()); 831 832 bailout: 833 if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); 834 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); 835 return; 836 } 837 838 static void TJDecompressor_decodeYUV 839 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, 840 jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize, 841 jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags) 842 { 843 tjhandle handle=0; 844 jsize arraySize=0, actualPitch; 845 jbyteArray jSrcPlanes[3]={NULL, NULL, NULL}; 846 unsigned char *srcPlanes[3], *dstBuf=NULL; 847 int *srcOffsets=NULL, *srcStrides=NULL; 848 int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i; 849 850 gethandle(); 851 852 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp<0 853 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP) 854 _throw("Invalid argument in decodeYUV()"); 855 if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF 856 || org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP) 857 _throw("Mismatch between Java and C API"); 858 859 if((*env)->GetArrayLength(env, srcobjs)<nc) 860 _throw("Planes array is too small for the subsampling type"); 861 if((*env)->GetArrayLength(env, jSrcOffsets)<nc) 862 _throw("Offsets array is too small for the subsampling type"); 863 if((*env)->GetArrayLength(env, jSrcStrides)<nc) 864 _throw("Strides array is too small for the subsampling type"); 865 866 actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; 867 arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; 868 if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize) 869 _throw("Destination buffer is not large enough"); 870 871 bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); 872 bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); 873 for(i=0; i<nc; i++) 874 { 875 int planeSize=tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); 876 int pw=tjPlaneWidth(i, width, subsamp); 877 878 if(planeSize<0 || pw<0) 879 _throw(tjGetErrorStr()); 880 881 if(srcOffsets[i]<0) 882 _throw("Invalid argument in decodeYUV()"); 883 if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0) 884 _throw("Negative plane stride would cause memory to be accessed below plane boundary"); 885 886 bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i)); 887 if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize) 888 _throw("Source plane is not large enough"); 889 890 bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 891 0)); 892 srcPlanes[i]=&srcPlanes[i][srcOffsets[i]]; 893 } 894 bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); 895 896 if(tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp, 897 &dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf, 898 flags)==-1) 899 _throw(tjGetErrorStr()); 900 901 bailout: 902 if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); 903 for(i=0; i<nc; i++) 904 { 905 if(srcPlanes[i] && jSrcPlanes[i]) 906 (*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i], 907 0); 908 } 909 if(srcStrides) 910 (*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0); 911 if(srcOffsets) 912 (*env)->ReleasePrimitiveArrayCritical(env, jSrcOffsets, srcOffsets, 0); 913 return; 914 } 915 916 /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */ 917 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII 918 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, 919 jintArray jSrcStrides, jint subsamp, jbyteArray dst, jint x, jint y, 920 jint width, jint pitch, jint height, jint pf, jint flags) 921 { 922 TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides, 923 subsamp, dst, 1, x, y, width, pitch, height, pf, flags); 924 } 925 926 /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() int destination */ 927 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII 928 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, 929 jintArray jSrcStrides, jint subsamp, jintArray dst, jint x, jint y, 930 jint width, jint stride, jint height, jint pf, jint flags) 931 { 932 if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) 933 _throw("Invalid argument in decodeYUV()"); 934 if(tjPixelSize[pf]!=sizeof(jint)) 935 _throw("Pixel format must be 32-bit when decoding to an integer buffer."); 936 937 TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides, 938 subsamp, dst, sizeof(jint), x, y, width, stride*sizeof(jint), height, pf, 939 flags); 940 941 bailout: 942 return; 943 } 944 945 /* TurboJPEG 1.2.x: TJTransformer::init() */ 946 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init 947 (JNIEnv *env, jobject obj) 948 { 949 jclass cls; 950 jfieldID fid; 951 tjhandle handle; 952 953 if((handle=tjInitTransform())==NULL) _throw(tjGetErrorStr()); 954 955 bailif0(cls=(*env)->GetObjectClass(env, obj)); 956 bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J")); 957 (*env)->SetLongField(env, obj, fid, (size_t)handle); 958 959 bailout: 960 return; 961 } 962 963 typedef struct _JNICustomFilterParams 964 { 965 JNIEnv *env; 966 jobject tobj; 967 jobject cfobj; 968 } JNICustomFilterParams; 969 970 static int JNICustomFilter(short *coeffs, tjregion arrayRegion, 971 tjregion planeRegion, int componentIndex, int transformIndex, 972 tjtransform *transform) 973 { 974 JNICustomFilterParams *params=(JNICustomFilterParams *)transform->data; 975 JNIEnv *env=params->env; 976 jobject tobj=params->tobj, cfobj=params->cfobj; 977 jobject arrayRegionObj, planeRegionObj, bufobj, borobj; 978 jclass cls; jmethodID mid; jfieldID fid; 979 980 bailif0(bufobj=(*env)->NewDirectByteBuffer(env, coeffs, 981 sizeof(short)*arrayRegion.w*arrayRegion.h)); 982 bailif0(cls=(*env)->FindClass(env, "java/nio/ByteOrder")); 983 bailif0(mid=(*env)->GetStaticMethodID(env, cls, "nativeOrder", 984 "()Ljava/nio/ByteOrder;")); 985 bailif0(borobj=(*env)->CallStaticObjectMethod(env, cls, mid)); 986 bailif0(cls=(*env)->GetObjectClass(env, bufobj)); 987 bailif0(mid=(*env)->GetMethodID(env, cls, "order", 988 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;")); 989 (*env)->CallObjectMethod(env, bufobj, mid, borobj); 990 bailif0(mid=(*env)->GetMethodID(env, cls, "asShortBuffer", 991 "()Ljava/nio/ShortBuffer;")); 992 bailif0(bufobj=(*env)->CallObjectMethod(env, bufobj, mid)); 993 994 bailif0(cls=(*env)->FindClass(env, "java/awt/Rectangle")); 995 bailif0(arrayRegionObj=(*env)->AllocObject(env, cls)); 996 bailif0(fid=(*env)->GetFieldID(env, cls, "x", "I")); 997 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.x); 998 bailif0(fid=(*env)->GetFieldID(env, cls, "y", "I")); 999 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.y); 1000 bailif0(fid=(*env)->GetFieldID(env, cls, "width", "I")); 1001 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.w); 1002 bailif0(fid=(*env)->GetFieldID(env, cls, "height", "I")); 1003 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.h); 1004 1005 bailif0(planeRegionObj=(*env)->AllocObject(env, cls)); 1006 bailif0(fid=(*env)->GetFieldID(env, cls, "x", "I")); 1007 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.x); 1008 bailif0(fid=(*env)->GetFieldID(env, cls, "y", "I")); 1009 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.y); 1010 bailif0(fid=(*env)->GetFieldID(env, cls, "width", "I")); 1011 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.w); 1012 bailif0(fid=(*env)->GetFieldID(env, cls, "height", "I")); 1013 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.h); 1014 1015 bailif0(cls=(*env)->GetObjectClass(env, cfobj)); 1016 bailif0(mid=(*env)->GetMethodID(env, cls, "customFilter", 1017 "(Ljava/nio/ShortBuffer;Ljava/awt/Rectangle;Ljava/awt/Rectangle;IILorg/libjpegturbo/turbojpeg/TJTransform;)V")); 1018 (*env)->CallVoidMethod(env, cfobj, mid, bufobj, arrayRegionObj, 1019 planeRegionObj, componentIndex, transformIndex, tobj); 1020 1021 return 0; 1022 1023 bailout: 1024 return -1; 1025 } 1026 1027 /* TurboJPEG 1.2.x: TJTransformer::transform() */ 1028 JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform 1029 (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize, 1030 jobjectArray dstobjs, jobjectArray tobjs, jint flags) 1031 { 1032 tjhandle handle=0; int i; 1033 unsigned char *jpegBuf=NULL, **dstBufs=NULL; jsize n=0; 1034 unsigned long *dstSizes=NULL; tjtransform *t=NULL; 1035 jbyteArray *jdstBufs=NULL; 1036 int jpegWidth=0, jpegHeight=0, jpegSubsamp; 1037 jintArray jdstSizes=0; jint *dstSizesi=NULL; 1038 JNICustomFilterParams *params=NULL; 1039 1040 gethandle(); 1041 1042 if((*env)->GetArrayLength(env, jsrcBuf)<jpegSize) 1043 _throw("Source buffer is not large enough"); 1044 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); 1045 jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); 1046 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); 1047 jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); 1048 bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); 1049 jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); 1050 1051 n=(*env)->GetArrayLength(env, dstobjs); 1052 if(n!=(*env)->GetArrayLength(env, tobjs)) 1053 _throw("Mismatch between size of transforms array and destination buffers array"); 1054 1055 if((dstBufs=(unsigned char **)malloc(sizeof(unsigned char *)*n))==NULL) 1056 _throw("Memory allocation failure"); 1057 if((jdstBufs=(jbyteArray *)malloc(sizeof(jbyteArray)*n))==NULL) 1058 _throw("Memory allocation failure"); 1059 if((dstSizes=(unsigned long *)malloc(sizeof(unsigned long)*n))==NULL) 1060 _throw("Memory allocation failure"); 1061 if((t=(tjtransform *)malloc(sizeof(tjtransform)*n))==NULL) 1062 _throw("Memory allocation failure"); 1063 if((params=(JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams)*n)) 1064 ==NULL) 1065 _throw("Memory allocation failure"); 1066 for(i=0; i<n; i++) 1067 { 1068 dstBufs[i]=NULL; jdstBufs[i]=NULL; dstSizes[i]=0; 1069 memset(&t[i], 0, sizeof(tjtransform)); 1070 memset(¶ms[i], 0, sizeof(JNICustomFilterParams)); 1071 } 1072 1073 for(i=0; i<n; i++) 1074 { 1075 jobject tobj, cfobj; 1076 1077 bailif0(tobj=(*env)->GetObjectArrayElement(env, tobjs, i)); 1078 bailif0(_cls=(*env)->GetObjectClass(env, tobj)); 1079 bailif0(_fid=(*env)->GetFieldID(env, _cls, "op", "I")); 1080 t[i].op=(*env)->GetIntField(env, tobj, _fid); 1081 bailif0(_fid=(*env)->GetFieldID(env, _cls, "options", "I")); 1082 t[i].options=(*env)->GetIntField(env, tobj, _fid); 1083 bailif0(_fid=(*env)->GetFieldID(env, _cls, "x", "I")); 1084 t[i].r.x=(*env)->GetIntField(env, tobj, _fid); 1085 bailif0(_fid=(*env)->GetFieldID(env, _cls, "y", "I")); 1086 t[i].r.y=(*env)->GetIntField(env, tobj, _fid); 1087 bailif0(_fid=(*env)->GetFieldID(env, _cls, "width", "I")); 1088 t[i].r.w=(*env)->GetIntField(env, tobj, _fid); 1089 bailif0(_fid=(*env)->GetFieldID(env, _cls, "height", "I")); 1090 t[i].r.h=(*env)->GetIntField(env, tobj, _fid); 1091 1092 bailif0(_fid=(*env)->GetFieldID(env, _cls, "cf", 1093 "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;")); 1094 cfobj=(*env)->GetObjectField(env, tobj, _fid); 1095 if(cfobj) 1096 { 1097 params[i].env=env; 1098 params[i].tobj=tobj; 1099 params[i].cfobj=cfobj; 1100 t[i].customFilter=JNICustomFilter; 1101 t[i].data=(void *)¶ms[i]; 1102 } 1103 } 1104 1105 for(i=0; i<n; i++) 1106 { 1107 int w=jpegWidth, h=jpegHeight; 1108 if(t[i].r.w!=0) w=t[i].r.w; 1109 if(t[i].r.h!=0) h=t[i].r.h; 1110 bailif0(jdstBufs[i]=(*env)->GetObjectArrayElement(env, dstobjs, i)); 1111 if((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) 1112 <tjBufSize(w, h, jpegSubsamp)) 1113 _throw("Destination buffer is not large enough"); 1114 } 1115 bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0)); 1116 for(i=0; i<n; i++) 1117 bailif0(dstBufs[i]=(*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0)); 1118 1119 if(tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t, 1120 flags|TJFLAG_NOREALLOC)==-1) 1121 _throw(tjGetErrorStr()); 1122 1123 for(i=0; i<n; i++) 1124 { 1125 (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0); 1126 dstBufs[i]=NULL; 1127 } 1128 (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0); 1129 jpegBuf=NULL; 1130 1131 jdstSizes=(*env)->NewIntArray(env, n); 1132 bailif0(dstSizesi=(*env)->GetIntArrayElements(env, jdstSizes, 0)); 1133 for(i=0; i<n; i++) dstSizesi[i]=(int)dstSizes[i]; 1134 1135 bailout: 1136 if(dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0); 1137 if(dstBufs) 1138 { 1139 for(i=0; i<n; i++) 1140 { 1141 if(dstBufs[i] && jdstBufs && jdstBufs[i]) 1142 (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0); 1143 } 1144 free(dstBufs); 1145 } 1146 if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0); 1147 if(jdstBufs) free(jdstBufs); 1148 if(dstSizes) free(dstSizes); 1149 if(t) free(t); 1150 return jdstSizes; 1151 } 1152 1153 /* TurboJPEG 1.2.x: TJDecompressor::destroy() */ 1154 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy 1155 (JNIEnv *env, jobject obj) 1156 { 1157 Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj); 1158 } 1159