}
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
{
}
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
{
}
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();
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
{
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);
}
}
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;
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("... ");
}
{
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);
}
}
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
{
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");
}
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,
int subsamp)
throws Exception;
+ public native final static ScalingFactor [] getScalingFactors()
+ throws Exception;
+
static {
System.loadLibrary("turbojpeg");
}
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)
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,
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");
}
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
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
}
}
-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");
- }
-}
+#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); \
+ retval=0; goto bailout; \
+ }}
+
+#define checkval0(v) { \
+ if(v>1) { \
+ printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, i, j, v); \
+ retval=0; goto bailout; \
+ }}
+
+#define checkval255(v) { \
+ if(v<254) { \
+ printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, i, j, v); \
+ retval=0; goto bailout; \
+ }}
int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp,
- int scalefactor, int flags)
+ 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;
+ _i, j, retval=1;
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)
+ int halfway=16*scale_num/scale_denom, blocksize=8*scale_num/scale_denom;
+
+ for(_i=0; _i<halfway; _i++)
{
- for(_i=0; _i<halfway; _i++)
+ if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
+ for(j=0; j<w; j++)
{
- 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)
{
- 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;
- }
+ checkval255(r); checkval255(g); checkval255(b);
}
- }
- for(_i=halfway; _i<h; _i++)
- {
- if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
- for(j=0; j<w; j++)
+ else
{
- 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(subsamp==TJ_GRAYSCALE)
{
- if(r>2 || g>2 || b>2) return 0;
+ checkval(r, 76); checkval(g, 76); checkval(b, 76);
}
else
{
- if(r<224 || r>228 || g<224 || g>228 || b<224 || b>228) return 0;
+ checkval255(r); checkval0(g); checkval0(b);
}
}
}
}
- else
+ for(_i=halfway; _i<h; _i++)
{
- for(_i=0; _i<halfway; _i++)
+ if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
+ for(j=0; j<w; j++)
{
- 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(buf[(w*i+j)*ps+roffset]<253) return 0;
- if(((_i/blocksize)+(j/blocksize))%2==0)
+ checkval0(r); checkval0(g); checkval0(b);
+ }
+ else
+ {
+ if(subsamp==TJ_GRAYSCALE)
{
- if(buf[(w*i+j)*ps+goffset]<253) return 0;
- if(buf[(w*i+j)*ps+boffset]<253) return 0;
+ checkval(r, 226); checkval(g, 226); checkval(b, 226);
}
else
{
- if(buf[(w*i+j)*ps+goffset]>2) return 0;
- if(buf[(w*i+j)*ps+boffset]>2) return 0;
+ checkval255(r); checkval255(g); checkval0(b);
}
}
}
- for(_i=halfway; _i<h; _i++)
+ }
+
+ bailout:
+ if(retval==0)
+ {
+ printf("\n");
+ for(i=0; 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;
- }
+ 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 1;
+ return retval;
}
-#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); \
- retval=0; goto bailout; \
- }}
-
-#define checkval0(v) { \
- if(v>1) { \
- printf("\nComp. %s at %d,%d should be 0, not %d\n", #v, i, j, v); \
- retval=0; goto bailout; \
- }}
-
-#define checkval255(v) { \
- if(v<254) { \
- printf("\nComp. %s at %d,%d should be 255, not %d\n", #v, i, j, v); \
- retval=0; goto bailout; \
- }}
-
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
int checkbufyuv(unsigned char *buf, int w, int h, int subsamp)
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;
{
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("... ");
}
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)
}
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.);
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");
}
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};
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)
{
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)
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);
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");
}
void usage(char *progname)
{
+ int i;
printf("USAGE: %s\n", progname);
printf(" <Inputfile (BMP|PPM)> <%% Quality> [options]\n\n");
printf(" %s\n", 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);
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], '.');
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");
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;
}
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
TURBOJPEG_1.2
{
global:
- tjGetScaledSize;
+ tjGetScalingFactors;
tjInitTransform;
tjTransform;
} TURBOJPEG_1.1;
TURBOJPEG_1.2
{
global:
- tjGetScaledSize;
+ tjGetScalingFactors;
tjInitTransform;
tjTransform;
Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
#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
/*
- int tjGetScaledSize(int input_width, int input_height,
- int *output_width, int *output_height)
-
- [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: 0 on success, -1 if arguments are out of bounds
+ tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
+
+ Returns a list of fractional scaling factors that the JPEG decompressor in
+ this implementation of TurboJPEG supports.
+
+ [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);
/*
[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
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
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; \
}
-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;
}
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);
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);