mirror of
https://github.com/libjpeg-turbo/libjpeg-turbo.git
synced 2026-01-18 21:41:20 +01:00
Don't ignore JPEG buf size with TJPARAM_NOREALLOC
Since the introduction of TJFLAG_NOREALLOC in libjpeg-turbo 1.2.x, the TurboJPEG C API documentation has (confusingly) stated that: - if the JPEG buffer pointer points to a pre-allocated buffer, then the JPEG buffer size must be specified, and - the JPEG buffer size should be specified if the JPEG buffer is pre-allocated to an arbitrary size. The documentation never explicitly stated that the JPEG buffer size should be specified if the JPEG buffer is pre-allocated to a worst-case size, but since focus does not imply exclusion, it also never explicitly stated the reverse. Furthermore, the documentation never stated that this was contingent upon TJPARAM_NOREALLOC/TJFLAG_NOREALLOC. However, effectively the compression and lossless transformation functions ignored the JPEG buffer size(s) passed to them, and assumed that the JPEG buffer(s) had been allocated to a worst-case size, if TJPARAM_NOREALLOC/TJFLAG_NOREALLOC was set. This behavior was an accidental and undocumented throwback to libjpeg-turbo 1.1.x, in which the tjCompress() function provided no way to specify the JPEG buffer size. It was always a bad idea for applications to rely upon that behavior (although our own TJBench application unfortunately did.) However, if such applications exist in the wild, the new behavior would constitute a breaking change, so it has been introduced only into libjpeg-turbo 3.1.x and only into TurboJPEG 3 API functions. The previous behavior has been retained when calling functions from the TurboJPEG 2.1.x API and prior versions. Did I mention that APIs are hard?
This commit is contained in:
@@ -673,8 +673,7 @@ final class TJBench {
|
||||
tntilesh = (th + ttileh - 1) / ttileh;
|
||||
|
||||
TJTransform[] t = new TJTransform[tntilesw * tntilesh];
|
||||
jpegBufs =
|
||||
new byte[tntilesw * tntilesh][TJ.bufSize(ttilew, ttileh, tsubsamp)];
|
||||
jpegBufs = new byte[tntilesw * tntilesh][];
|
||||
|
||||
for (y = 0, tile = 0; y < th; y += ttileh) {
|
||||
for (x = 0; x < tw; x += ttilew, tile++) {
|
||||
@@ -686,9 +685,9 @@ final class TJBench {
|
||||
t[tile].op = xformOp;
|
||||
t[tile].options = xformOpt | TJTransform.OPT_TRIM;
|
||||
t[tile].cf = customFilter;
|
||||
if ((t[tile].options & TJTransform.OPT_NOOUTPUT) != 0 &&
|
||||
jpegBufs[tile] != null)
|
||||
jpegBufs[tile] = null;
|
||||
if ((t[tile].options & TJTransform.OPT_NOOUTPUT) == 0)
|
||||
jpegBufs[tile] =
|
||||
new byte[TJ.bufSize(t[tile].width, t[tile].height, tsubsamp)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -237,15 +237,13 @@ static jint TJCompressor_compress
|
||||
jpegSubsamp = TJSAMP_444;
|
||||
else if (jpegSubsamp == TJSAMP_UNKNOWN)
|
||||
THROW_ARG("TJPARAM_SUBSAMP must be specified");
|
||||
jpegSize = tj3JPEGBufSize(width, height, jpegSubsamp);
|
||||
if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
|
||||
THROW_ARG("Destination buffer is not large enough");
|
||||
|
||||
if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
|
||||
THROW_TJ();
|
||||
|
||||
BAILIF0NOEC(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
|
||||
BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
|
||||
jpegSize = (*env)->GetArrayLength(env, dst);
|
||||
|
||||
if (precision == 8) {
|
||||
if (tj3Compress8(handle, &((unsigned char *)srcBuf)[y * actualPitch +
|
||||
@@ -353,10 +351,6 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
|
||||
if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
|
||||
THROW_ARG("Strides array is too small for the subsampling type");
|
||||
|
||||
jpegSize = tj3JPEGBufSize(width, height, subsamp);
|
||||
if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
|
||||
THROW_ARG("Destination buffer is not large enough");
|
||||
|
||||
if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
|
||||
THROW_TJ();
|
||||
|
||||
@@ -396,6 +390,7 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFrom
|
||||
srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
|
||||
}
|
||||
BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
|
||||
jpegSize = (*env)->GetArrayLength(env, dst);
|
||||
|
||||
if (tj3CompressFromYUVPlanes8(handle, srcPlanes, width, srcStrides, height,
|
||||
&jpegBuf, &jpegSize) == -1) {
|
||||
@@ -1141,7 +1136,7 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
|
||||
size_t *dstSizes = NULL;
|
||||
tjtransform *t = NULL;
|
||||
jbyteArray *jdstBufs = NULL;
|
||||
int i, jpegWidth = 0, jpegHeight = 0, srcSubsamp;
|
||||
int i, jpegWidth = 0, jpegHeight = 0;
|
||||
jintArray jdstSizes = 0;
|
||||
jint *dstSizesi = NULL;
|
||||
JNICustomFilterParams *params = NULL;
|
||||
@@ -1154,7 +1149,6 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
|
||||
THROW_ARG("JPEG header has not yet been read");
|
||||
if ((jpegHeight = tj3Get(handle, TJPARAM_JPEGHEIGHT)) == -1)
|
||||
THROW_ARG("JPEG header has not yet been read");
|
||||
srcSubsamp = tj3Get(handle, TJPARAM_SUBSAMP);
|
||||
|
||||
n = (*env)->GetArrayLength(env, dstobjs);
|
||||
if (n != (*env)->GetArrayLength(env, tobjs))
|
||||
@@ -1211,29 +1205,13 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
|
||||
if (tj3Set(handle, TJPARAM_NOREALLOC, 1) == -1)
|
||||
THROW_TJ();
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
int w = jpegWidth, h = jpegHeight;
|
||||
int dstSubsamp = (t[i].options & TJXOPT_GRAY) ? TJSAMP_GRAY : srcSubsamp;
|
||||
|
||||
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
|
||||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
|
||||
w = jpegHeight; h = jpegWidth;
|
||||
if (dstSubsamp == TJSAMP_422) dstSubsamp = TJSAMP_440;
|
||||
else if (dstSubsamp == TJSAMP_440) dstSubsamp = TJSAMP_422;
|
||||
else if (dstSubsamp == TJSAMP_411) dstSubsamp = TJSAMP_441;
|
||||
else if (dstSubsamp == TJSAMP_441) dstSubsamp = TJSAMP_411;
|
||||
}
|
||||
if (t[i].r.w != 0) w = t[i].r.w;
|
||||
if (t[i].r.h != 0) h = t[i].r.h;
|
||||
BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
|
||||
if ((size_t)(*env)->GetArrayLength(env, jdstBufs[i]) <
|
||||
tj3JPEGBufSize(w, h, dstSubsamp))
|
||||
THROW_ARG("Destination buffer is not large enough");
|
||||
}
|
||||
BAILIF0NOEC(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
|
||||
for (i = 0; i < n; i++)
|
||||
for (i = 0; i < n; i++) {
|
||||
BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
|
||||
BAILIF0NOEC(dstBufs[i] =
|
||||
(*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
|
||||
dstSizes[i] = (*env)->GetArrayLength(env, jdstBufs[i]);
|
||||
}
|
||||
|
||||
if (tj3Transform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t) == -1) {
|
||||
for (i = 0; i < n; i++)
|
||||
|
||||
Reference in New Issue
Block a user