• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C)2011-2019 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 *srcPlanes[3];
330   unsigned char *jpegBuf = NULL;
331   int *srcOffsets = NULL, *srcStrides = NULL;
332   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
333 
334   GET_HANDLE();
335 
336   if (subsamp < 0 || subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
337     THROW_ARG("Invalid argument in compressFromYUV()");
338   if (org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
339     THROW_ARG("Mismatch between Java and C API");
340 
341   if ((*env)->GetArrayLength(env, srcobjs) < nc)
342     THROW_ARG("Planes array is too small for the subsampling type");
343   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
344     THROW_ARG("Offsets array is too small for the subsampling type");
345   if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
346     THROW_ARG("Strides array is too small for the subsampling type");
347 
348   jpegSize = tjBufSize(width, height, subsamp);
349   if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
350     THROW_ARG("Destination buffer is not large enough");
351 
352   if (ProcessSystemProperties(env) < 0) goto bailout;
353 
354 #define RELEASE_ARRAYS_COMPRESSFROMYUV() { \
355   SAFE_RELEASE(dst, jpegBuf); \
356   for (i = 0; i < nc; i++) \
357     SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \
358   SAFE_RELEASE(jSrcStrides, srcStrides); \
359   SAFE_RELEASE(jSrcOffsets, srcOffsets); \
360 }
361 
362   BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
363   BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
364   for (i = 0; i < nc; i++) {
365     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
366     int pw = tjPlaneWidth(i, width, subsamp);
367 
368     if (planeSize < 0 || pw < 0) {
369       RELEASE_ARRAYS_COMPRESSFROMYUV();
370       THROW_ARG(tjGetErrorStr());
371     }
372 
373     if (srcOffsets[i] < 0) {
374       RELEASE_ARRAYS_COMPRESSFROMYUV();
375       THROW_ARG("Invalid argument in compressFromYUV()");
376     }
377     if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
378       RELEASE_ARRAYS_COMPRESSFROMYUV();
379       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
380     }
381 
382     BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
383     if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
384         srcOffsets[i] + planeSize) {
385       RELEASE_ARRAYS_COMPRESSFROMYUV();
386       THROW_ARG("Source plane is not large enough");
387     }
388 
389     BAILIF0(srcPlanes[i] =
390             (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
391     srcPlanes[i] = &srcPlanes[i][srcOffsets[i]];
392   }
393   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
394 
395   if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
396                               subsamp, &jpegBuf, &jpegSize, jpegQual,
397                               flags | TJFLAG_NOREALLOC) == -1) {
398     RELEASE_ARRAYS_COMPRESSFROMYUV();
399     THROW_TJ();
400   }
401 
402 bailout:
403   RELEASE_ARRAYS_COMPRESSFROMYUV();
404   return (jint)jpegSize;
405 }
406 
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)407 static void TJCompressor_encodeYUV
408   (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
409    jint width, jint pitch, jint height, jint pf, jobjectArray dstobjs,
410    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
411 {
412   tjhandle handle = 0;
413   jsize arraySize = 0, actualPitch;
414   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
415   unsigned char *srcBuf = NULL, *dstPlanes[3];
416   int *dstOffsets = NULL, *dstStrides = NULL;
417   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
418 
419   GET_HANDLE();
420 
421   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
422       height < 1 || pitch < 0 || subsamp < 0 ||
423       subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
424     THROW_ARG("Invalid argument in encodeYUV()");
425   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
426       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
427     THROW_ARG("Mismatch between Java and C API");
428 
429   if ((*env)->GetArrayLength(env, dstobjs) < nc)
430     THROW_ARG("Planes array is too small for the subsampling type");
431   if ((*env)->GetArrayLength(env, jDstOffsets) < nc)
432     THROW_ARG("Offsets array is too small for the subsampling type");
433   if ((*env)->GetArrayLength(env, jDstStrides) < nc)
434     THROW_ARG("Strides array is too small for the subsampling type");
435 
436   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
437   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
438   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
439     THROW_ARG("Source buffer is not large enough");
440 
441 #define RELEASE_ARRAYS_ENCODEYUV() { \
442   SAFE_RELEASE(src, srcBuf); \
443   for (i = 0; i < nc; i++) \
444     SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \
445   SAFE_RELEASE(jDstStrides, dstStrides); \
446   SAFE_RELEASE(jDstOffsets, dstOffsets); \
447 }
448 
449   BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
450   BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
451   for (i = 0; i < nc; i++) {
452     int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
453     int pw = tjPlaneWidth(i, width, subsamp);
454 
455     if (planeSize < 0 || pw < 0) {
456       RELEASE_ARRAYS_ENCODEYUV();
457       THROW_ARG(tjGetErrorStr());
458     }
459 
460     if (dstOffsets[i] < 0) {
461       RELEASE_ARRAYS_ENCODEYUV();
462       THROW_ARG("Invalid argument in encodeYUV()");
463     }
464     if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
465       RELEASE_ARRAYS_ENCODEYUV();
466       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
467     }
468 
469     BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
470     if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
471         dstOffsets[i] + planeSize) {
472       RELEASE_ARRAYS_ENCODEYUV();
473       THROW_ARG("Destination plane is not large enough");
474     }
475 
476     BAILIF0(dstPlanes[i] =
477             (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
478     dstPlanes[i] = &dstPlanes[i][dstOffsets[i]];
479   }
480   BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
481 
482   if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
483                         width, pitch, height, pf, dstPlanes, dstStrides,
484                         subsamp, flags) == -1) {
485     RELEASE_ARRAYS_ENCODEYUV();
486     THROW_TJ();
487   }
488 
489 bailout:
490   RELEASE_ARRAYS_ENCODEYUV();
491 }
492 
493 /* 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)494 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III
495   (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
496    jint pitch, jint height, jint pf, jobjectArray dstobjs,
497    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
498 {
499   TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf,
500                          dstobjs, jDstOffsets, jDstStrides, subsamp, flags);
501 }
502 
503 /* 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)504 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
505   (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
506    jint stride, jint height, jint pf, jobjectArray dstobjs,
507    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
508 {
509   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
510     THROW_ARG("Invalid argument in encodeYUV()");
511   if (tjPixelSize[pf] != sizeof(jint))
512     THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
513 
514   TJCompressor_encodeYUV(env, obj, src, sizeof(jint), x, y, width,
515                          stride * sizeof(jint), height, pf, dstobjs,
516                          jDstOffsets, jDstStrides, subsamp, flags);
517 
518 bailout:
519   return;
520 }
521 
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)522 static void JNICALL TJCompressor_encodeYUV_12
523   (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width,
524    jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
525 {
526   tjhandle handle = 0;
527   jsize arraySize = 0;
528   unsigned char *srcBuf = NULL, *dstBuf = NULL;
529 
530   GET_HANDLE();
531 
532   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
533       height < 1 || pitch < 0)
534     THROW_ARG("Invalid argument in encodeYUV()");
535   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
536     THROW_ARG("Mismatch between Java and C API");
537 
538   arraySize = (pitch == 0) ? width * tjPixelSize[pf] * height : pitch * height;
539   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
540     THROW_ARG("Source buffer is not large enough");
541   if ((*env)->GetArrayLength(env, dst) <
542       (jsize)tjBufSizeYUV(width, height, subsamp))
543     THROW_ARG("Destination buffer is not large enough");
544 
545   BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
546   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
547 
548   if (tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
549                    flags) == -1) {
550     SAFE_RELEASE(dst, dstBuf);
551     SAFE_RELEASE(src, srcBuf);
552     THROW_TJ();
553   }
554 
555 bailout:
556   SAFE_RELEASE(dst, dstBuf);
557   SAFE_RELEASE(src, srcBuf);
558 }
559 
560 /* 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)561 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
562   (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
563    jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
564 {
565   TJCompressor_encodeYUV_12(env, obj, src, 1, width, pitch, height, pf, dst,
566                             subsamp, flags);
567 }
568 
569 /* 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)570 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII
571   (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
572    jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
573 {
574   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
575     THROW_ARG("Invalid argument in encodeYUV()");
576   if (tjPixelSize[pf] != sizeof(jint))
577     THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
578 
579   TJCompressor_encodeYUV_12(env, obj, src, sizeof(jint), width,
580                             stride * sizeof(jint), height, pf, dst, subsamp,
581                             flags);
582 
583 bailout:
584   return;
585 }
586 
587 /* TurboJPEG 1.2.x: TJCompressor::destroy() */
Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(JNIEnv * env,jobject obj)588 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
589   (JNIEnv *env, jobject obj)
590 {
591   tjhandle handle = 0;
592 
593   GET_HANDLE();
594 
595   if (tjDestroy(handle) == -1) THROW_TJ();
596   (*env)->SetLongField(env, obj, _fid, 0);
597 
598 bailout:
599   return;
600 }
601 
602 /* TurboJPEG 1.2.x: TJDecompressor::init() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_init(JNIEnv * env,jobject obj)603 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
604   (JNIEnv *env, jobject obj)
605 {
606   jclass cls;
607   jfieldID fid;
608   tjhandle handle;
609 
610   if ((handle = tjInitDecompress()) == NULL)
611     THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
612 
613   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
614   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
615   (*env)->SetLongField(env, obj, fid, (size_t)handle);
616 
617 bailout:
618   return;
619 }
620 
621 /* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */
Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors(JNIEnv * env,jclass cls)622 JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
623   (JNIEnv *env, jclass cls)
624 {
625   jclass sfcls = NULL;
626   jfieldID fid = 0;
627   tjscalingfactor *sf = NULL;
628   int n = 0, i;
629   jobject sfobj = NULL;
630   jobjectArray sfjava = NULL;
631 
632   if ((sf = tjGetScalingFactors(&n)) == NULL || n == 0)
633     THROW_ARG(tjGetErrorStr());
634 
635   BAILIF0(sfcls = (*env)->FindClass(env,
636     "org/libjpegturbo/turbojpeg/TJScalingFactor"));
637   BAILIF0(sfjava = (jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
638 
639   for (i = 0; i < n; i++) {
640     BAILIF0(sfobj = (*env)->AllocObject(env, sfcls));
641     BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
642     (*env)->SetIntField(env, sfobj, fid, sf[i].num);
643     BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
644     (*env)->SetIntField(env, sfobj, fid, sf[i].denom);
645     (*env)->SetObjectArrayElement(env, sfjava, i, sfobj);
646   }
647 
648 bailout:
649   return sfjava;
650 }
651 
652 /* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize)653 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader
654   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize)
655 {
656   tjhandle handle = 0;
657   unsigned char *jpegBuf = NULL;
658   int width = 0, height = 0, jpegSubsamp = -1, jpegColorspace = -1;
659 
660   GET_HANDLE();
661 
662   if ((*env)->GetArrayLength(env, src) < jpegSize)
663     THROW_ARG("Source buffer is not large enough");
664 
665   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
666 
667   if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width,
668                           &height, &jpegSubsamp, &jpegColorspace) == -1) {
669     SAFE_RELEASE(src, jpegBuf);
670     THROW_TJ();
671   }
672 
673   SAFE_RELEASE(src, jpegBuf);
674 
675   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
676   (*env)->SetIntField(env, obj, _fid, jpegSubsamp);
677   if ((_fid = (*env)->GetFieldID(env, _cls, "jpegColorspace", "I")) == 0)
678     (*env)->ExceptionClear(env);
679   else
680     (*env)->SetIntField(env, obj, _fid, jpegColorspace);
681   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
682   (*env)->SetIntField(env, obj, _fid, width);
683   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
684   (*env)->SetIntField(env, obj, _fid, height);
685 
686 bailout:
687   SAFE_RELEASE(src, jpegBuf);
688 }
689 
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)690 static void TJDecompressor_decompress
691   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst,
692    jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height,
693    jint pf, jint flags)
694 {
695   tjhandle handle = 0;
696   jsize arraySize = 0, actualPitch;
697   unsigned char *jpegBuf = NULL, *dstBuf = NULL;
698 
699   GET_HANDLE();
700 
701   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
702     THROW_ARG("Invalid argument in decompress()");
703   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
704     THROW_ARG("Mismatch between Java and C API");
705 
706   if ((*env)->GetArrayLength(env, src) < jpegSize)
707     THROW_ARG("Source buffer is not large enough");
708   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
709   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
710   if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
711     THROW_ARG("Destination buffer is not large enough");
712 
713   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
714   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
715 
716   if (tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize,
717                     &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
718                     pitch, height, pf, flags) == -1) {
719     SAFE_RELEASE(dst, dstBuf);
720     SAFE_RELEASE(src, jpegBuf);
721     THROW_TJ();
722   }
723 
724 bailout:
725   SAFE_RELEASE(dst, dstBuf);
726   SAFE_RELEASE(src, jpegBuf);
727 }
728 
729 /* 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)730 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
731   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
732    jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
733 {
734   TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width,
735                             pitch, height, pf, flags);
736 }
737 
738 /* 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)739 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
740   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
741    jint width, jint pitch, jint height, jint pf, jint flags)
742 {
743   TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width,
744                             pitch, height, pf, flags);
745 }
746 
747 /* 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)748 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII
749   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
750    jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags)
751 {
752   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
753     THROW_ARG("Invalid argument in decompress()");
754   if (tjPixelSize[pf] != sizeof(jint))
755     THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
756 
757   TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), x, y,
758                             width, stride * sizeof(jint), height, pf, flags);
759 
760 bailout:
761   return;
762 }
763 
764 /* 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)765 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
766   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
767    jint width, jint stride, jint height, jint pf, jint flags)
768 {
769   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
770     THROW_ARG("Invalid argument in decompress()");
771   if (tjPixelSize[pf] != sizeof(jint))
772     THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
773 
774   TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 0, 0,
775                             width, stride * sizeof(jint), height, pf, flags);
776 
777 bailout:
778   return;
779 }
780 
781 /* 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)782 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
783   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize,
784    jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth,
785    jintArray jDstStrides, jint desiredHeight, jint flags)
786 {
787   tjhandle handle = 0;
788   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
789   unsigned char *jpegBuf = NULL, *dstPlanes[3];
790   int *dstOffsets = NULL, *dstStrides = NULL;
791   int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
792   int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
793   tjscalingfactor *sf;
794 
795   GET_HANDLE();
796 
797   if ((*env)->GetArrayLength(env, src) < jpegSize)
798     THROW_ARG("Source buffer is not large enough");
799   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
800   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
801   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
802   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
803   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
804   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
805 
806   nc = (jpegSubsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3);
807 
808   width = desiredWidth;
809   height = desiredHeight;
810   if (width == 0) width = jpegWidth;
811   if (height == 0) height = jpegHeight;
812   sf = tjGetScalingFactors(&nsf);
813   if (!sf || nsf < 1)
814     THROW_ARG(tjGetErrorStr());
815   for (i = 0; i < nsf; i++) {
816     scaledWidth = TJSCALED(jpegWidth, sf[i]);
817     scaledHeight = TJSCALED(jpegHeight, sf[i]);
818     if (scaledWidth <= width && scaledHeight <= height)
819       break;
820   }
821   if (i >= nsf)
822     THROW_ARG("Could not scale down to desired image dimensions");
823 
824 #define RELEASE_ARRAYS_DECOMPRESSTOYUV() { \
825   SAFE_RELEASE(src, jpegBuf); \
826   for (i = 0; i < nc; i++) \
827     SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \
828   SAFE_RELEASE(jDstStrides, dstStrides); \
829   SAFE_RELEASE(jDstOffsets, dstOffsets); \
830 }
831 
832   BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
833   BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
834   for (i = 0; i < nc; i++) {
835     int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
836                                    jpegSubsamp);
837     int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp);
838 
839     if (planeSize < 0 || pw < 0) {
840       RELEASE_ARRAYS_DECOMPRESSTOYUV();
841       THROW_ARG(tjGetErrorStr());
842     }
843 
844     if (dstOffsets[i] < 0) {
845       RELEASE_ARRAYS_DECOMPRESSTOYUV();
846       THROW_ARG("Invalid argument in decompressToYUV()");
847     }
848     if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
849       RELEASE_ARRAYS_DECOMPRESSTOYUV();
850       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
851     }
852 
853     BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
854     if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
855         dstOffsets[i] + planeSize) {
856       RELEASE_ARRAYS_DECOMPRESSTOYUV();
857       THROW_ARG("Destination plane is not large enough");
858     }
859 
860     BAILIF0(dstPlanes[i] =
861             (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
862     dstPlanes[i] = &dstPlanes[i][dstOffsets[i]];
863   }
864   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
865 
866   if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
867                               dstPlanes, desiredWidth, dstStrides,
868                               desiredHeight, flags) == -1) {
869     RELEASE_ARRAYS_DECOMPRESSTOYUV();
870     THROW_TJ();
871   }
872 
873 bailout:
874   RELEASE_ARRAYS_DECOMPRESSTOYUV();
875 }
876 
877 /* 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)878 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI
879   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
880    jint flags)
881 {
882   tjhandle handle = 0;
883   unsigned char *jpegBuf = NULL, *dstBuf = NULL;
884   int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
885 
886   GET_HANDLE();
887 
888   if ((*env)->GetArrayLength(env, src) < jpegSize)
889     THROW_ARG("Source buffer is not large enough");
890   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
891   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
892   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
893   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
894   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
895   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
896   if ((*env)->GetArrayLength(env, dst) <
897       (jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp))
898     THROW_ARG("Destination buffer is not large enough");
899 
900   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
901   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
902 
903   if (tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
904                         flags) == -1) {
905     SAFE_RELEASE(dst, dstBuf);
906     SAFE_RELEASE(src, jpegBuf);
907     THROW_TJ();
908   }
909 
910 bailout:
911   SAFE_RELEASE(dst, dstBuf);
912   SAFE_RELEASE(src, jpegBuf);
913 }
914 
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)915 static void TJDecompressor_decodeYUV
916   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
917    jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize,
918    jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
919 {
920   tjhandle handle = 0;
921   jsize arraySize = 0, actualPitch;
922   jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
923   const unsigned char *srcPlanes[3];
924   unsigned char *dstBuf = NULL;
925   int *srcOffsets = NULL, *srcStrides = NULL;
926   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
927 
928   GET_HANDLE();
929 
930   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp < 0 ||
931       subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
932     THROW_ARG("Invalid argument in decodeYUV()");
933   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
934       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
935     THROW_ARG("Mismatch between Java and C API");
936 
937   if ((*env)->GetArrayLength(env, srcobjs) < nc)
938     THROW_ARG("Planes array is too small for the subsampling type");
939   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
940     THROW_ARG("Offsets array is too small for the subsampling type");
941   if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
942     THROW_ARG("Strides array is too small for the subsampling type");
943 
944   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
945   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
946   if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
947     THROW_ARG("Destination buffer is not large enough");
948 
949 #define RELEASE_ARRAYS_DECODEYUV() { \
950   SAFE_RELEASE(dst, dstBuf); \
951   for (i = 0; i < nc; i++) \
952     SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \
953   SAFE_RELEASE(jSrcStrides, srcStrides); \
954   SAFE_RELEASE(jSrcOffsets, srcOffsets); \
955 }
956 
957   BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
958   BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
959   for (i = 0; i < nc; i++) {
960     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
961     int pw = tjPlaneWidth(i, width, subsamp);
962 
963     if (planeSize < 0 || pw < 0) {
964       RELEASE_ARRAYS_DECODEYUV();
965       THROW_ARG(tjGetErrorStr());
966     }
967 
968     if (srcOffsets[i] < 0) {
969       RELEASE_ARRAYS_DECODEYUV();
970       THROW_ARG("Invalid argument in decodeYUV()");
971     }
972     if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
973       RELEASE_ARRAYS_DECODEYUV();
974       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
975     }
976 
977     BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
978     if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
979         srcOffsets[i] + planeSize) {
980       RELEASE_ARRAYS_DECODEYUV();
981       THROW_ARG("Source plane is not large enough");
982     }
983 
984     BAILIF0(srcPlanes[i] =
985             (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
986     srcPlanes[i] = &srcPlanes[i][srcOffsets[i]];
987   }
988   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
989 
990   if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
991                         &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
992                         pitch, height, pf, flags) == -1) {
993     RELEASE_ARRAYS_DECODEYUV();
994     THROW_TJ();
995   }
996 
997 bailout:
998   RELEASE_ARRAYS_DECODEYUV();
999 }
1000 
1001 /* 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)1002 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII
1003   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
1004    jintArray jSrcStrides, jint subsamp, jbyteArray dst, jint x, jint y,
1005    jint width, jint pitch, jint height, jint pf, jint flags)
1006 {
1007   TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
1008                            subsamp, dst, 1, x, y, width, pitch, height, pf,
1009                            flags);
1010 }
1011 
1012 /* 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)1013 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
1014   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
1015    jintArray jSrcStrides, jint subsamp, jintArray dst, jint x, jint y,
1016    jint width, jint stride, jint height, jint pf, jint flags)
1017 {
1018   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
1019     THROW_ARG("Invalid argument in decodeYUV()");
1020   if (tjPixelSize[pf] != sizeof(jint))
1021     THROW_ARG("Pixel format must be 32-bit when decoding to an integer buffer.");
1022 
1023   TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
1024                            subsamp, dst, sizeof(jint), x, y, width,
1025                            stride * sizeof(jint), height, pf, flags);
1026 
1027 bailout:
1028   return;
1029 }
1030 
1031 /* TurboJPEG 1.2.x: TJTransformer::init() */
Java_org_libjpegturbo_turbojpeg_TJTransformer_init(JNIEnv * env,jobject obj)1032 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
1033   (JNIEnv *env, jobject obj)
1034 {
1035   jclass cls;
1036   jfieldID fid;
1037   tjhandle handle;
1038 
1039   if ((handle = tjInitTransform()) == NULL)
1040     THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
1041 
1042   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
1043   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
1044   (*env)->SetLongField(env, obj, fid, (size_t)handle);
1045 
1046 bailout:
1047   return;
1048 }
1049 
1050 typedef struct _JNICustomFilterParams {
1051   JNIEnv *env;
1052   jobject tobj;
1053   jobject cfobj;
1054 } JNICustomFilterParams;
1055 
JNICustomFilter(short * coeffs,tjregion arrayRegion,tjregion planeRegion,int componentIndex,int transformIndex,tjtransform * transform)1056 static int JNICustomFilter(short *coeffs, tjregion arrayRegion,
1057                            tjregion planeRegion, int componentIndex,
1058                            int transformIndex, tjtransform *transform)
1059 {
1060   JNICustomFilterParams *params = (JNICustomFilterParams *)transform->data;
1061   JNIEnv *env = params->env;
1062   jobject tobj = params->tobj, cfobj = params->cfobj;
1063   jobject arrayRegionObj, planeRegionObj, bufobj, borobj;
1064   jclass cls;
1065   jmethodID mid;
1066   jfieldID fid;
1067 
1068   BAILIF0(bufobj = (*env)->NewDirectByteBuffer(env, coeffs,
1069     sizeof(short) * arrayRegion.w * arrayRegion.h));
1070   BAILIF0(cls = (*env)->FindClass(env, "java/nio/ByteOrder"));
1071   BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "nativeOrder",
1072                                           "()Ljava/nio/ByteOrder;"));
1073   BAILIF0(borobj = (*env)->CallStaticObjectMethod(env, cls, mid));
1074   BAILIF0(cls = (*env)->GetObjectClass(env, bufobj));
1075   BAILIF0(mid = (*env)->GetMethodID(env, cls, "order",
1076     "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"));
1077   (*env)->CallObjectMethod(env, bufobj, mid, borobj);
1078   BAILIF0(mid = (*env)->GetMethodID(env, cls, "asShortBuffer",
1079                                     "()Ljava/nio/ShortBuffer;"));
1080   BAILIF0(bufobj = (*env)->CallObjectMethod(env, bufobj, mid));
1081 
1082   BAILIF0(cls = (*env)->FindClass(env, "java/awt/Rectangle"));
1083   BAILIF0(arrayRegionObj = (*env)->AllocObject(env, cls));
1084   BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
1085   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.x);
1086   BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
1087   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.y);
1088   BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
1089   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.w);
1090   BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
1091   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.h);
1092 
1093   BAILIF0(planeRegionObj = (*env)->AllocObject(env, cls));
1094   BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
1095   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.x);
1096   BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
1097   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.y);
1098   BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
1099   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.w);
1100   BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
1101   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.h);
1102 
1103   BAILIF0(cls = (*env)->GetObjectClass(env, cfobj));
1104   BAILIF0(mid = (*env)->GetMethodID(env, cls, "customFilter",
1105     "(Ljava/nio/ShortBuffer;Ljava/awt/Rectangle;Ljava/awt/Rectangle;IILorg/libjpegturbo/turbojpeg/TJTransform;)V"));
1106   (*env)->CallVoidMethod(env, cfobj, mid, bufobj, arrayRegionObj,
1107                          planeRegionObj, componentIndex, transformIndex, tobj);
1108 
1109   return 0;
1110 
1111 bailout:
1112   return -1;
1113 }
1114 
1115 /* 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)1116 JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
1117   (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize,
1118    jobjectArray dstobjs, jobjectArray tobjs, jint flags)
1119 {
1120   tjhandle handle = 0;
1121   unsigned char *jpegBuf = NULL, **dstBufs = NULL;
1122   jsize n = 0;
1123   unsigned long *dstSizes = NULL;
1124   tjtransform *t = NULL;
1125   jbyteArray *jdstBufs = NULL;
1126   int i, jpegWidth = 0, jpegHeight = 0, jpegSubsamp;
1127   jintArray jdstSizes = 0;
1128   jint *dstSizesi = NULL;
1129   JNICustomFilterParams *params = NULL;
1130 
1131   GET_HANDLE();
1132 
1133   if ((*env)->GetArrayLength(env, jsrcBuf) < jpegSize)
1134     THROW_ARG("Source buffer is not large enough");
1135   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
1136   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
1137   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
1138   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
1139   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
1140   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
1141 
1142   n = (*env)->GetArrayLength(env, dstobjs);
1143   if (n != (*env)->GetArrayLength(env, tobjs))
1144     THROW_ARG("Mismatch between size of transforms array and destination buffers array");
1145 
1146   if ((dstBufs =
1147        (unsigned char **)malloc(sizeof(unsigned char *) * n)) == NULL)
1148     THROW_MEM();
1149   if ((jdstBufs = (jbyteArray *)malloc(sizeof(jbyteArray) * n)) == NULL)
1150     THROW_MEM();
1151   if ((dstSizes = (unsigned long *)malloc(sizeof(unsigned long) * n)) == NULL)
1152     THROW_MEM();
1153   if ((t = (tjtransform *)malloc(sizeof(tjtransform) * n)) == NULL)
1154     THROW_MEM();
1155   if ((params = (JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams) *
1156                                                 n)) == NULL)
1157     THROW_MEM();
1158   for (i = 0; i < n; i++) {
1159     dstBufs[i] = NULL;  jdstBufs[i] = NULL;  dstSizes[i] = 0;
1160     memset(&t[i], 0, sizeof(tjtransform));
1161     memset(&params[i], 0, sizeof(JNICustomFilterParams));
1162   }
1163 
1164   for (i = 0; i < n; i++) {
1165     jobject tobj, cfobj;
1166 
1167     BAILIF0(tobj = (*env)->GetObjectArrayElement(env, tobjs, i));
1168     BAILIF0(_cls = (*env)->GetObjectClass(env, tobj));
1169     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "op", "I"));
1170     t[i].op = (*env)->GetIntField(env, tobj, _fid);
1171     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "options", "I"));
1172     t[i].options = (*env)->GetIntField(env, tobj, _fid);
1173     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "x", "I"));
1174     t[i].r.x = (*env)->GetIntField(env, tobj, _fid);
1175     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "y", "I"));
1176     t[i].r.y = (*env)->GetIntField(env, tobj, _fid);
1177     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "width", "I"));
1178     t[i].r.w = (*env)->GetIntField(env, tobj, _fid);
1179     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "height", "I"));
1180     t[i].r.h = (*env)->GetIntField(env, tobj, _fid);
1181 
1182     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "cf",
1183       "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;"));
1184     cfobj = (*env)->GetObjectField(env, tobj, _fid);
1185     if (cfobj) {
1186       params[i].env = env;
1187       params[i].tobj = tobj;
1188       params[i].cfobj = cfobj;
1189       t[i].customFilter = JNICustomFilter;
1190       t[i].data = (void *)&params[i];
1191     }
1192   }
1193 
1194   for (i = 0; i < n; i++) {
1195     int w = jpegWidth, h = jpegHeight;
1196 
1197     if (t[i].r.w != 0) w = t[i].r.w;
1198     if (t[i].r.h != 0) h = t[i].r.h;
1199     BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
1200     if ((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) <
1201         tjBufSize(w, h, jpegSubsamp))
1202       THROW_ARG("Destination buffer is not large enough");
1203   }
1204   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
1205   for (i = 0; i < n; i++)
1206     BAILIF0(dstBufs[i] =
1207             (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
1208 
1209   if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
1210                   flags | TJFLAG_NOREALLOC) == -1) {
1211     for (i = 0; i < n; i++)
1212       SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1213     SAFE_RELEASE(jsrcBuf, jpegBuf);
1214     THROW_TJ();
1215   }
1216 
1217   for (i = 0; i < n; i++)
1218     SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1219   SAFE_RELEASE(jsrcBuf, jpegBuf);
1220 
1221   jdstSizes = (*env)->NewIntArray(env, n);
1222   BAILIF0(dstSizesi = (*env)->GetIntArrayElements(env, jdstSizes, 0));
1223   for (i = 0; i < n; i++) dstSizesi[i] = (int)dstSizes[i];
1224 
1225 bailout:
1226   if (dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0);
1227   if (dstBufs) {
1228     for (i = 0; i < n; i++) {
1229       if (dstBufs[i] && jdstBufs && jdstBufs[i])
1230         (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
1231     }
1232     free(dstBufs);
1233   }
1234   SAFE_RELEASE(jsrcBuf, jpegBuf);
1235   if (jdstBufs) free(jdstBufs);
1236   if (dstSizes) free(dstSizes);
1237   if (t) free(t);
1238   return jdstSizes;
1239 }
1240 
1241 /* TurboJPEG 1.2.x: TJDecompressor::destroy() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy(JNIEnv * env,jobject obj)1242 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
1243   (JNIEnv *env, jobject obj)
1244 {
1245   Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj);
1246 }
1247