Fix an issue that prevented tjEncodeYUV2() and TJCompressor.encodeYUV() from working properly if the source image was very tiny. Basically, jpeg_start_compress() was attempting to write the JPEG headers, which was overrunning the YUV buffer. This patch removes the call to jpeg_start_compress() in tjEncodeYUV2() and replaces it with calls to the individual routines that are necessary to initialize the color converter and downsampler. TJUnitTest has also been modified to test for this condition (the buffer size regression test now works in YUV mode.)
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/branches/1.2.x@1121 632fc199-4ca6-4c93-a231-07263d6284db
diff --git a/ChangeLog.txt b/ChangeLog.txt
index 9d5ae8d..8027ec8 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -23,6 +23,10 @@
[6] Fixed a couple of issues whereby malformed JPEG images would cause
libjpeg-turbo to use uninitialized memory during decompression.
+[7] Fixed an error ("Buffer passed to JPEG library is too small") that occurred
+when calling the TurboJPEG YUV encoding function with a very small (< 5x5)
+source image, and added a unit test to check for this error.
+
1.2.1
=====
diff --git a/java/TJUnitTest.java b/java/TJUnitTest.java
index b88b28e..eaebf20 100644
--- a/java/TJUnitTest.java
+++ b/java/TJUnitTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2011-2012 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2011-2012, 2014 D. R. Commander.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -794,7 +794,7 @@
private static void bufSizeTest() throws Exception {
int w, h, i, subsamp;
- byte[] srcBuf, jpegBuf;
+ byte[] srcBuf, dstBuf;
TJCompressor tjc = null;
Random r = new Random();
@@ -808,22 +808,34 @@
if(h % 100 == 0)
System.out.format("%04d x %04d\b\b\b\b\b\b\b\b\b\b\b", w, h);
srcBuf = new byte[w * h * 4];
- jpegBuf = new byte[TJ.bufSize(w, h, subsamp)];
+ if (yuv == YUVENCODE)
+ dstBuf = new byte[TJ.bufSizeYUV(w, h, subsamp)];
+ else
+ dstBuf = new byte[TJ.bufSize(w, h, subsamp)];
for(i = 0; i < w * h * 4; i++) {
srcBuf[i] = (byte)(r.nextInt(2) * 255);
}
tjc.setSourceImage(srcBuf, w, 0, h, TJ.PF_BGRX);
tjc.setSubsamp(subsamp);
tjc.setJPEGQuality(100);
- tjc.compress(jpegBuf, 0);
+ if (yuv == YUVENCODE)
+ tjc.encodeYUV(dstBuf, 0);
+ else
+ tjc.compress(dstBuf, 0);
srcBuf = new byte[h * w * 4];
- jpegBuf = new byte[TJ.bufSize(h, w, subsamp)];
+ if (yuv == YUVENCODE)
+ dstBuf = new byte[TJ.bufSizeYUV(h, w, subsamp)];
+ else
+ dstBuf = new byte[TJ.bufSize(h, w, subsamp)];
for(i = 0; i < h * w * 4; i++) {
srcBuf[i] = (byte)(r.nextInt(2) * 255);
}
tjc.setSourceImage(srcBuf, h, 0, w, TJ.PF_BGRX);
- tjc.compress(jpegBuf, 0);
+ if (yuv == YUVENCODE)
+ tjc.encodeYUV(dstBuf, 0);
+ else
+ tjc.compress(dstBuf, 0);
}
}
}
@@ -870,8 +882,10 @@
testName);
doTest(41, 35, bi ? _4byteFormatsBI : _4byteFormats, TJ.SAMP_GRAY,
testName);
- if(!doyuv && !bi) bufSizeTest();
- if(doyuv && !bi) {
+ if(!bi)
+ bufSizeTest();
+ if (doyuv && !bi) {
+ System.out.print("\n\n");
yuv = YUVDECODE;
doTest(48, 48, onlyRGB, TJ.SAMP_444, "javatest_yuv0");
doTest(35, 39, onlyRGB, TJ.SAMP_444, "javatest_yuv1");
diff --git a/jversion.h b/jversion.h
index 88c2566..0e3db28 100644
--- a/jversion.h
+++ b/jversion.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2010, Thomas G. Lane, Guido Vollbeding.
* Modifications:
- * Copyright (C) 2010, 2012, D. R. Commander.
+ * Copyright (C) 2010, 2012-2014, D. R. Commander.
* For conditions of distribution and use, see the accompanying README file.
*
* This file contains software version identification.
@@ -28,5 +28,5 @@
#define JCOPYRIGHT "Copyright (C) 1991-2010 Thomas G. Lane, Guido Vollbeding\n" \
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
"Copyright (C) 2009 Pierre Ossman for Cendio AB\n" \
- "Copyright (C) 2009-2012 D. R. Commander\n" \
+ "Copyright (C) 2009-2014 D. R. Commander\n" \
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)"
diff --git a/tjunittest.c b/tjunittest.c
index 89a6d1d..a61d266 100644
--- a/tjunittest.c
+++ b/tjunittest.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2009-2012, 2014 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -531,9 +531,9 @@
void bufSizeTest(void)
{
int w, h, i, subsamp;
- unsigned char *srcBuf=NULL, *jpegBuf=NULL;
+ unsigned char *srcBuf=NULL, *dstBuf=NULL;
tjhandle handle=NULL;
- unsigned long jpegSize=0;
+ unsigned long dstSize=0;
if((handle=tjInitCompress())==NULL) _throwtj();
@@ -548,12 +548,12 @@
if(h%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", w, h);
if((srcBuf=(unsigned char *)malloc(w*h*4))==NULL)
_throw("Memory allocation failure");
- if(!alloc)
+ if(!alloc || yuv==YUVENCODE)
{
- if((jpegBuf=(unsigned char *)tjAlloc(tjBufSize(w, h, subsamp)))
- ==NULL)
+ if(yuv==YUVENCODE) dstSize=tjBufSizeYUV(w, h, subsamp);
+ else dstSize=tjBufSize(w, h, subsamp);
+ if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
_throw("Memory allocation failure");
- jpegSize=tjBufSize(w, h, subsamp);
}
for(i=0; i<w*h*4; i++)
@@ -562,19 +562,27 @@
else srcBuf[i]=255;
}
- _tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &jpegBuf,
- &jpegSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
+ if(yuv==YUVENCODE)
+ {
+ _tj(tjEncodeYUV2(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, subsamp,
+ 0));
+ }
+ else
+ {
+ _tj(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
+ &dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
+ }
free(srcBuf); srcBuf=NULL;
- tjFree(jpegBuf); jpegBuf=NULL;
+ tjFree(dstBuf); dstBuf=NULL;
if((srcBuf=(unsigned char *)malloc(h*w*4))==NULL)
_throw("Memory allocation failure");
- if(!alloc)
+ if(!alloc || yuv==YUVENCODE)
{
- if((jpegBuf=(unsigned char *)tjAlloc(tjBufSize(h, w, subsamp)))
- ==NULL)
+ if(yuv==YUVENCODE) dstSize=tjBufSizeYUV(h, w, subsamp);
+ else dstSize=tjBufSize(h, w, subsamp);
+ if((dstBuf=(unsigned char *)tjAlloc(dstSize))==NULL)
_throw("Memory allocation failure");
- jpegSize=tjBufSize(h, w, subsamp);
}
for(i=0; i<h*w*4; i++)
@@ -583,10 +591,18 @@
else srcBuf[i]=255;
}
- _tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &jpegBuf,
- &jpegSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
+ if(yuv==YUVENCODE)
+ {
+ _tj(tjEncodeYUV2(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, subsamp,
+ 0));
+ }
+ else
+ {
+ _tj(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
+ &dstSize, subsamp, 100, alloc? 0:TJFLAG_NOREALLOC));
+ }
free(srcBuf); srcBuf=NULL;
- tjFree(jpegBuf); jpegBuf=NULL;
+ tjFree(dstBuf); dstBuf=NULL;
}
}
}
@@ -594,7 +610,7 @@
bailout:
if(srcBuf) free(srcBuf);
- if(jpegBuf) free(jpegBuf);
+ if(dstBuf) free(dstBuf);
if(handle) tjDestroy(handle);
}
@@ -628,9 +644,10 @@
doTest(35, 39, _onlyGray, 1, TJSAMP_GRAY, "test");
doTest(39, 41, _3byteFormats, 2, TJSAMP_GRAY, "test");
doTest(41, 35, _4byteFormats, 4, TJSAMP_GRAY, "test");
- if(!doyuv) bufSizeTest();
+ bufSizeTest();
if(doyuv)
{
+ printf("\n\n");
yuv=YUVDECODE;
doTest(48, 48, _onlyRGB, 1, TJSAMP_444, "test_yuv0");
doTest(35, 39, _onlyRGB, 1, TJSAMP_444, "test_yuv1");
diff --git a/turbojpeg.c b/turbojpeg.c
index 2089cbe..50fb1e3 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2009-2012 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2009-2012, 2014 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -538,7 +538,20 @@
jpeg_mem_dest_tj(cinfo, &dstBuf, &yuvsize, 0);
if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1;
- jpeg_start_compress(cinfo, TRUE);
+ /* Execute only the parts of jpeg_start_compress() that we need. If we
+ were to call the whole jpeg_start_compress() function, then it would try
+ to write the file headers, which could overflow the output buffer if the
+ YUV image were very small. */
+ if(cinfo->global_state!=CSTATE_START)
+ _throw("tjEncodeYUV3(): libjpeg API is in the wrong state");
+ (*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo);
+ (*cinfo->dest->init_destination)(cinfo);
+ jinit_c_master_control(cinfo, FALSE);
+ jinit_color_converter(cinfo);
+ jinit_downsampler(cinfo);
+ jinit_c_prep_controller(cinfo, FALSE);
+ (*cinfo->mem->realize_virt_arrays)((j_common_ptr)cinfo);
+
pw=PAD(width, cinfo->max_h_samp_factor);
ph=PAD(height, cinfo->max_v_samp_factor);