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