Added scaling API to TurboJPEG/OSS

git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@367 632fc199-4ca6-4c93-a231-07263d6284db
This commit is contained in:
DRC
2011-02-15 08:31:34 +00:00
parent e9cf55cc94
commit 8ed7b81403
5 changed files with 130 additions and 63 deletions

View File

@@ -3,7 +3,7 @@
[1] Added a JNI wrapper for TurboJPEG/OSS. See java/README for more details.
[2] Ported jpgtest.cxx to pure C to avoid the need for a C++ compiler.
[2] TurboJPEG/OSS can now scale down images during decompression.
1.1.0
@@ -15,6 +15,8 @@ forward DCT when generating JPEG images of quality 96 or greater. This
reduces compression performance by as much as 15% for these high-quality images
but is necessary to ensure that the images are perceptually lossless.
[2] Ported jpgtest.cxx to pure C to avoid the need for a C++ compiler.
1.0.90 (1.1 beta1)
==================

View File

@@ -103,8 +103,10 @@ 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 flags)
void dumpbuf(unsigned char *buf, int w, int h, int ps, int scalefactor,
int flags)
{
printf("\n");
int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
j;
for(i=0; i<h; i++)
@@ -118,15 +120,17 @@ void dumpbuf(unsigned char *buf, int w, int h, int ps, int flags)
}
}
int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
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<16; _i++)
for(_i=0; _i<halfway; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
@@ -134,7 +138,7 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
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/8)+(j/8))%2==0)
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(r<253 || g<253 || b<253) return 0;
}
@@ -144,7 +148,7 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
}
}
}
for(_i=16; _i<h; _i++)
for(_i=halfway; _i<h; _i++)
{
if(flags&TJ_BOTTOMUP) i=h-_i-1; else i=_i;
for(j=0; j<w; j++)
@@ -152,7 +156,7 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
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/8)+(j/8))%2==0)
if(((_i/blocksize)+(j/blocksize))%2==0)
{
if(r>2 || g>2 || b>2) return 0;
}
@@ -165,13 +169,13 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
}
else
{
for(_i=0; _i<16; _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(buf[(w*i+j)*ps+roffset]<253) return 0;
if(((_i/8)+(j/8))%2==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;
@@ -183,13 +187,13 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
}
}
}
for(_i=16; _i<h; _i++)
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/8)+(j/8))%2==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;
@@ -377,7 +381,8 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
memset(jpegbuf, 0, TJBUFSIZE(w, h));
t=rrtime();
_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual,
flags));
t=rrtime()-t;
if(yuv==YUVENCODE)
@@ -399,14 +404,16 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
if(bmpbuf) free(bmpbuf);
}
void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int flags)
void _gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int flags,
int scalefactor)
{
unsigned char *bmpbuf=NULL;
const char *pixformat; int _w=0, _h=0; double t;
const char *pixformat; int _hdrw=0, _hdrh=0, _hdrsubsamp=-1; double t;
unsigned long size=0;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
int pw=PAD(w, hsf), ph=PAD(h, vsf);
int _w=(w+scalefactor-1)/scalefactor, _h=(h+scalefactor-1)/scalefactor;
int cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
@@ -427,11 +434,16 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
if(yuv==YUVDECODE)
printf("JPEG -> YUV %s ... ", _subnames[subsamp]);
else
printf("JPEG -> %s %s ... ", pixformat,
{
printf("JPEG -> %s %s ", pixformat,
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
if(scalefactor) printf("1/%d ... ", scalefactor);
else printf("... ");
}
_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
if(_w!=w || _h!=h)
_catch(tjDecompressHeader2(hnd, jpegbuf, jpegsize, &_hdrw, &_hdrh,
&_hdrsubsamp));
if(_hdrw!=w || _hdrh!=h || _hdrsubsamp!=subsamp)
{
printf("Incorrect JPEG header\n"); bailout();
}
@@ -439,7 +451,7 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
if(yuv==YUVDECODE)
size=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
else
size=w*h*ps;
size=_w*_h*ps;
if((bmpbuf=(unsigned char *)malloc(size+1))==NULL)
{
printf("ERROR: Could not allocate buffer\n"); bailout();
@@ -447,7 +459,8 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
memset(bmpbuf, 0, size+1);
t=rrtime();
_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
_catch(tjDecompress2(hnd, jpegbuf, jpegsize, bmpbuf, 0, ps, 1,
scalefactor, flags));
t=rrtime()-t;
if(yuv==YUVDECODE)
@@ -458,19 +471,36 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
}
else
{
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
if(checkbuf(bmpbuf, _w, _h, ps, subsamp, scalefactor, flags))
printf("Passed.");
else
{
printf("FAILED!"); exitstatus=-1;
dumpbuf(bmpbuf, w, h, ps, flags);
dumpbuf(bmpbuf, _w, _h, ps, scalefactor, flags);
}
}
printf(" %f ms\n\n", t*1000.);
printf(" %f ms\n", t*1000.);
finally:
if(bmpbuf) free(bmpbuf);
}
void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
int w, int h, int ps, char *basefilename, int subsamp, int flags)
{
int i;
if((subsamp==TJ_444 || subsamp==TJ_GRAYSCALE) && !yuv)
{
for(i=1; i<=8; i*=2)
_gentestbmp(hnd, jpegbuf, jpegsize, w, h, ps, basefilename, subsamp,
flags, i);
}
else
_gentestbmp(hnd, jpegbuf, jpegsize, w, h, ps, basefilename, subsamp,
flags, 1);
printf("\n");
}
void dotest(int w, int h, int ps, int subsamp, char *basefilename)
{
tjhandle hnd=NULL, dhnd=NULL; unsigned char *jpegbuf=NULL;
@@ -548,7 +578,7 @@ void dotest1(void)
bmpbuf[i2*4+1]=pixels[i2%9][1];
bmpbuf[i2*2+2]=pixels[i2%9][0];
}
_catch(tjCompress(hnd, bmpbuf, i, i*4, j, 4,
_catch(tjCompress(hnd, bmpbuf, i, 0, j, 4,
jpgbuf, &size, TJ_444, 100, TJ_BGR));
free(bmpbuf); bmpbuf=NULL; free(jpgbuf); jpgbuf=NULL;
@@ -562,7 +592,7 @@ void dotest1(void)
if(i2%2==0) bmpbuf[i2]=0xFF;
else bmpbuf[i2]=0;
}
_catch(tjCompress(hnd, bmpbuf, j, j*4, i, 4,
_catch(tjCompress(hnd, bmpbuf, j, 0, i, 4,
jpgbuf, &size, TJ_444, 100, TJ_BGR));
free(bmpbuf); bmpbuf=NULL; free(jpgbuf); jpgbuf=NULL;
}

View File

@@ -7,6 +7,7 @@
tjDecompressHeader;
tjDecompressHeader2;
tjDecompress;
tjDecompress2;
tjDestroy;
tjGetErrorStr;
local:

View File

@@ -1,6 +1,6 @@
/* Copyright (C)2004 Landmark Graphics Corporation
* Copyright (C)2005, 2006 Sun Microsystems, Inc.
* Copyright (C)2009 D. R. Commander
* Copyright (C)2009-2011 D. R. Commander
*
* This library is free software and may be redistributed and/or modified under
* the terms of the wxWindows Library License, Version 3.1 or (at your option)
@@ -117,8 +117,9 @@ DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
[INPUT] pitch = bytes per line of the source image (width*pixelsize if the
bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
is padded to the nearest 32-bit boundary, such as is the case for Windows
bitmaps. You can also be clever and use this parameter to skip lines, etc.,
as long as the pitch is greater than 0.)
bitmaps. 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
width*pixelsize;
[INPUT] height = height (in pixels) of the source image
[INPUT] pixelsize = size (in bytes) of each pixel in the source image
RGBA and BGRA: 4, RGB and BGR: 3, Grayscale: 1
@@ -190,7 +191,7 @@ DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle j,
int *width, int *height, int *jpegsub);
/*
Deprecated version of the above function
Legacy version of the above function
*/
DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
unsigned char *srcbuf, unsigned long size,
@@ -198,10 +199,10 @@ DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
/*
int tjDecompress(tjhandle j,
int tjDecompress2(tjhandle j,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
int flags)
unsigned char *dstbuf, int pitch, int pixelsize,
int scale_num, int scale_denom, int flags)
[INPUT] j = instance handle previously returned from a call to
tjInitDecompress()
@@ -209,23 +210,34 @@ DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
to decompress
[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*height
bytes in size, although this pointer may also be used to decompress into
a specific region of a larger buffer.
[INPUT] width = width (in pixels) of the destination image
[INPUT] pitch = bytes per line of the destination image (width*pixelsize if the
bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
is padded to the nearest 32-bit boundary, such as is the case for Windows
bitmaps. You can also be clever and use this parameter to skip lines, etc.,
as long as the pitch is greater than 0.)
[INPUT] height = height (in pixels) of the destination image
the bitmap image. This buffer should normally be pitch*scaled_height
bytes in size, where scaled_height=ceil(JPEG image height/scale_denom).
However, this pointer may also be used to decompress into a specific
region of a larger buffer.
[INPUT] pitch = bytes per line of the destination image. Normally, this is
scaled_width*pixelsize if the bitmap 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=ceil(JPEG image width/scale_denom). 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] pixelsize = size (in bytes) of each pixel in the destination image
RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3, Grayscale: 1
[INPUT] scale_num = numerator of scaling factor (currently must be 1)
[INPUT] scale_denom = denominator of scaling factor (1, 2, 4, or 8)
[INPUT] flags = the bitwise OR of one or more of the flags described in the
"Flags" section above.
RETURNS: 0 on success, -1 on error
*/
DLLEXPORT int DLLCALL tjDecompress2(tjhandle j,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int pitch, int pixelsize,
int scale_num, int scale_denom, int flags);
/*
Legacy version of the above function
*/
DLLEXPORT int DLLCALL tjDecompress(tjhandle j,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,

View File

@@ -418,10 +418,10 @@ DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
}
DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
DLLEXPORT int DLLCALL tjDecompress2(tjhandle h,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int width, int pitch, int height, int ps,
int flags)
unsigned char *dstbuf, int pitch, int ps,
int scale_num, int scale_denom, int flags)
{
int i, row, retval=0; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
@@ -435,14 +435,15 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
tmpbuf[i]=NULL; outbuf[i]=NULL;
}
if(srcbuf==NULL || size<=0
|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
_throw("Invalid argument in tjDecompress()");
if(srcbuf==NULL || size<=0 || dstbuf==NULL || pitch<0)
_throw("Invalid argument in tjDecompress2()");
if(ps!=3 && ps!=4 && ps!=1)
_throw("This decompressor can only handle 24-bit and 32-bit RGB or 8-bit grayscale output");
if(!j->initd) _throw("Instance has not been initialized for decompression");
if(pitch==0) pitch=width*ps;
if(scale_num!=1 || scale_denom<1 || scale_denom>8
|| (scale_denom&(scale_denom-1))!=0)
_throw("Unsupported scaling factor");
if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
@@ -470,10 +471,10 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
int ih;
iw[i]=compptr->width_in_blocks*DCTSIZE;
ih=compptr->height_in_blocks*DCTSIZE;
cw[i]=PAD(width, dinfo->max_h_samp_factor)*compptr->h_samp_factor
/dinfo->max_h_samp_factor;
ch[i]=PAD(height, dinfo->max_v_samp_factor)*compptr->v_samp_factor
/dinfo->max_v_samp_factor;
cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
*compptr->h_samp_factor/dinfo->max_h_samp_factor;
ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
*compptr->v_samp_factor/dinfo->max_v_samp_factor;
if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
th[i]=compptr->v_samp_factor*DCTSIZE;
tmpbufsize+=iw[i]*th[i];
@@ -503,16 +504,6 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
}
}
}
else
{
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
_throw("Memory allocation failed in tjInitDecompress()");
for(i=0; i<height; i++)
{
if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
else row_pointer[i]= &dstbuf[i*pitch];
}
}
if(ps==1) j->dinfo.out_color_space = JCS_GRAYSCALE;
#if JCS_EXTENSIONS==1
@@ -533,6 +524,11 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
else
{
j->dinfo.scale_num=scale_num;
j->dinfo.scale_denom=scale_denom;
}
jpeg_start_decompress(&j->dinfo);
if(flags&TJ_YUV)
@@ -567,6 +563,19 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
}
else
{
if(pitch==0) pitch=j->dinfo.output_width*ps;
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)
*j->dinfo.output_height))==NULL)
{
jpeg_finish_decompress(&j->dinfo);
_throw("Memory allocation failed in tjInitDecompress()");
}
for(i=0; i<j->dinfo.output_height; i++)
{
if(flags&TJ_BOTTOMUP)
row_pointer[i]= &dstbuf[(j->dinfo.output_height-i-1)*pitch];
else row_pointer[i]= &dstbuf[i*pitch];
}
while(j->dinfo.output_scanline<j->dinfo.output_height)
{
jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
@@ -587,6 +596,19 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
}
DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int width, int pitch, int height, int ps,
int flags)
{
if(width<=0 || height<=0)
{
sprintf(lasterror, "Invalid argument in tjDecompress()");
return -1;
}
return tjDecompress2(h, srcbuf, size, dstbuf, pitch, ps, 1, 1, flags);
}
// General
DLLEXPORT char* DLLCALL tjGetErrorStr(void)