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