tjGetScaledSize() would never be able to accommodate scaling factors > 1, so replace it with a function that returns a list of fractional scaling factors that TurboJPEG supports.

This commit is contained in:
DRC
2011-03-01 09:53:07 +00:00
parent da6a1f6c76
commit be085e08b3
12 changed files with 269 additions and 262 deletions

View File

@@ -253,14 +253,14 @@ public class TJUnitTest {
}
private static int checkbuf(byte [] buf, int w, int pitch, int h, int pf,
int subsamp, int scalefactor, int flags) throws Exception
int subsamp, int scale_num, int scale_denom, int flags) throws Exception
{
int roffset=TJ.getRedShift(pf)/8;
int goffset=TJ.getGreenShift(pf)/8;
int boffset=TJ.getBlueShift(pf)/8;
int ps=TJ.getPixelSize(pf);
int i, _i, j, retval=1;
int halfway=16/scalefactor, blocksize=8/scalefactor;
int halfway=16*scale_num/scale_denom, blocksize=8*scale_num/scale_denom;
try
{
@@ -350,13 +350,13 @@ public class TJUnitTest {
}
private static int checkintbuf(int [] buf, int w, int pitch, int h, int pf,
int subsamp, int scalefactor, int flags) throws Exception
int subsamp, int scale_num, int scale_denom, int flags) throws Exception
{
int rshift=TJ.getRedShift(pf);
int gshift=TJ.getGreenShift(pf);
int bshift=TJ.getBlueShift(pf);
int i, _i, j, retval=1;
int halfway=16/scalefactor, blocksize=8/scalefactor;
int halfway=16*scale_num/scale_denom, blocksize=8*scale_num/scale_denom;
try
{
@@ -448,7 +448,7 @@ public class TJUnitTest {
}
private static int checkimg(BufferedImage img, int pf,
int subsamp, int scalefactor, int flags) throws Exception
int subsamp, int scale_num, int scale_denom, int flags) throws Exception
{
WritableRaster wr=img.getRaster();
int imgtype=img.getType();
@@ -461,7 +461,7 @@ public class TJUnitTest {
DataBufferInt db=(DataBufferInt)wr.getDataBuffer();
int [] buf = db.getData();
return checkintbuf(buf, img.getWidth(), pitch, img.getHeight(), pf,
subsamp, scalefactor, flags);
subsamp, scale_num, scale_denom, flags);
}
else
{
@@ -471,7 +471,7 @@ public class TJUnitTest {
DataBufferByte db=(DataBufferByte)wr.getDataBuffer();
byte [] buf = db.getData();
return checkbuf(buf, img.getWidth(), pitch, img.getHeight(), pf, subsamp,
scalefactor, flags);
scale_num, scale_denom, flags);
}
}
@@ -681,12 +681,12 @@ public class TJUnitTest {
private static void _gentestbmp(TJDecompressor tjd, byte [] jpegbuf,
int jpegsize, int w, int h, int pf, String basefilename, int subsamp,
int flags, int scalefactor) throws Exception
int flags, int scale_num, int scale_denom) throws Exception
{
String pixformat, tempstr; int _hdrw=0, _hdrh=0, _hdrsubsamp=-1;
double t;
int scaledw=(w+scalefactor-1)/scalefactor;
int scaledh=(h+scalefactor-1)/scalefactor;
int scaledw=(w*scale_num+scale_denom-1)/scale_denom;
int scaledh=(h*scale_num+scale_denom-1)/scale_denom;
int temp1, temp2;
BufferedImage img=null; byte [] bmpbuf=null;
@@ -701,7 +701,8 @@ public class TJUnitTest {
System.out.print(pixformat+" ");
if((flags&TJ.BOTTOMUP)!=0) System.out.print("Bottom-Up ");
else System.out.print("Top-Down ");
if(scalefactor!=1) System.out.print("1/"+scalefactor+" ... ");
if(scale_num!=1 || scale_denom!=1)
System.out.print(scale_num+"/"+scale_denom+" ... ");
else System.out.print("... ");
}
@@ -728,7 +729,7 @@ public class TJUnitTest {
{
tempstr=basefilename+"_dec_"+pixformat+"_"
+(((flags&TJ.BOTTOMUP)!=0)? "BU":"TD")+"_"+_subnames[subsamp]
+"_"+scalefactor+"x"+".png";
+"_"+(double)scale_num/(double)scale_denom+"x"+".png";
File file=new File(tempstr);
ImageIO.write(img, "png", file);
}
@@ -741,9 +742,9 @@ public class TJUnitTest {
}
else
{
if((bi && checkimg(img, pf, subsamp, scalefactor, flags)==1)
if((bi && checkimg(img, pf, subsamp, scale_num, scale_denom, flags)==1)
|| (!bi && checkbuf(bmpbuf, scaledw, scaledw*TJ.getPixelSize(pf),
scaledh, pf, subsamp, scalefactor, flags)==1))
scaledh, pf, subsamp, scale_num, scale_denom, flags)==1))
System.out.print("Passed.");
else
{
@@ -760,13 +761,14 @@ public class TJUnitTest {
int i;
if((subsamp==TJ.SAMP_444 || subsamp==TJ.SAMP_GRAY) && yuv==0)
{
for(i=1; i<=8; i*=2)
TJ.ScalingFactor sf []=TJ.getScalingFactors();
for(i=0; i<sf.length; i++)
_gentestbmp(tjd, jpegbuf, jpegsize, w, h, pf, basefilename, subsamp,
flags, i);
flags, sf[i].num, sf[i].denom);
}
else
_gentestbmp(tjd, jpegbuf, jpegsize, w, h, pf, basefilename, subsamp,
flags, 1);
flags, 1, 1);
System.out.print("\n");
}

View File

@@ -30,6 +30,11 @@ package org.libjpegturbo.turbojpeg;
final public class TJ {
final public class ScalingFactor {
public int num = 1;
public int denom = 1;
};
// Chrominance subsampling options
final public static int
NUMSAMPOPT = 4,
@@ -105,6 +110,9 @@ final public class TJ {
int subsamp)
throws Exception;
public native final static ScalingFactor [] getScalingFactors()
throws Exception;
static {
System.loadLibrary("turbojpeg");
}

View File

@@ -76,8 +76,19 @@ public class TJDecompressor {
throw new Exception("JPEG buffer not initialized");
if(desiredWidth < 0 || desiredHeight < 0)
throw new Exception("Invalid argument in getScaledWidth()");
return getScaledWidth(jpegWidth, jpegHeight, desiredWidth,
desiredHeight);
TJ.ScalingFactor sf [] = TJ.getScalingFactors();
if(desiredWidth == 0) desiredWidth = jpegWidth;
if(desiredHeight == 0) desiredHeight = jpegHeight;
int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
for(int i=0; i<sf.length; i++) {
scaledWidth = (jpegWidth * sf[i].num + sf[i].denom - 1) / sf[i].denom;
scaledHeight = (jpegHeight * sf[i].num + sf[i].denom - 1) / sf[i].denom;
if(scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
break;
}
if(scaledWidth > desiredWidth || scaledHeight > desiredHeight)
throw new Exception("Could not scale down to desired image dimensions");
return scaledWidth;
}
public int getScaledHeight(int desiredWidth, int desiredHeight)
@@ -86,8 +97,19 @@ public class TJDecompressor {
throw new Exception("JPEG buffer not initialized");
if(desiredWidth < 0 || desiredHeight < 0)
throw new Exception("Invalid argument in getScaledHeight()");
return getScaledHeight(jpegWidth, jpegHeight, desiredWidth,
desiredHeight);
TJ.ScalingFactor sf [] = TJ.getScalingFactors();
if(desiredWidth == 0) desiredWidth = jpegWidth;
if(desiredHeight == 0) desiredHeight = jpegHeight;
int scaledWidth = jpegWidth, scaledHeight = jpegHeight;
for(int i=0; i<sf.length; i++) {
scaledWidth = (jpegWidth * sf[i].num + sf[i].denom - 1) / sf[i].denom;
scaledHeight = (jpegHeight * sf[i].num + sf[i].denom - 1) / sf[i].denom;
if(scaledWidth <= desiredWidth && scaledHeight <= desiredHeight)
break;
}
if(scaledWidth > desiredWidth || scaledHeight > desiredHeight)
throw new Exception("Could not scale down to desired image dimensions");
return scaledHeight;
}
public void decompress(byte [] dstBuf, int desiredWidth, int pitch,
@@ -224,12 +246,6 @@ public class TJDecompressor {
int flags)
throws Exception;
private native int getScaledWidth(int jpegWidth, int jpegHeight,
int desiredWidth, int desiredHeight) throws Exception;
private native int getScaledHeight(int jpegWidth, int jpegHeight,
int desiredWidth, int desiredHeight) throws Exception;
static {
System.loadLibrary("turbojpeg");
}

View File

@@ -61,6 +61,14 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV
(JNIEnv *, jclass, jint, jint, jint);
/*
* Class: org_libjpegturbo_turbojpeg_TJ
* Method: getScalingFactors
* Signature: ()[Lorg/libjpegturbo/turbojpeg/TJ/ScalingFactor;
*/
JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif

View File

@@ -55,22 +55,6 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress
JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV
(JNIEnv *, jobject, jbyteArray, jint, jbyteArray, jint);
/*
* Class: org_libjpegturbo_turbojpeg_TJDecompressor
* Method: getScaledWidth
* Signature: (IIII)I
*/
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_getScaledWidth
(JNIEnv *, jobject, jint, jint, jint, jint);
/*
* Class: org_libjpegturbo_turbojpeg_TJDecompressor
* Method: getScaledHeight
* Signature: (IIII)I
*/
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_getScaledHeight
(JNIEnv *, jobject, jint, jint, jint, jint);
#ifdef __cplusplus
}
#endif

226
jpegut.c
View File

@@ -103,112 +103,6 @@ void initbuf(unsigned char *buf, int w, int h, int ps, int flags)
}
}
void dumpbuf(unsigned char *buf, int w, int h, int ps, int scalefactor,
int flags)
{
int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
j;
printf("\n");
for(i=0; i<h; i++)
{
for(j=0; j<w; j++)
{
printf("%.3d/%.3d/%.3d ", buf[(w*i+j)*ps+roffset],
buf[(w*i+j)*ps+goffset], buf[(w*i+j)*ps+boffset]);
}
printf("\n");
}
}
int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp,
int scalefactor, int flags)
{
int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
_i, j;
if(flags&TJ_ALPHAFIRST) {roffset++; goffset++; boffset++;}
if(ps==1) roffset=goffset=boffset=0;
int halfway=16/scalefactor, blocksize=8/scalefactor;
if(subsamp==TJ_GRAYSCALE)
{
for(_i=0; _i<halfway; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
unsigned char r=buf[(w*i+j)*ps+roffset],
g=buf[(w*i+j)*ps+goffset],
b=buf[(w*i+j)*ps+boffset];
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(r<253 || g<253 || b<253) return 0;
}
else
{
if(r<74 || r>78 || g<74 || g>78 || b<74 || b>78) return 0;
}
}
}
for(_i=halfway; _i<h; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
unsigned char r=buf[(w*i+j)*ps+roffset],
g=buf[(w*i+j)*ps+goffset],
b=buf[(w*i+j)*ps+boffset];
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(r>2 || g>2 || b>2) return 0;
}
else
{
if(r<224 || r>228 || g<224 || g>228 || b<224 || b>228) return 0;
}
}
}
}
else
{
for(_i=0; _i<halfway; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
if(buf[(w*i+j)*ps+roffset]<253) return 0;
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(buf[(w*i+j)*ps+goffset]<253) return 0;
if(buf[(w*i+j)*ps+boffset]<253) return 0;
}
else
{
if(buf[(w*i+j)*ps+goffset]>2) return 0;
if(buf[(w*i+j)*ps+boffset]>2) return 0;
}
}
}
for(_i=halfway; _i<h; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
if(buf[(w*i+j)*ps+boffset]>2) return 0;
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(buf[(w*i+j)*ps+roffset]>2) return 0;
if(buf[(w*i+j)*ps+goffset]>2) return 0;
}
else
{
if(buf[(w*i+j)*ps+roffset]<253) return 0;
if(buf[(w*i+j)*ps+goffset]<253) return 0;
}
}
}
}
return 1;
}
#define checkval(v, cv) { \
if(v<cv-1 || v>cv+1) { \
printf("\nComp. %s at %d,%d should be %d, not %d\n", #v, i, j, cv, v); \
@@ -227,6 +121,83 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp,
retval=0; goto bailout; \
}}
int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp,
int scale_num, int scale_denom, int flags)
{
int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
_i, j, retval=1;
if(flags&TJ_ALPHAFIRST) {roffset++; goffset++; boffset++;}
if(ps==1) roffset=goffset=boffset=0;
int halfway=16*scale_num/scale_denom, blocksize=8*scale_num/scale_denom;
for(_i=0; _i<halfway; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
unsigned char r=buf[(w*i+j)*ps+roffset],
g=buf[(w*i+j)*ps+goffset],
b=buf[(w*i+j)*ps+boffset];
if(((_i/blocksize)+(j/blocksize))%2==0)
{
checkval255(r); checkval255(g); checkval255(b);
}
else
{
if(subsamp==TJ_GRAYSCALE)
{
checkval(r, 76); checkval(g, 76); checkval(b, 76);
}
else
{
checkval255(r); checkval0(g); checkval0(b);
}
}
}
}
for(_i=halfway; _i<h; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
{
unsigned char r=buf[(w*i+j)*ps+roffset],
g=buf[(w*i+j)*ps+goffset],
b=buf[(w*i+j)*ps+boffset];
if(((_i/blocksize)+(j/blocksize))%2==0)
{
checkval0(r); checkval0(g); checkval0(b);
}
else
{
if(subsamp==TJ_GRAYSCALE)
{
checkval(r, 226); checkval(g, 226); checkval(b, 226);
}
else
{
checkval255(r); checkval255(g); checkval0(b);
}
}
}
}
bailout:
if(retval==0)
{
printf("\n");
for(i=0; i<h; i++)
{
for(j=0; j<w; j++)
{
printf("%.3d/%.3d/%.3d ", buf[(w*i+j)*ps+roffset],
buf[(w*i+j)*ps+goffset], buf[(w*i+j)*ps+boffset]);
}
printf("\n");
}
}
return retval;
}
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
int checkbufyuv(unsigned char *buf, int w, int h, int subsamp)
@@ -405,12 +376,12 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int flags,
int scalefactor)
int scale_num, int scale_denom)
{
unsigned char *bmpbuf=NULL;
const char *pixformat; int _hdrw=0, _hdrh=0, _hdrsubsamp=-1; double t;
int scaledw=(w+scalefactor-1)/scalefactor, scaledh=(h+scalefactor-1)/scalefactor;
int temp1, temp2;
int scaledw=(w*scale_num+scale_denom-1)/scale_denom;
int scaledh=(h*scale_num+scale_denom-1)/scale_denom;
unsigned long size=0;
if(yuv==YUVENCODE) return;
@@ -432,7 +403,8 @@ void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
{
printf("JPEG -> %s %s ", pixformat,
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
if(scalefactor) printf("1/%d ... ", scalefactor);
if(scale_num!=1 || scale_denom!=1)
printf("%d/%d ... ", scale_num, scale_denom);
else printf("... ");
}
@@ -443,13 +415,6 @@ void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
printf("Incorrect JPEG header\n"); bailout();
}
temp1=scaledw; temp2=scaledh;
_catch(tjGetScaledSize(w, h, &temp1, &temp2));
if(temp1!=scaledw || temp2!=scaledh)
{
printf("Scaled size mismatch\n"); bailout();
}
if(yuv==YUVDECODE) size=TJBUFSIZEYUV(w, h, subsamp);
else size=scaledw*scaledh*ps+1;
if((bmpbuf=(unsigned char *)malloc(size))==NULL)
@@ -477,13 +442,9 @@ void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
}
else
{
if(checkbuf(bmpbuf, scaledw, scaledh, ps, subsamp, scalefactor, flags))
printf("Passed.");
else
{
printf("FAILED!"); exitstatus=-1;
dumpbuf(bmpbuf, scaledw, scaledh, ps, scalefactor, flags);
}
if(checkbuf(bmpbuf, scaledw, scaledh, ps, subsamp, scale_num, scale_denom,
flags)) printf("Passed.");
else {printf("FAILED!"); exitstatus=-1;}
}
printf(" %f ms\n", t*1000.);
@@ -494,16 +455,25 @@ void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int flags)
{
int i;
int i, n=0;
tjscalingfactor *sf=tjGetScalingFactors(&n);
if(!sf || !n)
{
printf("Error in tjGetScalingFactors():\n%s\n", tjGetErrorStr());
bailout();
}
if((subsamp==TJ_444 || subsamp==TJ_GRAYSCALE) && !yuv)
{
for(i=1; i<=8; i*=2)
for(i=0; i<n; i++)
_gentestbmp(hnd, jpegbuf, jpegsize, w, h, ps, basefilename, subsamp,
flags, i);
flags, sf[i].num, sf[i].denom);
}
else
_gentestbmp(hnd, jpegbuf, jpegsize, w, h, ps, basefilename, subsamp,
flags, 1);
flags, 1, 1);
finally:
printf("\n");
}

View File

@@ -34,7 +34,7 @@
enum {YUVENCODE=1, YUVDECODE};
int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
decomponly=0, yuv=0, quiet=0, dotile=0, pf=BMP_BGR, bu=0, useppm=0,
scalefactor=1;
scale_num=1, scale_denom=1;
const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
@@ -44,6 +44,7 @@ const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"};
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
tjscalingfactor *sf=NULL; int nsf=0;
void printsigfig(double val, int figs)
{
@@ -77,8 +78,8 @@ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
double start, elapsed;
int ps=_ps[pf];
int yuvsize=TJBUFSIZEYUV(w, h, jpegsub), bufsize;
int scaledw=(yuv==YUVDECODE)? w : (w+scalefactor-1)/scalefactor;
int scaledh=(yuv==YUVDECODE)? h : (h+scalefactor-1)/scalefactor;
int scaledw=(yuv==YUVDECODE)? w : (w*scale_num+scale_denom-1)/scale_denom;
int scaledh=(yuv==YUVDECODE)? h : (h*scale_num+scale_denom-1)/scale_denom;
int pitch=scaledw*ps;
if(qual>0)
@@ -172,7 +173,7 @@ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
if(savebmp(tempstr, rgbbuf, scaledw, scaledh, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
if(srcbuf && scalefactor==1)
if(srcbuf && scale_num==1 && scale_denom==1)
{
if(!quiet)
printf("Computing compression error and saving to %s.\n", tempstr);
@@ -533,8 +534,9 @@ void dodecomptest(char *filename)
printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
bu?"Bottom-up":"Top-down");
printf("\nImage size: %d x %d", w, h);
if(scalefactor!=1) printf(" --> %d x %d", (w+scalefactor-1)/scalefactor,
(h+scalefactor-1)/scalefactor);
if(scale_num!=1 || scale_denom!=1)
printf(" --> %d x %d", (w*scale_num+scale_denom-1)/scale_denom,
(h*scale_num+scale_denom-1)/scale_denom);
printf("\n");
}
@@ -559,6 +561,7 @@ void dodecomptest(char *filename)
void usage(char *progname)
{
int i;
printf("USAGE: %s\n", progname);
printf(" <Inputfile (BMP|PPM)> <%% Quality> [options]\n\n");
printf(" %s\n", progname);
@@ -575,8 +578,19 @@ void usage(char *progname)
printf("-quiet = Output results in tabular rather than verbose format\n");
printf("-yuvencode = Encode RGB input as planar YUV rather than compressing as JPEG\n");
printf("-yuvdecode = Decode JPEG image to planar YUV rather than RGB\n");
printf("-scale 1/N = scale down the width/height of the decompressed JPEG image by a\n");
printf(" factor of N (N = 1, 2, 4, or 8}\n\n");
printf("-scale M/N = scale down the width/height of the decompressed JPEG image by a\n");
printf(" factor of M/N (M/N = ");
for(i=0; i<nsf; i++)
{
printf("%d/%d", sf[i].num, sf[i].denom);
if(nsf==2 && i!=nsf-1) printf(" or ");
else if(nsf>2)
{
if(i!=nsf-1) printf(", ");
if(i==nsf-2) printf("or ");
}
}
printf(")\n\n");
printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
printf("test will be performed for all quality values in the range.\n\n");
exit(1);
@@ -585,10 +599,13 @@ void usage(char *progname)
int main(int argc, char *argv[])
{
unsigned char *bmpbuf=NULL; int w, h, i;
unsigned char *bmpbuf=NULL; int w, h, i, j;
int qual=-1, hiqual=-1; char *temp;
int minarg=2;
if((sf=tjGetScalingFactors(&nsf))==NULL || nsf==0)
_throwtj("executing tjGetScalingFactors()");
if(argc<minarg) usage(argv[0]);
temp=strrchr(argv[1], '.');
@@ -673,16 +690,25 @@ int main(int argc, char *argv[])
if(!stricmp(argv[i], "-qq")) quiet=2;
if(!stricmp(argv[i], "-scale") && i<argc-1)
{
int temp1=0, temp2=0;
if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)!=2
|| temp1!=1 || temp2<1 || temp2>8 || (temp2&(temp2-1))!=0)
usage(argv[0]);
scalefactor=temp2;
int temp1=0, temp2=0, match=0;
if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2)
{
for(j=0; j<nsf; j++)
{
if(temp1==sf[j].num && temp2==sf[j].denom)
{
scale_num=temp1; scale_denom=temp2;
match=1; break;
}
}
if(!match) usage(argv[0]);
}
else usage(argv[0]);
}
}
}
if(scalefactor!=1 && dotile)
if((scale_num!=1 || scale_denom!=1) && dotile)
{
printf("Disabling tiled compression/decompression tests, because these tests do not\n");
printf("work when scaled decompression is enabled.\n");
@@ -723,7 +749,10 @@ int main(int argc, char *argv[])
dotest(bmpbuf, w, h, TJ_444, i, argv[1]);
printf("\n");
bailout:
if(bmpbuf) free(bmpbuf);
return 0;
bailout:
if(bmpbuf) free(bmpbuf);
return 1;
}

View File

@@ -253,28 +253,32 @@ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
return;
}
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_getScaledWidth
(JNIEnv *env, jobject obj, jint input_width, jint input_height,
jint output_width, jint output_height)
JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
(JNIEnv *env, jclass cls)
{
if(tjGetScaledSize(input_width, input_height, &output_width, &output_height)
==-1)
jclass sfcls=NULL; jfieldID fid=0;
tjscalingfactor *sf=NULL; int n=0, i;
jobject sfobj=NULL;
jobjectArray sfjava=NULL;
if((sf=tjGetScalingFactors(&n))==NULL || n==0)
_throw(tjGetErrorStr());
bailout:
return output_width;
}
bailif0(sfcls=(*env)->FindClass(env, "org/libjpegturbo/turbojpeg/TJ$ScalingFactor"));
bailif0(sfjava=(jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_getScaledHeight
(JNIEnv *env, jobject obj, jint input_width, jint input_height,
jint output_width, jint output_height)
{
if(tjGetScaledSize(input_width, input_height, &output_width, &output_height)
==-1)
_throw(tjGetErrorStr());
for(i=0; i<n; i++)
{
bailif0(sfobj=(*env)->AllocObject(env, sfcls));
bailif0(fid=(*env)->GetFieldID(env, sfcls, "num", "I"));
(*env)->SetIntField(env, sfobj, fid, sf[i].num);
bailif0(fid=(*env)->GetFieldID(env, sfcls, "denom", "I"));
(*env)->SetIntField(env, sfobj, fid, sf[i].denom);
(*env)->SetObjectArrayElement(env, sfjava, i, sfobj);
}
bailout:
return output_height;
return sfjava;
}
JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader

View File

@@ -25,7 +25,7 @@ TURBOJPEG_1.1
TURBOJPEG_1.2
{
global:
tjGetScaledSize;
tjGetScalingFactors;
tjInitTransform;
tjTransform;
} TURBOJPEG_1.1;

View File

@@ -25,7 +25,7 @@ TURBOJPEG_1.1
TURBOJPEG_1.2
{
global:
tjGetScaledSize;
tjGetScalingFactors;
tjInitTransform;
tjTransform;
Java_org_libjpegturbo_turbojpeg_TJ_bufSize;

View File

@@ -56,6 +56,12 @@ enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE};
#define TJ_YUV 512
/* Nothing to see here. Pay no attention to the man behind the curtain. */
/* Scaling factor structure */
typedef struct
{
int num, denom;
} tjscalingfactor;
/* Transform operations for tjTransform() */
#define NUMXFORMOPT 8
@@ -299,23 +305,16 @@ DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
/*
int tjGetScaledSize(int input_width, int input_height,
int *output_width, int *output_height)
tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
[INPUT] input_width = width (in pixels) of the JPEG image
[INPUT] input_height = height (in pixels) of the JPEG image
[INPUT/OUTPUT] output_width, output_height = Before calling this function,
*output_width and *output_height should be set to the desired dimensions
of the output image. Upon returning from this function, they will be set
to the dimensions of the largest scaled down image that TurboJPEG can
produce without exceeding the desired dimensions. If either *output_width
or *output_height is set to 0, then the corresponding dimension will not
be considered when determining the scaled image size.
Returns a list of fractional scaling factors that the JPEG decompressor in
this implementation of TurboJPEG supports.
RETURNS: 0 on success, -1 if arguments are out of bounds
[OUTPUT] numscalingfactors = the size of the list
RETURNS: NULL on error
*/
DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
int *output_width, int *output_height);
DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors);
/*
@@ -331,10 +330,10 @@ DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
[INPUT] size = size of the JPEG image buffer (in bytes)
[INPUT] dstbuf = pointer to user-allocated image buffer which will receive
the bitmap image. This buffer should normally be pitch*scaled_height
bytes in size, where scaled_height is determined by calling
tjGetScaledSize() with the height of the desired output image. This
pointer may also be used to decompress into a specific region of a
larger buffer.
bytes in size, where scaled_height is ceil(jpeg_height*scaling_factor),
and the supported scaling factors can be determined by calling
tjGetScalingFactors(). The dstbuf pointer may also be used to decompress
into a specific region of a larger buffer.
[INPUT] width = desired width (in pixels) of the destination image. If this
is smaller than the width of the JPEG image being decompressed, then
TurboJPEG will use scaling in the JPEG decompressor to generate the
@@ -345,10 +344,9 @@ DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
scaled_width*pixelsize if the bitmap image is unpadded, else
TJPAD(scaled_width*pixelsize) if each line of the bitmap is padded to the
nearest 32-bit boundary, such as is the case for Windows bitmaps.
(NOTE: scaled_width can be determined by calling tjGetScaledSize().) You
can also be clever and use this parameter to skip lines, etc. Setting
this parameter to 0 is the equivalent of setting it to
scaled_width*pixelsize.
(NOTE: scaled_width = ceil(jpeg_width*scaling_factor).) You can also be
clever and use this parameter to skip lines, etc. Setting this parameter
to 0 is the equivalent of setting it to scaled_width*pixelsize.
[INPUT] height = desired height (in pixels) of the destination image. If
this is smaller than the height of the JPEG image being decompressed, then
TurboJPEG will use scaling in the JPEG decompressor to generate the

View File

@@ -74,6 +74,13 @@ static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
};
#define NUMSF 4
static const tjscalingfactor sf[NUMSF]={
{1, 1},
{1, 2},
{1, 4},
{1, 8}
};
#define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;}
#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
@@ -472,31 +479,16 @@ DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
}
DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
int *output_width, int *output_height)
DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors)
{
int i, retval=0, scaledw=0, scaledh=0;
if(input_width<1 || input_height<1 || output_width==NULL
|| output_height==NULL || *output_width<0 || *output_height<0)
_throw("Invalid argument in tjGetScaledSize()");
if(*output_width==0) *output_width=input_width;
if(*output_height==0) *output_height=input_height;
if(*output_width<input_width || *output_height<input_height)
if(numscalingfactors==NULL)
{
for(i=1; i<=8; i*=2)
{
scaledw=(input_width+i-1)/i;
scaledh=(input_height+i-1)/i;
if(scaledw<=*output_width && scaledh<=*output_height)
break;
}
*output_width=scaledw; *output_height=scaledh;
sprintf(lasterror, "Invalid argument in tjGetScalingFactors()");
return NULL;
}
bailout:
return retval;
*numscalingfactors=NUMSF;
return (tjscalingfactor *)sf;
}
@@ -509,7 +501,7 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
int scale_num=1, scale_denom=1, jpegwidth, jpegheight, scaledw, scaledh;
int jpegwidth, jpegheight, scaledw, scaledh;
checkhandle(h);
@@ -608,22 +600,18 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
jpegwidth=j->dinfo.image_width; jpegheight=j->dinfo.image_height;
if(width==0) width=jpegwidth;
if(height==0) height=jpegheight;
if(width<jpegwidth || height<jpegheight)
for(i=0; i<NUMSF; i++)
{
for(i=1; i<=8; i*=2)
{
scaledw=(jpegwidth+i-1)/i;
scaledh=(jpegheight+i-1)/i;
if(scaledw<=width && scaledh<=height)
scaledw=(jpegwidth*sf[i].num+sf[i].denom-1)/sf[i].denom;
scaledh=(jpegheight*sf[i].num+sf[i].denom-1)/sf[i].denom;
if(scaledw<=width && scaledh<=height)
break;
}
if(scaledw>width || scaledh>height)
_throw("Could not scale down to desired image dimensions");
width=scaledw; height=scaledh;
scale_denom=i;
}
j->dinfo.scale_num=scale_num;
j->dinfo.scale_denom=scale_denom;
if(scaledw>width || scaledh>height)
_throw("Could not scale down to desired image dimensions");
width=scaledw; height=scaledh;
j->dinfo.scale_num=sf[i].num;
j->dinfo.scale_denom=sf[i].denom;
}
jpeg_start_decompress(&j->dinfo);