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