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