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