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:
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
226
jpegut.c
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
61
jpgtest.c
61
jpgtest.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,7 +25,7 @@ TURBOJPEG_1.1
|
||||
TURBOJPEG_1.2
|
||||
{
|
||||
global:
|
||||
tjGetScaledSize;
|
||||
tjGetScalingFactors;
|
||||
tjInitTransform;
|
||||
tjTransform;
|
||||
} TURBOJPEG_1.1;
|
||||
|
||||
@@ -25,7 +25,7 @@ TURBOJPEG_1.1
|
||||
TURBOJPEG_1.2
|
||||
{
|
||||
global:
|
||||
tjGetScaledSize;
|
||||
tjGetScalingFactors;
|
||||
tjInitTransform;
|
||||
tjTransform;
|
||||
Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
|
||||
|
||||
42
turbojpeg.h
42
turbojpeg.h
@@ -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
|
||||
|
||||
58
turbojpegl.c
58
turbojpegl.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user