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(¶ms[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 *)¶ms[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