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