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