blob: 070dd90060834ae0ef01202631ed7d7351532ef7 [file] [log] [blame]
DRCf8e00552011-02-04 11:06:36 +00001/*
DRC5ea77d82018-10-26 08:55:22 -05002 * Copyright (C)2011-2018 D. R. Commander. All Rights Reserved.
DRCf8e00552011-02-04 11:06:36 +00003 *
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
DRCe8573012011-03-04 10:13:59 +000029#include <stdlib.h>
30#include <string.h>
DRCf8e00552011-02-04 11:06:36 +000031#include "turbojpeg.h"
DRCbc2e66c2012-10-02 06:47:37 +000032#ifdef WIN32
33#include "tjutil.h"
34#endif
DRCf8e00552011-02-04 11:06:36 +000035#include <jni.h>
DRCc5a41992011-02-08 06:54:36 +000036#include "java/org_libjpegturbo_turbojpeg_TJCompressor.h"
37#include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h"
38#include "java/org_libjpegturbo_turbojpeg_TJ.h"
DRCf8e00552011-02-04 11:06:36 +000039
DRC293263c2018-03-17 15:14:35 -050040#define PAD(v, p) ((v + (p) - 1) & (~((p) - 1)))
DRC40dd3142014-08-17 12:23:49 +000041
DRCbce58f42019-04-12 07:49:35 -050042#define BAILIF0(f) { \
DRC19c791c2018-03-08 10:55:20 -060043 if (!(f) || (*env)->ExceptionCheck(env)) { \
44 goto bailout; \
45 } \
DRCf8e00552011-02-04 11:06:36 +000046}
47
DRCbce58f42019-04-12 07:49:35 -050048#define THROW(msg, exceptionClass) { \
DRC19c791c2018-03-08 10:55:20 -060049 jclass _exccls = (*env)->FindClass(env, exceptionClass); \
50 \
DRCbce58f42019-04-12 07:49:35 -050051 BAILIF0(_exccls); \
DRC19c791c2018-03-08 10:55:20 -060052 (*env)->ThrowNew(env, _exccls, msg); \
53 goto bailout; \
54}
55
DRCbce58f42019-04-12 07:49:35 -050056#define THROW_TJ() { \
DRC19c791c2018-03-08 10:55:20 -060057 jclass _exccls; \
58 jmethodID _excid; \
59 jobject _excobj; \
60 jstring _errstr; \
61 \
DRCbce58f42019-04-12 07:49:35 -050062 BAILIF0(_errstr = (*env)->NewStringUTF(env, tjGetErrorStr2(handle))); \
63 BAILIF0(_exccls = (*env)->FindClass(env, \
DRC19c791c2018-03-08 10:55:20 -060064 "org/libjpegturbo/turbojpeg/TJException")); \
DRCbce58f42019-04-12 07:49:35 -050065 BAILIF0(_excid = (*env)->GetMethodID(env, _exccls, "<init>", \
DRC19c791c2018-03-08 10:55:20 -060066 "(Ljava/lang/String;I)V")); \
DRCbce58f42019-04-12 07:49:35 -050067 BAILIF0(_excobj = (*env)->NewObject(env, _exccls, _excid, _errstr, \
DRC19c791c2018-03-08 10:55:20 -060068 tjGetErrorCode(handle))); \
69 (*env)->Throw(env, _excobj); \
70 goto bailout; \
DRCd4092f62017-06-27 10:54:21 -050071}
DRCb3817da2015-07-14 20:42:52 +000072
DRCbce58f42019-04-12 07:49:35 -050073#define THROW_ARG(msg) THROW(msg, "java/lang/IllegalArgumentException")
DRCb3817da2015-07-14 20:42:52 +000074
DRCbce58f42019-04-12 07:49:35 -050075#define THROW_MEM() \
76 THROW("Memory allocation failure", "java/lang/OutOfMemoryError");
DRCb3817da2015-07-14 20:42:52 +000077
DRCbce58f42019-04-12 07:49:35 -050078#define GET_HANDLE() \
DRC19c791c2018-03-08 10:55:20 -060079 jclass _cls = (*env)->GetObjectClass(env, obj); \
80 jfieldID _fid; \
81 \
DRCbce58f42019-04-12 07:49:35 -050082 BAILIF0(_cls); \
83 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "handle", "J")); \
DRC19c791c2018-03-08 10:55:20 -060084 handle = (tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid);
DRCf8e00552011-02-04 11:06:36 +000085
DRCbdb36e12014-08-22 15:39:32 +000086#ifdef _WIN32
DRC293263c2018-03-17 15:14:35 -050087#define setenv(envvar, value, dummy) _putenv_s(envvar, value)
DRCbdb36e12014-08-22 15:39:32 +000088#endif
89
DRCbce58f42019-04-12 07:49:35 -050090#define PROP2ENV(property, envvar) { \
DRC19c791c2018-03-08 10:55:20 -060091 if ((jName = (*env)->NewStringUTF(env, property)) != NULL && \
92 (jValue = (*env)->CallStaticObjectMethod(env, cls, mid, \
93 jName)) != NULL) { \
94 if ((value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \
95 setenv(envvar, value, 1); \
96 (*env)->ReleaseStringUTFChars(env, jValue, value); \
97 } \
98 } \
DRC0713c1b2014-08-22 13:43:33 +000099}
100
DRC33011752019-04-12 08:47:28 -0500101#define SAFE_RELEASE(javaArray, cArray) { \
102 if (javaArray && cArray) \
103 (*env)->ReleasePrimitiveArrayCritical(env, javaArray, (void *)cArray, 0); \
104 cArray = NULL; \
105}
106
DRC0713c1b2014-08-22 13:43:33 +0000107int ProcessSystemProperties(JNIEnv *env)
108{
DRC19c791c2018-03-08 10:55:20 -0600109 jclass cls;
110 jmethodID mid;
111 jstring jName, jValue;
112 const char *value;
DRC0713c1b2014-08-22 13:43:33 +0000113
DRCbce58f42019-04-12 07:49:35 -0500114 BAILIF0(cls = (*env)->FindClass(env, "java/lang/System"));
115 BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "getProperty",
DRC19c791c2018-03-08 10:55:20 -0600116 "(Ljava/lang/String;)Ljava/lang/String;"));
DRC0713c1b2014-08-22 13:43:33 +0000117
DRCbce58f42019-04-12 07:49:35 -0500118 PROP2ENV("turbojpeg.optimize", "TJ_OPTIMIZE");
119 PROP2ENV("turbojpeg.arithmetic", "TJ_ARITHMETIC");
120 PROP2ENV("turbojpeg.restart", "TJ_RESTART");
121 PROP2ENV("turbojpeg.progressive", "TJ_PROGRESSIVE");
DRC19c791c2018-03-08 10:55:20 -0600122 return 0;
DRC0713c1b2014-08-22 13:43:33 +0000123
DRC19c791c2018-03-08 10:55:20 -0600124bailout:
125 return -1;
DRC0713c1b2014-08-22 13:43:33 +0000126}
127
DRCa4940d12014-08-15 16:07:15 +0000128/* TurboJPEG 1.2.x: TJ::bufSize() */
DRC3bad53f2011-02-23 02:20:49 +0000129JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize
DRC19c791c2018-03-08 10:55:20 -0600130 (JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp)
DRCf8e00552011-02-04 11:06:36 +0000131{
DRC19c791c2018-03-08 10:55:20 -0600132 jint retval = (jint)tjBufSize(width, height, jpegSubsamp);
DRC36336fc2011-02-22 10:27:31 +0000133
DRCbce58f42019-04-12 07:49:35 -0500134 if (retval == -1) THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600135
136bailout:
137 return retval;
DRC36336fc2011-02-22 10:27:31 +0000138}
139
DRCa4940d12014-08-15 16:07:15 +0000140/* TurboJPEG 1.4.x: TJ::bufSizeYUV() */
DRCfef98522013-04-28 01:32:52 +0000141JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
DRC19c791c2018-03-08 10:55:20 -0600142 (JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp)
DRC36336fc2011-02-22 10:27:31 +0000143{
DRC19c791c2018-03-08 10:55:20 -0600144 jint retval = (jint)tjBufSizeYUV2(width, pad, height, subsamp);
DRC36336fc2011-02-22 10:27:31 +0000145
DRCbce58f42019-04-12 07:49:35 -0500146 if (retval == -1) THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600147
148bailout:
149 return retval;
DRCf8e00552011-02-04 11:06:36 +0000150}
151
DRCa4940d12014-08-15 16:07:15 +0000152/* TurboJPEG 1.2.x: TJ::bufSizeYUV() */
DRCfef98522013-04-28 01:32:52 +0000153JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III
DRC19c791c2018-03-08 10:55:20 -0600154 (JNIEnv *env, jclass cls, jint width, jint height, jint subsamp)
DRCfef98522013-04-28 01:32:52 +0000155{
DRC19c791c2018-03-08 10:55:20 -0600156 return Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII(env, cls, width,
157 4, height,
158 subsamp);
DRCfef98522013-04-28 01:32:52 +0000159}
160
DRC40dd3142014-08-17 12:23:49 +0000161/* TurboJPEG 1.4.x: TJ::planeSizeYUV() */
162JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII
DRC19c791c2018-03-08 10:55:20 -0600163 (JNIEnv *env, jclass cls, jint componentID, jint width, jint stride,
164 jint height, jint subsamp)
DRC40dd3142014-08-17 12:23:49 +0000165{
DRC19c791c2018-03-08 10:55:20 -0600166 jint retval = (jint)tjPlaneSizeYUV(componentID, width, stride, height,
167 subsamp);
DRC40dd3142014-08-17 12:23:49 +0000168
DRCbce58f42019-04-12 07:49:35 -0500169 if (retval == -1) THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600170
171bailout:
172 return retval;
DRC40dd3142014-08-17 12:23:49 +0000173}
174
175/* TurboJPEG 1.4.x: TJ::planeWidth() */
176JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III
DRC19c791c2018-03-08 10:55:20 -0600177 (JNIEnv *env, jclass cls, jint componentID, jint width, jint subsamp)
DRC40dd3142014-08-17 12:23:49 +0000178{
DRC19c791c2018-03-08 10:55:20 -0600179 jint retval = (jint)tjPlaneWidth(componentID, width, subsamp);
DRC40dd3142014-08-17 12:23:49 +0000180
DRCbce58f42019-04-12 07:49:35 -0500181 if (retval == -1) THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600182
183bailout:
184 return retval;
DRC40dd3142014-08-17 12:23:49 +0000185}
186
187/* TurboJPEG 1.4.x: TJ::planeHeight() */
188JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III
DRC19c791c2018-03-08 10:55:20 -0600189 (JNIEnv *env, jclass cls, jint componentID, jint height, jint subsamp)
DRC40dd3142014-08-17 12:23:49 +0000190{
DRC19c791c2018-03-08 10:55:20 -0600191 jint retval = (jint)tjPlaneHeight(componentID, height, subsamp);
DRC40dd3142014-08-17 12:23:49 +0000192
DRCbce58f42019-04-12 07:49:35 -0500193 if (retval == -1) THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600194
195bailout:
196 return retval;
DRC40dd3142014-08-17 12:23:49 +0000197}
198
DRCa4940d12014-08-15 16:07:15 +0000199/* TurboJPEG 1.2.x: TJCompressor::init() */
DRCc5a41992011-02-08 06:54:36 +0000200JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init
DRC19c791c2018-03-08 10:55:20 -0600201 (JNIEnv *env, jobject obj)
DRCf8e00552011-02-04 11:06:36 +0000202{
DRC19c791c2018-03-08 10:55:20 -0600203 jclass cls;
204 jfieldID fid;
205 tjhandle handle;
DRCf8e00552011-02-04 11:06:36 +0000206
DRC19c791c2018-03-08 10:55:20 -0600207 if ((handle = tjInitCompress()) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500208 THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
DRCf8e00552011-02-04 11:06:36 +0000209
DRCbce58f42019-04-12 07:49:35 -0500210 BAILIF0(cls = (*env)->GetObjectClass(env, obj));
211 BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
DRC19c791c2018-03-08 10:55:20 -0600212 (*env)->SetLongField(env, obj, fid, (size_t)handle);
DRCf8e00552011-02-04 11:06:36 +0000213
DRC19c791c2018-03-08 10:55:20 -0600214bailout:
215 return;
DRCf8e00552011-02-04 11:06:36 +0000216}
217
DRC5d87f6d2014-08-15 16:40:56 +0000218static jint TJCompressor_compress
DRC19c791c2018-03-08 10:55:20 -0600219 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
220 jint width, jint pitch, jint height, jint pf, jbyteArray dst,
221 jint jpegSubsamp, jint jpegQual, jint flags)
DRCf8e00552011-02-04 11:06:36 +0000222{
DRC19c791c2018-03-08 10:55:20 -0600223 tjhandle handle = 0;
224 unsigned long jpegSize = 0;
225 jsize arraySize = 0, actualPitch;
226 unsigned char *srcBuf = NULL, *jpegBuf = NULL;
DRCf8e00552011-02-04 11:06:36 +0000227
DRCbce58f42019-04-12 07:49:35 -0500228 GET_HANDLE();
DRCf8e00552011-02-04 11:06:36 +0000229
DRC19c791c2018-03-08 10:55:20 -0600230 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
231 height < 1 || pitch < 0)
DRCbce58f42019-04-12 07:49:35 -0500232 THROW_ARG("Invalid argument in compress()");
DRC19c791c2018-03-08 10:55:20 -0600233 if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500234 THROW_ARG("Mismatch between Java and C API");
DRC4f1580c2011-02-25 06:11:03 +0000235
DRC19c791c2018-03-08 10:55:20 -0600236 actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
237 arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
238 if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
DRCbce58f42019-04-12 07:49:35 -0500239 THROW_ARG("Source buffer is not large enough");
DRC19c791c2018-03-08 10:55:20 -0600240 jpegSize = tjBufSize(width, height, jpegSubsamp);
241 if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500242 THROW_ARG("Destination buffer is not large enough");
DRC6acf52b2011-03-02 01:09:20 +0000243
DRC5ea77d82018-10-26 08:55:22 -0500244 if (ProcessSystemProperties(env) < 0) goto bailout;
245
DRCbce58f42019-04-12 07:49:35 -0500246 BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
247 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRCf8e00552011-02-04 11:06:36 +0000248
DRC19c791c2018-03-08 10:55:20 -0600249 if (tjCompress2(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
250 width, pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp,
DRC33011752019-04-12 08:47:28 -0500251 jpegQual, flags | TJFLAG_NOREALLOC) == -1) {
252 SAFE_RELEASE(dst, jpegBuf);
253 SAFE_RELEASE(src, srcBuf);
DRCbce58f42019-04-12 07:49:35 -0500254 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500255 }
DRCfac3bea2012-09-24 02:27:55 +0000256
DRC19c791c2018-03-08 10:55:20 -0600257bailout:
DRC33011752019-04-12 08:47:28 -0500258 SAFE_RELEASE(dst, jpegBuf);
259 SAFE_RELEASE(src, srcBuf);
DRC19c791c2018-03-08 10:55:20 -0600260 return (jint)jpegSize;
DRCfac3bea2012-09-24 02:27:55 +0000261}
262
DRCa4940d12014-08-15 16:07:15 +0000263/* TurboJPEG 1.3.x: TJCompressor::compress() byte source */
DRC927a10d2014-08-15 13:18:58 +0000264JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
DRC19c791c2018-03-08 10:55:20 -0600265 (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
266 jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
267 jint jpegQual, jint flags)
DRC927a10d2014-08-15 13:18:58 +0000268{
DRC19c791c2018-03-08 10:55:20 -0600269 return TJCompressor_compress(env, obj, src, 1, x, y, width, pitch, height,
270 pf, dst, jpegSubsamp, jpegQual, flags);
DRC927a10d2014-08-15 13:18:58 +0000271}
272
DRCa4940d12014-08-15 16:07:15 +0000273/* TurboJPEG 1.2.x: TJCompressor::compress() byte source */
DRCfac3bea2012-09-24 02:27:55 +0000274JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
DRC19c791c2018-03-08 10:55:20 -0600275 (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
276 jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
277 jint flags)
DRCfac3bea2012-09-24 02:27:55 +0000278{
DRC19c791c2018-03-08 10:55:20 -0600279 return TJCompressor_compress(env, obj, src, 1, 0, 0, width, pitch, height,
280 pf, dst, jpegSubsamp, jpegQual, flags);
DRCfac3bea2012-09-24 02:27:55 +0000281}
282
DRCa4940d12014-08-15 16:07:15 +0000283/* TurboJPEG 1.3.x: TJCompressor::compress() int source */
DRCfac3bea2012-09-24 02:27:55 +0000284JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
DRC19c791c2018-03-08 10:55:20 -0600285 (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
286 jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
287 jint jpegQual, jint flags)
DRCfac3bea2012-09-24 02:27:55 +0000288{
DRC19c791c2018-03-08 10:55:20 -0600289 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500290 THROW_ARG("Invalid argument in compress()");
DRC19c791c2018-03-08 10:55:20 -0600291 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500292 THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
DRCfac3bea2012-09-24 02:27:55 +0000293
DRC19c791c2018-03-08 10:55:20 -0600294 return TJCompressor_compress(env, obj, src, sizeof(jint), x, y, width,
295 stride * sizeof(jint), height, pf, dst,
296 jpegSubsamp, jpegQual, flags);
DRCf8e00552011-02-04 11:06:36 +0000297
DRC19c791c2018-03-08 10:55:20 -0600298bailout:
299 return 0;
DRCf8e00552011-02-04 11:06:36 +0000300}
301
DRCa4940d12014-08-15 16:07:15 +0000302/* TurboJPEG 1.2.x: TJCompressor::compress() int source */
DRC4f1580c2011-02-25 06:11:03 +0000303JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
DRC19c791c2018-03-08 10:55:20 -0600304 (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
305 jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
306 jint flags)
DRC84a1bcc2011-02-23 12:09:56 +0000307{
DRC19c791c2018-03-08 10:55:20 -0600308 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500309 THROW_ARG("Invalid argument in compress()");
DRC19c791c2018-03-08 10:55:20 -0600310 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500311 THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
DRC927a10d2014-08-15 13:18:58 +0000312
DRC19c791c2018-03-08 10:55:20 -0600313 return TJCompressor_compress(env, obj, src, sizeof(jint), 0, 0, width,
314 stride * sizeof(jint), height, pf, dst,
315 jpegSubsamp, jpegQual, flags);
DRC927a10d2014-08-15 13:18:58 +0000316
DRC19c791c2018-03-08 10:55:20 -0600317bailout:
318 return 0;
DRC84a1bcc2011-02-23 12:09:56 +0000319}
320
DRCa4940d12014-08-15 16:07:15 +0000321/* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */
DRC40dd3142014-08-17 12:23:49 +0000322JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII
DRC19c791c2018-03-08 10:55:20 -0600323 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
324 jint width, jintArray jSrcStrides, jint height, jint subsamp,
325 jbyteArray dst, jint jpegQual, jint flags)
DRC1e672742013-10-31 05:04:51 +0000326{
DRC19c791c2018-03-08 10:55:20 -0600327 tjhandle handle = 0;
328 unsigned long jpegSize = 0;
329 jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
330 const unsigned char *srcPlanes[3];
331 unsigned char *jpegBuf = NULL;
332 int *srcOffsets = NULL, *srcStrides = NULL;
333 int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
DRC1e672742013-10-31 05:04:51 +0000334
DRCbce58f42019-04-12 07:49:35 -0500335 GET_HANDLE();
DRC1e672742013-10-31 05:04:51 +0000336
DRC19c791c2018-03-08 10:55:20 -0600337 if (subsamp < 0 || subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500338 THROW_ARG("Invalid argument in compressFromYUV()");
DRC19c791c2018-03-08 10:55:20 -0600339 if (org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500340 THROW_ARG("Mismatch between Java and C API");
DRC40dd3142014-08-17 12:23:49 +0000341
DRC19c791c2018-03-08 10:55:20 -0600342 if ((*env)->GetArrayLength(env, srcobjs) < nc)
DRCbce58f42019-04-12 07:49:35 -0500343 THROW_ARG("Planes array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600344 if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
DRCbce58f42019-04-12 07:49:35 -0500345 THROW_ARG("Offsets array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600346 if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
DRCbce58f42019-04-12 07:49:35 -0500347 THROW_ARG("Strides array is too small for the subsampling type");
DRC40dd3142014-08-17 12:23:49 +0000348
DRC19c791c2018-03-08 10:55:20 -0600349 jpegSize = tjBufSize(width, height, subsamp);
350 if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500351 THROW_ARG("Destination buffer is not large enough");
DRC1e672742013-10-31 05:04:51 +0000352
DRC5ea77d82018-10-26 08:55:22 -0500353 if (ProcessSystemProperties(env) < 0) goto bailout;
354
DRC33011752019-04-12 08:47:28 -0500355#define RELEASE_ARRAYS_COMPRESSFROMYUV() { \
356 SAFE_RELEASE(dst, jpegBuf); \
357 for (i = 0; i < nc; i++) \
358 SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \
359 SAFE_RELEASE(jSrcStrides, srcStrides); \
360 SAFE_RELEASE(jSrcOffsets, srcOffsets); \
361}
362
DRCbce58f42019-04-12 07:49:35 -0500363 BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
364 BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
DRC19c791c2018-03-08 10:55:20 -0600365 for (i = 0; i < nc; i++) {
366 int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
367 int pw = tjPlaneWidth(i, width, subsamp);
DRC40dd3142014-08-17 12:23:49 +0000368
DRC33011752019-04-12 08:47:28 -0500369 if (planeSize < 0 || pw < 0) {
370 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRCbce58f42019-04-12 07:49:35 -0500371 THROW_ARG(tjGetErrorStr());
DRC33011752019-04-12 08:47:28 -0500372 }
DRC40dd3142014-08-17 12:23:49 +0000373
DRC33011752019-04-12 08:47:28 -0500374 if (srcOffsets[i] < 0) {
375 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRCbce58f42019-04-12 07:49:35 -0500376 THROW_ARG("Invalid argument in compressFromYUV()");
DRC33011752019-04-12 08:47:28 -0500377 }
378 if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
379 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRCbce58f42019-04-12 07:49:35 -0500380 THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
DRC33011752019-04-12 08:47:28 -0500381 }
DRC40dd3142014-08-17 12:23:49 +0000382
DRCbce58f42019-04-12 07:49:35 -0500383 BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
DRC33011752019-04-12 08:47:28 -0500384 if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
385 srcOffsets[i] + planeSize) {
386 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRCbce58f42019-04-12 07:49:35 -0500387 THROW_ARG("Source plane is not large enough");
DRC33011752019-04-12 08:47:28 -0500388 }
DRC40dd3142014-08-17 12:23:49 +0000389
DRCbce58f42019-04-12 07:49:35 -0500390 BAILIF0(srcPlanes[i] =
DRC19c791c2018-03-08 10:55:20 -0600391 (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
392 srcPlanes[i] = &srcPlanes[i][srcOffsets[i]];
393 }
DRCbce58f42019-04-12 07:49:35 -0500394 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRC1e672742013-10-31 05:04:51 +0000395
DRC19c791c2018-03-08 10:55:20 -0600396 if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
397 subsamp, &jpegBuf, &jpegSize, jpegQual,
DRC33011752019-04-12 08:47:28 -0500398 flags | TJFLAG_NOREALLOC) == -1) {
399 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRCbce58f42019-04-12 07:49:35 -0500400 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500401 }
DRC1e672742013-10-31 05:04:51 +0000402
DRC19c791c2018-03-08 10:55:20 -0600403bailout:
DRC33011752019-04-12 08:47:28 -0500404 RELEASE_ARRAYS_COMPRESSFROMYUV();
DRC19c791c2018-03-08 10:55:20 -0600405 return (jint)jpegSize;
DRC1e672742013-10-31 05:04:51 +0000406}
407
DRC5d87f6d2014-08-15 16:40:56 +0000408static void TJCompressor_encodeYUV
DRC19c791c2018-03-08 10:55:20 -0600409 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
410 jint width, jint pitch, jint height, jint pf, jobjectArray dstobjs,
411 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
DRC4f1580c2011-02-25 06:11:03 +0000412{
DRC19c791c2018-03-08 10:55:20 -0600413 tjhandle handle = 0;
414 jsize arraySize = 0, actualPitch;
415 jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
416 unsigned char *srcBuf = NULL, *dstPlanes[3];
417 int *dstOffsets = NULL, *dstStrides = NULL;
418 int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
DRC40dd3142014-08-17 12:23:49 +0000419
DRCbce58f42019-04-12 07:49:35 -0500420 GET_HANDLE();
DRC40dd3142014-08-17 12:23:49 +0000421
DRC19c791c2018-03-08 10:55:20 -0600422 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
423 height < 1 || pitch < 0 || subsamp < 0 ||
424 subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500425 THROW_ARG("Invalid argument in encodeYUV()");
DRC19c791c2018-03-08 10:55:20 -0600426 if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
427 org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500428 THROW_ARG("Mismatch between Java and C API");
DRC40dd3142014-08-17 12:23:49 +0000429
DRC19c791c2018-03-08 10:55:20 -0600430 if ((*env)->GetArrayLength(env, dstobjs) < nc)
DRCbce58f42019-04-12 07:49:35 -0500431 THROW_ARG("Planes array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600432 if ((*env)->GetArrayLength(env, jDstOffsets) < nc)
DRCbce58f42019-04-12 07:49:35 -0500433 THROW_ARG("Offsets array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600434 if ((*env)->GetArrayLength(env, jDstStrides) < nc)
DRCbce58f42019-04-12 07:49:35 -0500435 THROW_ARG("Strides array is too small for the subsampling type");
DRC40dd3142014-08-17 12:23:49 +0000436
DRC19c791c2018-03-08 10:55:20 -0600437 actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
438 arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
439 if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
DRCbce58f42019-04-12 07:49:35 -0500440 THROW_ARG("Source buffer is not large enough");
DRC40dd3142014-08-17 12:23:49 +0000441
DRC33011752019-04-12 08:47:28 -0500442#define RELEASE_ARRAYS_ENCODEYUV() { \
443 SAFE_RELEASE(src, srcBuf); \
444 for (i = 0; i < nc; i++) \
445 SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \
446 SAFE_RELEASE(jDstStrides, dstStrides); \
447 SAFE_RELEASE(jDstOffsets, dstOffsets); \
448}
449
DRCbce58f42019-04-12 07:49:35 -0500450 BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
451 BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
DRC19c791c2018-03-08 10:55:20 -0600452 for (i = 0; i < nc; i++) {
453 int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
454 int pw = tjPlaneWidth(i, width, subsamp);
DRC40dd3142014-08-17 12:23:49 +0000455
DRC33011752019-04-12 08:47:28 -0500456 if (planeSize < 0 || pw < 0) {
457 RELEASE_ARRAYS_ENCODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500458 THROW_ARG(tjGetErrorStr());
DRC33011752019-04-12 08:47:28 -0500459 }
DRC40dd3142014-08-17 12:23:49 +0000460
DRC33011752019-04-12 08:47:28 -0500461 if (dstOffsets[i] < 0) {
462 RELEASE_ARRAYS_ENCODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500463 THROW_ARG("Invalid argument in encodeYUV()");
DRC33011752019-04-12 08:47:28 -0500464 }
465 if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
466 RELEASE_ARRAYS_ENCODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500467 THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
DRC33011752019-04-12 08:47:28 -0500468 }
DRC40dd3142014-08-17 12:23:49 +0000469
DRCbce58f42019-04-12 07:49:35 -0500470 BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
DRC33011752019-04-12 08:47:28 -0500471 if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
472 dstOffsets[i] + planeSize) {
473 RELEASE_ARRAYS_ENCODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500474 THROW_ARG("Destination plane is not large enough");
DRC33011752019-04-12 08:47:28 -0500475 }
DRC40dd3142014-08-17 12:23:49 +0000476
DRCbce58f42019-04-12 07:49:35 -0500477 BAILIF0(dstPlanes[i] =
DRC19c791c2018-03-08 10:55:20 -0600478 (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
479 dstPlanes[i] = &dstPlanes[i][dstOffsets[i]];
480 }
DRCbce58f42019-04-12 07:49:35 -0500481 BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
DRC40dd3142014-08-17 12:23:49 +0000482
DRC19c791c2018-03-08 10:55:20 -0600483 if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
484 width, pitch, height, pf, dstPlanes, dstStrides,
DRC33011752019-04-12 08:47:28 -0500485 subsamp, flags) == -1) {
486 RELEASE_ARRAYS_ENCODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500487 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500488 }
DRC40dd3142014-08-17 12:23:49 +0000489
DRC19c791c2018-03-08 10:55:20 -0600490bailout:
DRC33011752019-04-12 08:47:28 -0500491 RELEASE_ARRAYS_ENCODEYUV();
DRC40dd3142014-08-17 12:23:49 +0000492}
493
494/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */
495JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III
DRC19c791c2018-03-08 10:55:20 -0600496 (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
497 jint pitch, jint height, jint pf, jobjectArray dstobjs,
498 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
DRC40dd3142014-08-17 12:23:49 +0000499{
DRC19c791c2018-03-08 10:55:20 -0600500 TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf,
501 dstobjs, jDstOffsets, jDstStrides, subsamp, flags);
DRC40dd3142014-08-17 12:23:49 +0000502}
503
504/* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */
505JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
DRC19c791c2018-03-08 10:55:20 -0600506 (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
507 jint stride, jint height, jint pf, jobjectArray dstobjs,
508 jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
DRC40dd3142014-08-17 12:23:49 +0000509{
DRC19c791c2018-03-08 10:55:20 -0600510 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500511 THROW_ARG("Invalid argument in encodeYUV()");
DRC19c791c2018-03-08 10:55:20 -0600512 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500513 THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
DRC40dd3142014-08-17 12:23:49 +0000514
DRC19c791c2018-03-08 10:55:20 -0600515 TJCompressor_encodeYUV(env, obj, src, sizeof(jint), x, y, width,
516 stride * sizeof(jint), height, pf, dstobjs,
517 jDstOffsets, jDstStrides, subsamp, flags);
DRC40dd3142014-08-17 12:23:49 +0000518
DRC19c791c2018-03-08 10:55:20 -0600519bailout:
520 return;
DRC40dd3142014-08-17 12:23:49 +0000521}
522
523JNIEXPORT void JNICALL TJCompressor_encodeYUV_12
DRC19c791c2018-03-08 10:55:20 -0600524 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width,
525 jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
DRC40dd3142014-08-17 12:23:49 +0000526{
DRC19c791c2018-03-08 10:55:20 -0600527 tjhandle handle = 0;
528 jsize arraySize = 0;
529 unsigned char *srcBuf = NULL, *dstBuf = NULL;
DRC4f1580c2011-02-25 06:11:03 +0000530
DRCbce58f42019-04-12 07:49:35 -0500531 GET_HANDLE();
DRC4f1580c2011-02-25 06:11:03 +0000532
DRC19c791c2018-03-08 10:55:20 -0600533 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
534 height < 1 || pitch < 0)
DRCbce58f42019-04-12 07:49:35 -0500535 THROW_ARG("Invalid argument in encodeYUV()");
DRC19c791c2018-03-08 10:55:20 -0600536 if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500537 THROW_ARG("Mismatch between Java and C API");
DRC4f1580c2011-02-25 06:11:03 +0000538
DRC19c791c2018-03-08 10:55:20 -0600539 arraySize = (pitch == 0) ? width * tjPixelSize[pf] * height : pitch * height;
540 if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
DRCbce58f42019-04-12 07:49:35 -0500541 THROW_ARG("Source buffer is not large enough");
DRC19c791c2018-03-08 10:55:20 -0600542 if ((*env)->GetArrayLength(env, dst) <
543 (jsize)tjBufSizeYUV(width, height, subsamp))
DRCbce58f42019-04-12 07:49:35 -0500544 THROW_ARG("Destination buffer is not large enough");
DRC6acf52b2011-03-02 01:09:20 +0000545
DRCbce58f42019-04-12 07:49:35 -0500546 BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
547 BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRC4f1580c2011-02-25 06:11:03 +0000548
DRC19c791c2018-03-08 10:55:20 -0600549 if (tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
DRC33011752019-04-12 08:47:28 -0500550 flags) == -1) {
551 SAFE_RELEASE(dst, dstBuf);
552 SAFE_RELEASE(src, srcBuf);
DRCbce58f42019-04-12 07:49:35 -0500553 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500554 }
DRC4f1580c2011-02-25 06:11:03 +0000555
DRC19c791c2018-03-08 10:55:20 -0600556bailout:
DRC33011752019-04-12 08:47:28 -0500557 SAFE_RELEASE(dst, dstBuf);
558 SAFE_RELEASE(src, srcBuf);
DRC4f1580c2011-02-25 06:11:03 +0000559}
560
DRCa4940d12014-08-15 16:07:15 +0000561/* TurboJPEG 1.2.x: TJCompressor::encodeYUV() byte source */
DRCfef98522013-04-28 01:32:52 +0000562JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
DRC19c791c2018-03-08 10:55:20 -0600563 (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
564 jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
DRC4f1580c2011-02-25 06:11:03 +0000565{
DRC19c791c2018-03-08 10:55:20 -0600566 TJCompressor_encodeYUV_12(env, obj, src, 1, width, pitch, height, pf, dst,
567 subsamp, flags);
DRC4f1580c2011-02-25 06:11:03 +0000568}
569
DRCa4940d12014-08-15 16:07:15 +0000570/* TurboJPEG 1.2.x: TJCompressor::encodeYUV() int source */
DRCfef98522013-04-28 01:32:52 +0000571JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII
DRC19c791c2018-03-08 10:55:20 -0600572 (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
573 jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
DRCfef98522013-04-28 01:32:52 +0000574{
DRC19c791c2018-03-08 10:55:20 -0600575 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500576 THROW_ARG("Invalid argument in encodeYUV()");
DRC19c791c2018-03-08 10:55:20 -0600577 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500578 THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
DRC927a10d2014-08-15 13:18:58 +0000579
DRC19c791c2018-03-08 10:55:20 -0600580 TJCompressor_encodeYUV_12(env, obj, src, sizeof(jint), width,
581 stride * sizeof(jint), height, pf, dst, subsamp,
582 flags);
DRC927a10d2014-08-15 13:18:58 +0000583
DRC19c791c2018-03-08 10:55:20 -0600584bailout:
585 return;
DRCfef98522013-04-28 01:32:52 +0000586}
587
DRCa4940d12014-08-15 16:07:15 +0000588/* TurboJPEG 1.2.x: TJCompressor::destroy() */
DRCc5a41992011-02-08 06:54:36 +0000589JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
DRC19c791c2018-03-08 10:55:20 -0600590 (JNIEnv *env, jobject obj)
DRCf8e00552011-02-04 11:06:36 +0000591{
DRC19c791c2018-03-08 10:55:20 -0600592 tjhandle handle = 0;
DRCf8e00552011-02-04 11:06:36 +0000593
DRCbce58f42019-04-12 07:49:35 -0500594 GET_HANDLE();
DRCf8e00552011-02-04 11:06:36 +0000595
DRCbce58f42019-04-12 07:49:35 -0500596 if (tjDestroy(handle) == -1) THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -0600597 (*env)->SetLongField(env, obj, _fid, 0);
DRCf8e00552011-02-04 11:06:36 +0000598
DRC19c791c2018-03-08 10:55:20 -0600599bailout:
600 return;
DRCf8e00552011-02-04 11:06:36 +0000601}
602
DRCa4940d12014-08-15 16:07:15 +0000603/* TurboJPEG 1.2.x: TJDecompressor::init() */
DRCc5a41992011-02-08 06:54:36 +0000604JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
DRC19c791c2018-03-08 10:55:20 -0600605 (JNIEnv *env, jobject obj)
DRCf8e00552011-02-04 11:06:36 +0000606{
DRC19c791c2018-03-08 10:55:20 -0600607 jclass cls;
608 jfieldID fid;
609 tjhandle handle;
DRCf8e00552011-02-04 11:06:36 +0000610
DRC19c791c2018-03-08 10:55:20 -0600611 if ((handle = tjInitDecompress()) == NULL)
DRCbce58f42019-04-12 07:49:35 -0500612 THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
DRCf8e00552011-02-04 11:06:36 +0000613
DRCbce58f42019-04-12 07:49:35 -0500614 BAILIF0(cls = (*env)->GetObjectClass(env, obj));
615 BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
DRC19c791c2018-03-08 10:55:20 -0600616 (*env)->SetLongField(env, obj, fid, (size_t)handle);
DRCf8e00552011-02-04 11:06:36 +0000617
DRC19c791c2018-03-08 10:55:20 -0600618bailout:
619 return;
DRCf8e00552011-02-04 11:06:36 +0000620}
621
DRCa4940d12014-08-15 16:07:15 +0000622/* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */
DRC109a5782011-03-01 09:53:07 +0000623JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
DRC19c791c2018-03-08 10:55:20 -0600624 (JNIEnv *env, jclass cls)
DRC36336fc2011-02-22 10:27:31 +0000625{
DRC19c791c2018-03-08 10:55:20 -0600626 jclass sfcls = NULL;
627 jfieldID fid = 0;
628 tjscalingfactor *sf = NULL;
629 int n = 0, i;
630 jobject sfobj = NULL;
631 jobjectArray sfjava = NULL;
DRC109a5782011-03-01 09:53:07 +0000632
DRC19c791c2018-03-08 10:55:20 -0600633 if ((sf = tjGetScalingFactors(&n)) == NULL || n == 0)
DRCbce58f42019-04-12 07:49:35 -0500634 THROW_ARG(tjGetErrorStr());
DRC36336fc2011-02-22 10:27:31 +0000635
DRCbce58f42019-04-12 07:49:35 -0500636 BAILIF0(sfcls = (*env)->FindClass(env,
DRC19c791c2018-03-08 10:55:20 -0600637 "org/libjpegturbo/turbojpeg/TJScalingFactor"));
DRCbce58f42019-04-12 07:49:35 -0500638 BAILIF0(sfjava = (jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
DRC36336fc2011-02-22 10:27:31 +0000639
DRC19c791c2018-03-08 10:55:20 -0600640 for (i = 0; i < n; i++) {
DRCbce58f42019-04-12 07:49:35 -0500641 BAILIF0(sfobj = (*env)->AllocObject(env, sfcls));
642 BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
DRC19c791c2018-03-08 10:55:20 -0600643 (*env)->SetIntField(env, sfobj, fid, sf[i].num);
DRCbce58f42019-04-12 07:49:35 -0500644 BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
DRC19c791c2018-03-08 10:55:20 -0600645 (*env)->SetIntField(env, sfobj, fid, sf[i].denom);
646 (*env)->SetObjectArrayElement(env, sfjava, i, sfobj);
647 }
DRC36336fc2011-02-22 10:27:31 +0000648
DRC19c791c2018-03-08 10:55:20 -0600649bailout:
650 return sfjava;
DRC36336fc2011-02-22 10:27:31 +0000651}
652
DRCa4940d12014-08-15 16:07:15 +0000653/* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */
DRC3bad53f2011-02-23 02:20:49 +0000654JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader
DRC19c791c2018-03-08 10:55:20 -0600655 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize)
DRCf8e00552011-02-04 11:06:36 +0000656{
DRC19c791c2018-03-08 10:55:20 -0600657 tjhandle handle = 0;
658 unsigned char *jpegBuf = NULL;
659 int width = 0, height = 0, jpegSubsamp = -1, jpegColorspace = -1;
DRCf8e00552011-02-04 11:06:36 +0000660
DRCbce58f42019-04-12 07:49:35 -0500661 GET_HANDLE();
DRCf8e00552011-02-04 11:06:36 +0000662
DRC19c791c2018-03-08 10:55:20 -0600663 if ((*env)->GetArrayLength(env, src) < jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500664 THROW_ARG("Source buffer is not large enough");
DRC6acf52b2011-03-02 01:09:20 +0000665
DRCbce58f42019-04-12 07:49:35 -0500666 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
DRCf8e00552011-02-04 11:06:36 +0000667
DRC19c791c2018-03-08 10:55:20 -0600668 if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width,
DRC33011752019-04-12 08:47:28 -0500669 &height, &jpegSubsamp, &jpegColorspace) == -1) {
670 SAFE_RELEASE(src, jpegBuf);
DRCbce58f42019-04-12 07:49:35 -0500671 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500672 }
DRC8951cf02014-08-14 16:54:04 +0000673
DRC33011752019-04-12 08:47:28 -0500674 SAFE_RELEASE(src, jpegBuf);
DRCf8e00552011-02-04 11:06:36 +0000675
DRCbce58f42019-04-12 07:49:35 -0500676 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
DRC19c791c2018-03-08 10:55:20 -0600677 (*env)->SetIntField(env, obj, _fid, jpegSubsamp);
678 if ((_fid = (*env)->GetFieldID(env, _cls, "jpegColorspace", "I")) == 0)
679 (*env)->ExceptionClear(env);
680 else
681 (*env)->SetIntField(env, obj, _fid, jpegColorspace);
DRCbce58f42019-04-12 07:49:35 -0500682 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
DRC19c791c2018-03-08 10:55:20 -0600683 (*env)->SetIntField(env, obj, _fid, width);
DRCbce58f42019-04-12 07:49:35 -0500684 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
DRC19c791c2018-03-08 10:55:20 -0600685 (*env)->SetIntField(env, obj, _fid, height);
DRCf8e00552011-02-04 11:06:36 +0000686
DRC19c791c2018-03-08 10:55:20 -0600687bailout:
DRC33011752019-04-12 08:47:28 -0500688 SAFE_RELEASE(src, jpegBuf);
DRCf8e00552011-02-04 11:06:36 +0000689}
690
DRC5d87f6d2014-08-15 16:40:56 +0000691static void TJDecompressor_decompress
DRC19c791c2018-03-08 10:55:20 -0600692 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst,
693 jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height,
694 jint pf, jint flags)
DRCf8e00552011-02-04 11:06:36 +0000695{
DRC19c791c2018-03-08 10:55:20 -0600696 tjhandle handle = 0;
697 jsize arraySize = 0, actualPitch;
698 unsigned char *jpegBuf = NULL, *dstBuf = NULL;
DRCf8e00552011-02-04 11:06:36 +0000699
DRCbce58f42019-04-12 07:49:35 -0500700 GET_HANDLE();
DRCf8e00552011-02-04 11:06:36 +0000701
DRC19c791c2018-03-08 10:55:20 -0600702 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500703 THROW_ARG("Invalid argument in decompress()");
DRC19c791c2018-03-08 10:55:20 -0600704 if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500705 THROW_ARG("Mismatch between Java and C API");
DRC4f1580c2011-02-25 06:11:03 +0000706
DRC19c791c2018-03-08 10:55:20 -0600707 if ((*env)->GetArrayLength(env, src) < jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500708 THROW_ARG("Source buffer is not large enough");
DRC19c791c2018-03-08 10:55:20 -0600709 actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
710 arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
711 if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
DRCbce58f42019-04-12 07:49:35 -0500712 THROW_ARG("Destination buffer is not large enough");
DRC6acf52b2011-03-02 01:09:20 +0000713
DRCbce58f42019-04-12 07:49:35 -0500714 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
715 BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRCf8e00552011-02-04 11:06:36 +0000716
DRC19c791c2018-03-08 10:55:20 -0600717 if (tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize,
718 &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
DRC33011752019-04-12 08:47:28 -0500719 pitch, height, pf, flags) == -1) {
720 SAFE_RELEASE(dst, dstBuf);
721 SAFE_RELEASE(src, jpegBuf);
DRCbce58f42019-04-12 07:49:35 -0500722 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500723 }
DRCf659f432012-06-06 08:41:06 +0000724
DRC19c791c2018-03-08 10:55:20 -0600725bailout:
DRC33011752019-04-12 08:47:28 -0500726 SAFE_RELEASE(dst, dstBuf);
727 SAFE_RELEASE(src, jpegBuf);
DRCf659f432012-06-06 08:41:06 +0000728}
729
DRCa4940d12014-08-15 16:07:15 +0000730/* TurboJPEG 1.3.x: TJDecompressor::decompress() byte destination */
DRC927a10d2014-08-15 13:18:58 +0000731JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
DRC19c791c2018-03-08 10:55:20 -0600732 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
733 jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
DRC927a10d2014-08-15 13:18:58 +0000734{
DRC19c791c2018-03-08 10:55:20 -0600735 TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width,
736 pitch, height, pf, flags);
DRC927a10d2014-08-15 13:18:58 +0000737}
738
DRCa4940d12014-08-15 16:07:15 +0000739/* TurboJPEG 1.2.x: TJDecompressor::decompress() byte destination */
DRCf659f432012-06-06 08:41:06 +0000740JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
DRC19c791c2018-03-08 10:55:20 -0600741 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
742 jint width, jint pitch, jint height, jint pf, jint flags)
DRCf659f432012-06-06 08:41:06 +0000743{
DRC19c791c2018-03-08 10:55:20 -0600744 TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width,
745 pitch, height, pf, flags);
DRCf659f432012-06-06 08:41:06 +0000746}
747
DRCa4940d12014-08-15 16:07:15 +0000748/* TurboJPEG 1.3.x: TJDecompressor::decompress() int destination */
DRCf659f432012-06-06 08:41:06 +0000749JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII
DRC19c791c2018-03-08 10:55:20 -0600750 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
751 jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags)
DRCf659f432012-06-06 08:41:06 +0000752{
DRC19c791c2018-03-08 10:55:20 -0600753 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500754 THROW_ARG("Invalid argument in decompress()");
DRC19c791c2018-03-08 10:55:20 -0600755 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500756 THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
DRCf659f432012-06-06 08:41:06 +0000757
DRC19c791c2018-03-08 10:55:20 -0600758 TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), x, y,
759 width, stride * sizeof(jint), height, pf, flags);
DRCf8e00552011-02-04 11:06:36 +0000760
DRC19c791c2018-03-08 10:55:20 -0600761bailout:
762 return;
DRCf8e00552011-02-04 11:06:36 +0000763}
764
DRCa4940d12014-08-15 16:07:15 +0000765/* TurboJPEG 1.2.x: TJDecompressor::decompress() int destination */
DRC4f1580c2011-02-25 06:11:03 +0000766JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
DRC19c791c2018-03-08 10:55:20 -0600767 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
768 jint width, jint stride, jint height, jint pf, jint flags)
DRC84a1bcc2011-02-23 12:09:56 +0000769{
DRC19c791c2018-03-08 10:55:20 -0600770 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -0500771 THROW_ARG("Invalid argument in decompress()");
DRC19c791c2018-03-08 10:55:20 -0600772 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -0500773 THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
DRC927a10d2014-08-15 13:18:58 +0000774
DRC19c791c2018-03-08 10:55:20 -0600775 TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 0, 0,
776 width, stride * sizeof(jint), height, pf, flags);
DRC927a10d2014-08-15 13:18:58 +0000777
DRC19c791c2018-03-08 10:55:20 -0600778bailout:
779 return;
DRC4f1580c2011-02-25 06:11:03 +0000780}
DRC84a1bcc2011-02-23 12:09:56 +0000781
DRCa4940d12014-08-15 16:07:15 +0000782/* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */
DRC40dd3142014-08-17 12:23:49 +0000783JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
DRC19c791c2018-03-08 10:55:20 -0600784 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize,
785 jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth,
786 jintArray jDstStrides, jint desiredHeight, jint flags)
DRC4f1580c2011-02-25 06:11:03 +0000787{
DRC19c791c2018-03-08 10:55:20 -0600788 tjhandle handle = 0;
789 jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
790 unsigned char *jpegBuf = NULL, *dstPlanes[3];
791 int *dstOffsets = NULL, *dstStrides = NULL;
792 int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
793 int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
794 tjscalingfactor *sf;
DRC40dd3142014-08-17 12:23:49 +0000795
DRCbce58f42019-04-12 07:49:35 -0500796 GET_HANDLE();
DRC4f1580c2011-02-25 06:11:03 +0000797
DRC19c791c2018-03-08 10:55:20 -0600798 if ((*env)->GetArrayLength(env, src) < jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500799 THROW_ARG("Source buffer is not large enough");
800 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
DRC19c791c2018-03-08 10:55:20 -0600801 jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -0500802 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
DRC19c791c2018-03-08 10:55:20 -0600803 jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -0500804 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
DRC19c791c2018-03-08 10:55:20 -0600805 jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
DRC4f1580c2011-02-25 06:11:03 +0000806
DRC19c791c2018-03-08 10:55:20 -0600807 nc = (jpegSubsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3);
DRC6acf52b2011-03-02 01:09:20 +0000808
DRC19c791c2018-03-08 10:55:20 -0600809 width = desiredWidth;
810 height = desiredHeight;
811 if (width == 0) width = jpegWidth;
812 if (height == 0) height = jpegHeight;
813 sf = tjGetScalingFactors(&nsf);
814 if (!sf || nsf < 1)
DRCbce58f42019-04-12 07:49:35 -0500815 THROW_ARG(tjGetErrorStr());
DRC19c791c2018-03-08 10:55:20 -0600816 for (i = 0; i < nsf; i++) {
817 scaledWidth = TJSCALED(jpegWidth, sf[i]);
818 scaledHeight = TJSCALED(jpegHeight, sf[i]);
819 if (scaledWidth <= width && scaledHeight <= height)
820 break;
821 }
822 if (i >= nsf)
DRCbce58f42019-04-12 07:49:35 -0500823 THROW_ARG("Could not scale down to desired image dimensions");
DRC4f1580c2011-02-25 06:11:03 +0000824
DRC33011752019-04-12 08:47:28 -0500825#define RELEASE_ARRAYS_DECOMPRESSTOYUV() { \
826 SAFE_RELEASE(src, jpegBuf); \
827 for (i = 0; i < nc; i++) \
828 SAFE_RELEASE(jDstPlanes[i], dstPlanes[i]); \
829 SAFE_RELEASE(jDstStrides, dstStrides); \
830 SAFE_RELEASE(jDstOffsets, dstOffsets); \
831}
832
DRCbce58f42019-04-12 07:49:35 -0500833 BAILIF0(dstOffsets = (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
834 BAILIF0(dstStrides = (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
DRC19c791c2018-03-08 10:55:20 -0600835 for (i = 0; i < nc; i++) {
836 int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
837 jpegSubsamp);
838 int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp);
DRC40dd3142014-08-17 12:23:49 +0000839
DRC33011752019-04-12 08:47:28 -0500840 if (planeSize < 0 || pw < 0) {
841 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRCbce58f42019-04-12 07:49:35 -0500842 THROW_ARG(tjGetErrorStr());
DRC33011752019-04-12 08:47:28 -0500843 }
DRC40dd3142014-08-17 12:23:49 +0000844
DRC33011752019-04-12 08:47:28 -0500845 if (dstOffsets[i] < 0) {
846 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRCbce58f42019-04-12 07:49:35 -0500847 THROW_ARG("Invalid argument in decompressToYUV()");
DRC33011752019-04-12 08:47:28 -0500848 }
849 if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0) {
850 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRCbce58f42019-04-12 07:49:35 -0500851 THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
DRC33011752019-04-12 08:47:28 -0500852 }
DRC40dd3142014-08-17 12:23:49 +0000853
DRCbce58f42019-04-12 07:49:35 -0500854 BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
DRC33011752019-04-12 08:47:28 -0500855 if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
856 dstOffsets[i] + planeSize) {
857 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRCbce58f42019-04-12 07:49:35 -0500858 THROW_ARG("Destination plane is not large enough");
DRC33011752019-04-12 08:47:28 -0500859 }
DRC40dd3142014-08-17 12:23:49 +0000860
DRCbce58f42019-04-12 07:49:35 -0500861 BAILIF0(dstPlanes[i] =
DRC19c791c2018-03-08 10:55:20 -0600862 (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
863 dstPlanes[i] = &dstPlanes[i][dstOffsets[i]];
864 }
DRCbce58f42019-04-12 07:49:35 -0500865 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
DRC40dd3142014-08-17 12:23:49 +0000866
DRC19c791c2018-03-08 10:55:20 -0600867 if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
868 dstPlanes, desiredWidth, dstStrides,
DRC33011752019-04-12 08:47:28 -0500869 desiredHeight, flags) == -1) {
870 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRCbce58f42019-04-12 07:49:35 -0500871 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500872 }
DRC40dd3142014-08-17 12:23:49 +0000873
DRC19c791c2018-03-08 10:55:20 -0600874bailout:
DRC33011752019-04-12 08:47:28 -0500875 RELEASE_ARRAYS_DECOMPRESSTOYUV();
DRC84a1bcc2011-02-23 12:09:56 +0000876}
877
DRCa4940d12014-08-15 16:07:15 +0000878/* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */
DRCfef98522013-04-28 01:32:52 +0000879JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI
DRC19c791c2018-03-08 10:55:20 -0600880 (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
881 jint flags)
DRCfef98522013-04-28 01:32:52 +0000882{
DRC19c791c2018-03-08 10:55:20 -0600883 tjhandle handle = 0;
884 unsigned char *jpegBuf = NULL, *dstBuf = NULL;
885 int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
DRCfc26b652014-03-16 22:56:26 +0000886
DRCbce58f42019-04-12 07:49:35 -0500887 GET_HANDLE();
DRCfc26b652014-03-16 22:56:26 +0000888
DRC19c791c2018-03-08 10:55:20 -0600889 if ((*env)->GetArrayLength(env, src) < jpegSize)
DRCbce58f42019-04-12 07:49:35 -0500890 THROW_ARG("Source buffer is not large enough");
891 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
DRC19c791c2018-03-08 10:55:20 -0600892 jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -0500893 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
DRC19c791c2018-03-08 10:55:20 -0600894 jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -0500895 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
DRC19c791c2018-03-08 10:55:20 -0600896 jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
897 if ((*env)->GetArrayLength(env, dst) <
898 (jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp))
DRCbce58f42019-04-12 07:49:35 -0500899 THROW_ARG("Destination buffer is not large enough");
DRC40dd3142014-08-17 12:23:49 +0000900
DRCbce58f42019-04-12 07:49:35 -0500901 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
902 BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRC40dd3142014-08-17 12:23:49 +0000903
DRC19c791c2018-03-08 10:55:20 -0600904 if (tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
DRC33011752019-04-12 08:47:28 -0500905 flags) == -1) {
906 SAFE_RELEASE(dst, dstBuf);
907 SAFE_RELEASE(src, jpegBuf);
DRCbce58f42019-04-12 07:49:35 -0500908 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500909 }
DRC40dd3142014-08-17 12:23:49 +0000910
DRC19c791c2018-03-08 10:55:20 -0600911bailout:
DRC33011752019-04-12 08:47:28 -0500912 SAFE_RELEASE(dst, dstBuf);
913 SAFE_RELEASE(src, jpegBuf);
DRC40dd3142014-08-17 12:23:49 +0000914}
915
916static void TJDecompressor_decodeYUV
DRC19c791c2018-03-08 10:55:20 -0600917 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
918 jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize,
919 jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
DRC40dd3142014-08-17 12:23:49 +0000920{
DRC19c791c2018-03-08 10:55:20 -0600921 tjhandle handle = 0;
922 jsize arraySize = 0, actualPitch;
923 jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
924 const unsigned char *srcPlanes[3];
925 unsigned char *dstBuf = NULL;
926 int *srcOffsets = NULL, *srcStrides = NULL;
927 int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
DRC40dd3142014-08-17 12:23:49 +0000928
DRCbce58f42019-04-12 07:49:35 -0500929 GET_HANDLE();
DRC40dd3142014-08-17 12:23:49 +0000930
DRC19c791c2018-03-08 10:55:20 -0600931 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp < 0 ||
932 subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500933 THROW_ARG("Invalid argument in decodeYUV()");
DRC19c791c2018-03-08 10:55:20 -0600934 if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
935 org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
DRCbce58f42019-04-12 07:49:35 -0500936 THROW_ARG("Mismatch between Java and C API");
DRCfc26b652014-03-16 22:56:26 +0000937
DRC19c791c2018-03-08 10:55:20 -0600938 if ((*env)->GetArrayLength(env, srcobjs) < nc)
DRCbce58f42019-04-12 07:49:35 -0500939 THROW_ARG("Planes array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600940 if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
DRCbce58f42019-04-12 07:49:35 -0500941 THROW_ARG("Offsets array is too small for the subsampling type");
DRC19c791c2018-03-08 10:55:20 -0600942 if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
DRCbce58f42019-04-12 07:49:35 -0500943 THROW_ARG("Strides array is too small for the subsampling type");
DRC40dd3142014-08-17 12:23:49 +0000944
DRC19c791c2018-03-08 10:55:20 -0600945 actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
946 arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
947 if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
DRCbce58f42019-04-12 07:49:35 -0500948 THROW_ARG("Destination buffer is not large enough");
DRCfc26b652014-03-16 22:56:26 +0000949
DRC33011752019-04-12 08:47:28 -0500950#define RELEASE_ARRAYS_DECODEYUV() { \
951 SAFE_RELEASE(dst, dstBuf); \
952 for (i = 0; i < nc; i++) \
953 SAFE_RELEASE(jSrcPlanes[i], srcPlanes[i]); \
954 SAFE_RELEASE(jSrcStrides, srcStrides); \
955 SAFE_RELEASE(jSrcOffsets, srcOffsets); \
956}
957
DRCbce58f42019-04-12 07:49:35 -0500958 BAILIF0(srcOffsets = (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
959 BAILIF0(srcStrides = (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
DRC19c791c2018-03-08 10:55:20 -0600960 for (i = 0; i < nc; i++) {
961 int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
962 int pw = tjPlaneWidth(i, width, subsamp);
DRC40dd3142014-08-17 12:23:49 +0000963
DRC33011752019-04-12 08:47:28 -0500964 if (planeSize < 0 || pw < 0) {
965 RELEASE_ARRAYS_DECODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500966 THROW_ARG(tjGetErrorStr());
DRC33011752019-04-12 08:47:28 -0500967 }
DRC40dd3142014-08-17 12:23:49 +0000968
DRC33011752019-04-12 08:47:28 -0500969 if (srcOffsets[i] < 0) {
970 RELEASE_ARRAYS_DECODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500971 THROW_ARG("Invalid argument in decodeYUV()");
DRC33011752019-04-12 08:47:28 -0500972 }
973 if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0) {
974 RELEASE_ARRAYS_DECODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500975 THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
DRC33011752019-04-12 08:47:28 -0500976 }
DRC40dd3142014-08-17 12:23:49 +0000977
DRCbce58f42019-04-12 07:49:35 -0500978 BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
DRC33011752019-04-12 08:47:28 -0500979 if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
980 srcOffsets[i] + planeSize) {
981 RELEASE_ARRAYS_DECODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500982 THROW_ARG("Source plane is not large enough");
DRC33011752019-04-12 08:47:28 -0500983 }
DRC40dd3142014-08-17 12:23:49 +0000984
DRCbce58f42019-04-12 07:49:35 -0500985 BAILIF0(srcPlanes[i] =
DRC19c791c2018-03-08 10:55:20 -0600986 (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
987 srcPlanes[i] = &srcPlanes[i][srcOffsets[i]];
988 }
DRCbce58f42019-04-12 07:49:35 -0500989 BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
DRCfc26b652014-03-16 22:56:26 +0000990
DRC19c791c2018-03-08 10:55:20 -0600991 if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
992 &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
DRC33011752019-04-12 08:47:28 -0500993 pitch, height, pf, flags) == -1) {
994 RELEASE_ARRAYS_DECODEYUV();
DRCbce58f42019-04-12 07:49:35 -0500995 THROW_TJ();
DRC33011752019-04-12 08:47:28 -0500996 }
DRCfc26b652014-03-16 22:56:26 +0000997
DRC19c791c2018-03-08 10:55:20 -0600998bailout:
DRC33011752019-04-12 08:47:28 -0500999 RELEASE_ARRAYS_DECODEYUV();
DRCfc26b652014-03-16 22:56:26 +00001000}
1001
DRCa4940d12014-08-15 16:07:15 +00001002/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */
DRC40dd3142014-08-17 12:23:49 +00001003JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII
DRC19c791c2018-03-08 10:55:20 -06001004 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
1005 jintArray jSrcStrides, jint subsamp, jbyteArray dst, jint x, jint y,
1006 jint width, jint pitch, jint height, jint pf, jint flags)
DRC927a10d2014-08-15 13:18:58 +00001007{
DRC19c791c2018-03-08 10:55:20 -06001008 TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
1009 subsamp, dst, 1, x, y, width, pitch, height, pf,
1010 flags);
DRC927a10d2014-08-15 13:18:58 +00001011}
1012
DRCa4940d12014-08-15 16:07:15 +00001013/* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() int destination */
DRC40dd3142014-08-17 12:23:49 +00001014JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
DRC19c791c2018-03-08 10:55:20 -06001015 (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
1016 jintArray jSrcStrides, jint subsamp, jintArray dst, jint x, jint y,
1017 jint width, jint stride, jint height, jint pf, jint flags)
DRCfc26b652014-03-16 22:56:26 +00001018{
DRC19c791c2018-03-08 10:55:20 -06001019 if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
DRCbce58f42019-04-12 07:49:35 -05001020 THROW_ARG("Invalid argument in decodeYUV()");
DRC19c791c2018-03-08 10:55:20 -06001021 if (tjPixelSize[pf] != sizeof(jint))
DRCbce58f42019-04-12 07:49:35 -05001022 THROW_ARG("Pixel format must be 32-bit when decoding to an integer buffer.");
DRCfc26b652014-03-16 22:56:26 +00001023
DRC19c791c2018-03-08 10:55:20 -06001024 TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
1025 subsamp, dst, sizeof(jint), x, y, width,
1026 stride * sizeof(jint), height, pf, flags);
DRCfc26b652014-03-16 22:56:26 +00001027
DRC19c791c2018-03-08 10:55:20 -06001028bailout:
1029 return;
DRCfc26b652014-03-16 22:56:26 +00001030}
1031
DRCa4940d12014-08-15 16:07:15 +00001032/* TurboJPEG 1.2.x: TJTransformer::init() */
DRCe8573012011-03-04 10:13:59 +00001033JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
DRC19c791c2018-03-08 10:55:20 -06001034 (JNIEnv *env, jobject obj)
DRCe8573012011-03-04 10:13:59 +00001035{
DRC19c791c2018-03-08 10:55:20 -06001036 jclass cls;
1037 jfieldID fid;
1038 tjhandle handle;
DRCe8573012011-03-04 10:13:59 +00001039
DRC19c791c2018-03-08 10:55:20 -06001040 if ((handle = tjInitTransform()) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001041 THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
DRCe8573012011-03-04 10:13:59 +00001042
DRCbce58f42019-04-12 07:49:35 -05001043 BAILIF0(cls = (*env)->GetObjectClass(env, obj));
1044 BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
DRC19c791c2018-03-08 10:55:20 -06001045 (*env)->SetLongField(env, obj, fid, (size_t)handle);
DRCe8573012011-03-04 10:13:59 +00001046
DRC19c791c2018-03-08 10:55:20 -06001047bailout:
1048 return;
DRCe8573012011-03-04 10:13:59 +00001049}
1050
DRC19c791c2018-03-08 10:55:20 -06001051typedef struct _JNICustomFilterParams {
1052 JNIEnv *env;
1053 jobject tobj;
1054 jobject cfobj;
DRCf5467112011-09-20 05:02:19 +00001055} JNICustomFilterParams;
1056
1057static int JNICustomFilter(short *coeffs, tjregion arrayRegion,
DRC19c791c2018-03-08 10:55:20 -06001058 tjregion planeRegion, int componentIndex,
1059 int transformIndex, tjtransform *transform)
DRCf5467112011-09-20 05:02:19 +00001060{
DRC19c791c2018-03-08 10:55:20 -06001061 JNICustomFilterParams *params = (JNICustomFilterParams *)transform->data;
1062 JNIEnv *env = params->env;
1063 jobject tobj = params->tobj, cfobj = params->cfobj;
1064 jobject arrayRegionObj, planeRegionObj, bufobj, borobj;
1065 jclass cls;
1066 jmethodID mid;
1067 jfieldID fid;
DRCf5467112011-09-20 05:02:19 +00001068
DRCbce58f42019-04-12 07:49:35 -05001069 BAILIF0(bufobj = (*env)->NewDirectByteBuffer(env, coeffs,
DRC19c791c2018-03-08 10:55:20 -06001070 sizeof(short) * arrayRegion.w * arrayRegion.h));
DRCbce58f42019-04-12 07:49:35 -05001071 BAILIF0(cls = (*env)->FindClass(env, "java/nio/ByteOrder"));
1072 BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "nativeOrder",
DRC19c791c2018-03-08 10:55:20 -06001073 "()Ljava/nio/ByteOrder;"));
DRCbce58f42019-04-12 07:49:35 -05001074 BAILIF0(borobj = (*env)->CallStaticObjectMethod(env, cls, mid));
1075 BAILIF0(cls = (*env)->GetObjectClass(env, bufobj));
1076 BAILIF0(mid = (*env)->GetMethodID(env, cls, "order",
DRC19c791c2018-03-08 10:55:20 -06001077 "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"));
1078 (*env)->CallObjectMethod(env, bufobj, mid, borobj);
DRCbce58f42019-04-12 07:49:35 -05001079 BAILIF0(mid = (*env)->GetMethodID(env, cls, "asShortBuffer",
DRC19c791c2018-03-08 10:55:20 -06001080 "()Ljava/nio/ShortBuffer;"));
DRCbce58f42019-04-12 07:49:35 -05001081 BAILIF0(bufobj = (*env)->CallObjectMethod(env, bufobj, mid));
DRCf5467112011-09-20 05:02:19 +00001082
DRCbce58f42019-04-12 07:49:35 -05001083 BAILIF0(cls = (*env)->FindClass(env, "java/awt/Rectangle"));
1084 BAILIF0(arrayRegionObj = (*env)->AllocObject(env, cls));
1085 BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
DRC19c791c2018-03-08 10:55:20 -06001086 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.x);
DRCbce58f42019-04-12 07:49:35 -05001087 BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
DRC19c791c2018-03-08 10:55:20 -06001088 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.y);
DRCbce58f42019-04-12 07:49:35 -05001089 BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
DRC19c791c2018-03-08 10:55:20 -06001090 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.w);
DRCbce58f42019-04-12 07:49:35 -05001091 BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
DRC19c791c2018-03-08 10:55:20 -06001092 (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.h);
DRCf5467112011-09-20 05:02:19 +00001093
DRCbce58f42019-04-12 07:49:35 -05001094 BAILIF0(planeRegionObj = (*env)->AllocObject(env, cls));
1095 BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
DRC19c791c2018-03-08 10:55:20 -06001096 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.x);
DRCbce58f42019-04-12 07:49:35 -05001097 BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
DRC19c791c2018-03-08 10:55:20 -06001098 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.y);
DRCbce58f42019-04-12 07:49:35 -05001099 BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
DRC19c791c2018-03-08 10:55:20 -06001100 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.w);
DRCbce58f42019-04-12 07:49:35 -05001101 BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
DRC19c791c2018-03-08 10:55:20 -06001102 (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.h);
DRCf5467112011-09-20 05:02:19 +00001103
DRCbce58f42019-04-12 07:49:35 -05001104 BAILIF0(cls = (*env)->GetObjectClass(env, cfobj));
1105 BAILIF0(mid = (*env)->GetMethodID(env, cls, "customFilter",
DRC19c791c2018-03-08 10:55:20 -06001106 "(Ljava/nio/ShortBuffer;Ljava/awt/Rectangle;Ljava/awt/Rectangle;IILorg/libjpegturbo/turbojpeg/TJTransform;)V"));
1107 (*env)->CallVoidMethod(env, cfobj, mid, bufobj, arrayRegionObj,
1108 planeRegionObj, componentIndex, transformIndex, tobj);
DRCf5467112011-09-20 05:02:19 +00001109
DRC19c791c2018-03-08 10:55:20 -06001110 return 0;
DRCf5467112011-09-20 05:02:19 +00001111
DRC19c791c2018-03-08 10:55:20 -06001112bailout:
1113 return -1;
DRCf5467112011-09-20 05:02:19 +00001114}
1115
DRCa4940d12014-08-15 16:07:15 +00001116/* TurboJPEG 1.2.x: TJTransformer::transform() */
DRCe8573012011-03-04 10:13:59 +00001117JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
DRC19c791c2018-03-08 10:55:20 -06001118 (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize,
1119 jobjectArray dstobjs, jobjectArray tobjs, jint flags)
DRCe8573012011-03-04 10:13:59 +00001120{
DRC19c791c2018-03-08 10:55:20 -06001121 tjhandle handle = 0;
1122 unsigned char *jpegBuf = NULL, **dstBufs = NULL;
1123 jsize n = 0;
1124 unsigned long *dstSizes = NULL;
1125 tjtransform *t = NULL;
1126 jbyteArray *jdstBufs = NULL;
1127 int i, jpegWidth = 0, jpegHeight = 0, jpegSubsamp;
1128 jintArray jdstSizes = 0;
1129 jint *dstSizesi = NULL;
1130 JNICustomFilterParams *params = NULL;
DRCe8573012011-03-04 10:13:59 +00001131
DRCbce58f42019-04-12 07:49:35 -05001132 GET_HANDLE();
DRCe8573012011-03-04 10:13:59 +00001133
DRC19c791c2018-03-08 10:55:20 -06001134 if ((*env)->GetArrayLength(env, jsrcBuf) < jpegSize)
DRCbce58f42019-04-12 07:49:35 -05001135 THROW_ARG("Source buffer is not large enough");
1136 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
DRC19c791c2018-03-08 10:55:20 -06001137 jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001138 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
DRC19c791c2018-03-08 10:55:20 -06001139 jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001140 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
DRC19c791c2018-03-08 10:55:20 -06001141 jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
DRCe8573012011-03-04 10:13:59 +00001142
DRC19c791c2018-03-08 10:55:20 -06001143 n = (*env)->GetArrayLength(env, dstobjs);
1144 if (n != (*env)->GetArrayLength(env, tobjs))
DRCbce58f42019-04-12 07:49:35 -05001145 THROW_ARG("Mismatch between size of transforms array and destination buffers array");
DRCe8573012011-03-04 10:13:59 +00001146
DRC19c791c2018-03-08 10:55:20 -06001147 if ((dstBufs =
1148 (unsigned char **)malloc(sizeof(unsigned char *) * n)) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001149 THROW_MEM();
DRC19c791c2018-03-08 10:55:20 -06001150 if ((jdstBufs = (jbyteArray *)malloc(sizeof(jbyteArray) * n)) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001151 THROW_MEM();
DRC19c791c2018-03-08 10:55:20 -06001152 if ((dstSizes = (unsigned long *)malloc(sizeof(unsigned long) * n)) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001153 THROW_MEM();
DRC19c791c2018-03-08 10:55:20 -06001154 if ((t = (tjtransform *)malloc(sizeof(tjtransform) * n)) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001155 THROW_MEM();
DRC19c791c2018-03-08 10:55:20 -06001156 if ((params = (JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams) *
1157 n)) == NULL)
DRCbce58f42019-04-12 07:49:35 -05001158 THROW_MEM();
DRC19c791c2018-03-08 10:55:20 -06001159 for (i = 0; i < n; i++) {
1160 dstBufs[i] = NULL; jdstBufs[i] = NULL; dstSizes[i] = 0;
1161 memset(&t[i], 0, sizeof(tjtransform));
1162 memset(&params[i], 0, sizeof(JNICustomFilterParams));
1163 }
DRCe8573012011-03-04 10:13:59 +00001164
DRC19c791c2018-03-08 10:55:20 -06001165 for (i = 0; i < n; i++) {
1166 jobject tobj, cfobj;
DRCe8573012011-03-04 10:13:59 +00001167
DRCbce58f42019-04-12 07:49:35 -05001168 BAILIF0(tobj = (*env)->GetObjectArrayElement(env, tobjs, i));
1169 BAILIF0(_cls = (*env)->GetObjectClass(env, tobj));
1170 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "op", "I"));
DRC19c791c2018-03-08 10:55:20 -06001171 t[i].op = (*env)->GetIntField(env, tobj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001172 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "options", "I"));
DRC19c791c2018-03-08 10:55:20 -06001173 t[i].options = (*env)->GetIntField(env, tobj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001174 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "x", "I"));
DRC19c791c2018-03-08 10:55:20 -06001175 t[i].r.x = (*env)->GetIntField(env, tobj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001176 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "y", "I"));
DRC19c791c2018-03-08 10:55:20 -06001177 t[i].r.y = (*env)->GetIntField(env, tobj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001178 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "width", "I"));
DRC19c791c2018-03-08 10:55:20 -06001179 t[i].r.w = (*env)->GetIntField(env, tobj, _fid);
DRCbce58f42019-04-12 07:49:35 -05001180 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "height", "I"));
DRC19c791c2018-03-08 10:55:20 -06001181 t[i].r.h = (*env)->GetIntField(env, tobj, _fid);
DRCf5467112011-09-20 05:02:19 +00001182
DRCbce58f42019-04-12 07:49:35 -05001183 BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "cf",
DRC19c791c2018-03-08 10:55:20 -06001184 "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;"));
1185 cfobj = (*env)->GetObjectField(env, tobj, _fid);
1186 if (cfobj) {
1187 params[i].env = env;
1188 params[i].tobj = tobj;
1189 params[i].cfobj = cfobj;
1190 t[i].customFilter = JNICustomFilter;
1191 t[i].data = (void *)&params[i];
1192 }
1193 }
DRCe8573012011-03-04 10:13:59 +00001194
DRC19c791c2018-03-08 10:55:20 -06001195 for (i = 0; i < n; i++) {
1196 int w = jpegWidth, h = jpegHeight;
DRCe8573012011-03-04 10:13:59 +00001197
DRC19c791c2018-03-08 10:55:20 -06001198 if (t[i].r.w != 0) w = t[i].r.w;
1199 if (t[i].r.h != 0) h = t[i].r.h;
DRCbce58f42019-04-12 07:49:35 -05001200 BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
DRC19c791c2018-03-08 10:55:20 -06001201 if ((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) <
1202 tjBufSize(w, h, jpegSubsamp))
DRCbce58f42019-04-12 07:49:35 -05001203 THROW_ARG("Destination buffer is not large enough");
DRC19c791c2018-03-08 10:55:20 -06001204 }
DRCbce58f42019-04-12 07:49:35 -05001205 BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
DRC19c791c2018-03-08 10:55:20 -06001206 for (i = 0; i < n; i++)
DRCbce58f42019-04-12 07:49:35 -05001207 BAILIF0(dstBufs[i] =
DRC19c791c2018-03-08 10:55:20 -06001208 (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
DRC8951cf02014-08-14 16:54:04 +00001209
DRC19c791c2018-03-08 10:55:20 -06001210 if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
DRC33011752019-04-12 08:47:28 -05001211 flags | TJFLAG_NOREALLOC) == -1) {
1212 for (i = 0; i < n; i++)
1213 SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1214 SAFE_RELEASE(jsrcBuf, jpegBuf);
DRCbce58f42019-04-12 07:49:35 -05001215 THROW_TJ();
DRC19c791c2018-03-08 10:55:20 -06001216 }
DRC33011752019-04-12 08:47:28 -05001217
1218 for (i = 0; i < n; i++)
1219 SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1220 SAFE_RELEASE(jsrcBuf, jpegBuf);
DRCe8573012011-03-04 10:13:59 +00001221
DRC19c791c2018-03-08 10:55:20 -06001222 jdstSizes = (*env)->NewIntArray(env, n);
DRCbce58f42019-04-12 07:49:35 -05001223 BAILIF0(dstSizesi = (*env)->GetIntArrayElements(env, jdstSizes, 0));
DRC19c791c2018-03-08 10:55:20 -06001224 for (i = 0; i < n; i++) dstSizesi[i] = (int)dstSizes[i];
1225
1226bailout:
1227 if (dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0);
1228 if (dstBufs) {
1229 for (i = 0; i < n; i++) {
1230 if (dstBufs[i] && jdstBufs && jdstBufs[i])
1231 (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
1232 }
1233 free(dstBufs);
1234 }
DRC33011752019-04-12 08:47:28 -05001235 SAFE_RELEASE(jsrcBuf, jpegBuf);
DRC19c791c2018-03-08 10:55:20 -06001236 if (jdstBufs) free(jdstBufs);
1237 if (dstSizes) free(dstSizes);
1238 if (t) free(t);
1239 return jdstSizes;
DRCe8573012011-03-04 10:13:59 +00001240}
1241
DRCa4940d12014-08-15 16:07:15 +00001242/* TurboJPEG 1.2.x: TJDecompressor::destroy() */
DRCc5a41992011-02-08 06:54:36 +00001243JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
DRC19c791c2018-03-08 10:55:20 -06001244 (JNIEnv *env, jobject obj)
DRCf8e00552011-02-04 11:06:36 +00001245{
DRC19c791c2018-03-08 10:55:20 -06001246 Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj);
DRCf8e00552011-02-04 11:06:36 +00001247}