зеркало из https://github.com/mozilla/mozjpeg.git
Provide TJ_YUV option for tjDecompress() as well
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@307 632fc199-4ca6-4c93-a231-07263d6284db
This commit is contained in:
Родитель
ac08ef624c
Коммит
9e17f7d9bc
|
@ -21,8 +21,8 @@ when the library is built with libjpeg v6b emulation.
|
|||
[7] Added arithmetic encoding and decoding support (can be disabled via
|
||||
configure or CMake options)
|
||||
|
||||
[8] TurboJPEG/OSS can now leverage the SIMD-accelerated color conversion
|
||||
routines in libjpeg-turbo to generate planar YUV images from RGB input.
|
||||
[8] Added a TJ_YUV flag to TurboJPEG/OSS which causes both the compressor and
|
||||
decompressor to output planar YUV images.
|
||||
|
||||
|
||||
Significant changes since 1.0.0
|
||||
|
|
103
jpegut.c
103
jpegut.c
|
@ -29,6 +29,7 @@ const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
|
|||
const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
|
||||
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
|
||||
|
||||
enum {YUVENCODE=1, YUVDECODE};
|
||||
int yuv=0;
|
||||
|
||||
int exitstatus=0;
|
||||
|
@ -225,13 +226,13 @@ int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
|
|||
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
|
||||
|
||||
int checkbufyuv(unsigned char *buf, unsigned long size, int w, int h,
|
||||
int subsamp)
|
||||
int subsamp, int decode)
|
||||
{
|
||||
int i, j;
|
||||
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
|
||||
int pw=PAD(w, hsf), ph=PAD(h, vsf);
|
||||
int cw=pw/hsf, ch=ph/vsf;
|
||||
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
|
||||
int cw=PAD(pw/hsf, decode? 8:1), ch=PAD(ph/vsf, decode? 8:1);
|
||||
int ypitch=PAD(pw, decode? 8:4), uvpitch=PAD(cw, decode? 8:4);
|
||||
int retval=1;
|
||||
unsigned long correctsize=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
|
||||
|
||||
|
@ -348,7 +349,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
|
|||
char tempstr[1024]; unsigned char *bmpbuf=NULL;
|
||||
const char *pixformat; double t;
|
||||
|
||||
if(yuv) flags|=TJ_YUV;
|
||||
if(yuv==YUVENCODE) flags|=TJ_YUV;
|
||||
|
||||
if(flags&TJ_BGR)
|
||||
{
|
||||
|
@ -361,7 +362,7 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
|
|||
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
|
||||
}
|
||||
if(ps==1) pixformat="Grayscale";
|
||||
if(yuv)
|
||||
if(yuv==YUVENCODE)
|
||||
printf("%s %s -> %s YUV ... ", pixformat,
|
||||
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp]);
|
||||
else
|
||||
|
@ -379,16 +380,16 @@ void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
|
|||
_catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
|
||||
t=rrtime()-t;
|
||||
|
||||
if(yuv)
|
||||
if(yuv==YUVENCODE)
|
||||
sprintf(tempstr, "%s_enc_%s_%s_%s.yuv", basefilename, pixformat,
|
||||
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp]);
|
||||
else
|
||||
sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
|
||||
(flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
|
||||
writejpeg(jpegbuf, *size, tempstr);
|
||||
if(yuv)
|
||||
if(yuv==YUVENCODE)
|
||||
{
|
||||
if(checkbufyuv(jpegbuf, *size, w, h, subsamp)) printf("Passed.");
|
||||
if(checkbufyuv(jpegbuf, *size, w, h, subsamp, 0)) printf("Passed.");
|
||||
else printf("FAILED!");
|
||||
}
|
||||
else printf("Done.");
|
||||
|
@ -399,12 +400,16 @@ 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 qual, int flags)
|
||||
int w, int h, int ps, char *basefilename, int subsamp, int flags)
|
||||
{
|
||||
unsigned char *bmpbuf=NULL;
|
||||
const char *pixformat; int _w=0, _h=0; double t;
|
||||
unsigned long size=0;
|
||||
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
|
||||
int pw=PAD(w, 8), ph=PAD(h, 8), cw=PAD(pw/hsf, 8), ch=PAD(ph/vsf, 8);
|
||||
|
||||
if(yuv) return;
|
||||
if(yuv==YUVDECODE) flags|=TJ_YUV;
|
||||
else if(yuv==YUVENCODE) return;
|
||||
|
||||
if(flags&TJ_BGR)
|
||||
{
|
||||
|
@ -417,7 +422,11 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
|
|||
else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB"; else pixformat="RGBA";}
|
||||
}
|
||||
if(ps==1) pixformat="Grayscale";
|
||||
printf("JPEG -> %s %s ... ", pixformat, (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
|
||||
if(yuv==YUVDECODE)
|
||||
printf("JPEG -> YUV %s ... ", _subnames[subsamp]);
|
||||
else
|
||||
printf("JPEG -> %s %s ... ", pixformat,
|
||||
(flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
|
||||
|
||||
_catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
|
||||
if(_w!=w || _h!=h)
|
||||
|
@ -425,19 +434,31 @@ void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
|
|||
printf("Incorrect JPEG header\n"); bailout();
|
||||
}
|
||||
|
||||
if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
|
||||
if(yuv==YUVDECODE)
|
||||
size=pw*ph + (subsamp==TJ_GRAYSCALE? 0:cw*ch*(ps-1));
|
||||
else
|
||||
size=w*h*ps;
|
||||
if((bmpbuf=(unsigned char *)malloc(size+1))==NULL)
|
||||
{
|
||||
printf("ERROR: Could not allocate buffer\n"); bailout();
|
||||
}
|
||||
memset(bmpbuf, 0, w*ps*h);
|
||||
memset(bmpbuf, 0, size+1);
|
||||
|
||||
t=rrtime();
|
||||
_catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
|
||||
t=rrtime()-t;
|
||||
|
||||
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
|
||||
else {printf("FAILED!"); dumpbuf(bmpbuf, w, h, ps, flags);}
|
||||
|
||||
if(yuv==YUVDECODE)
|
||||
{
|
||||
if(checkbufyuv(bmpbuf, size, pw, ph, subsamp, 1))
|
||||
printf("Passed.");
|
||||
else printf("FAILED!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
|
||||
else {printf("FAILED!"); dumpbuf(bmpbuf, w, h, ps, flags);}
|
||||
}
|
||||
printf(" %f ms\n\n", t*1000.);
|
||||
|
||||
finally:
|
||||
|
@ -460,32 +481,32 @@ void dotest(int w, int h, int ps, int subsamp, char *basefilename)
|
|||
{printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr()); bailout();}
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, 0);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 0);
|
||||
|
||||
if(ps==1) goto finally;
|
||||
if(ps==1 || yuv==YUVDECODE) goto finally;
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR);
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BOTTOMUP);
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_BGR|TJ_BOTTOMUP);
|
||||
|
||||
if(ps==4)
|
||||
{
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST);
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR);
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BOTTOMUP);
|
||||
|
||||
gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
|
||||
gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
|
||||
}
|
||||
|
||||
finally:
|
||||
|
@ -549,20 +570,28 @@ void dotest1(void)
|
|||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc>1 && !stricmp(argv[1], "-yuv")) yuv=1;
|
||||
dotest(35, 41, 3, TJ_444, "test");
|
||||
dotest(35, 41, 4, TJ_444, "test");
|
||||
if(yuv)
|
||||
int doyuv=0;
|
||||
if(argc>1 && !stricmp(argv[1], "-yuv")) doyuv=1;
|
||||
if(doyuv) yuv=YUVENCODE;
|
||||
dotest(35, 39, 3, TJ_444, "test");
|
||||
dotest(39, 41, 4, TJ_444, "test");
|
||||
if(doyuv)
|
||||
{
|
||||
dotest(35, 41, 3, TJ_422, "test");
|
||||
dotest(35, 41, 4, TJ_422, "test");
|
||||
dotest(35, 41, 3, TJ_420, "test");
|
||||
dotest(35, 41, 4, TJ_420, "test");
|
||||
dotest(41, 35, 3, TJ_422, "test");
|
||||
dotest(35, 39, 4, TJ_422, "test");
|
||||
dotest(39, 41, 3, TJ_420, "test");
|
||||
dotest(41, 35, 4, TJ_420, "test");
|
||||
}
|
||||
dotest(35, 39, 1, TJ_GRAYSCALE, "test");
|
||||
dotest(39, 41, 3, TJ_GRAYSCALE, "test");
|
||||
dotest(41, 35, 4, TJ_GRAYSCALE, "test");
|
||||
if(!doyuv) dotest1();
|
||||
if(doyuv)
|
||||
{
|
||||
yuv=YUVDECODE;
|
||||
dotest(35, 39, 3, TJ_444, "test");
|
||||
dotest(39, 41, 1, TJ_GRAYSCALE, "test");
|
||||
}
|
||||
dotest(35, 41, 1, TJ_GRAYSCALE, "test");
|
||||
dotest(35, 41, 3, TJ_GRAYSCALE, "test");
|
||||
dotest(35, 41, 4, TJ_GRAYSCALE, "test");
|
||||
dotest1();
|
||||
|
||||
return exitstatus;
|
||||
}
|
||||
|
|
115
jpgtest.cxx
115
jpgtest.cxx
|
@ -29,6 +29,9 @@
|
|||
#define _throwtj(m) _throw(m, tjGetErrorStr())
|
||||
#define _throwbmp(m) _throw(m, bmpgeterr())
|
||||
|
||||
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
|
||||
|
||||
enum {YUVENCODE=1, YUVDECODE};
|
||||
int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0, fastupsample=0,
|
||||
decomponly=0, yuv=0;
|
||||
const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
|
||||
|
@ -40,6 +43,8 @@ const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
|
|||
const char *_pfname[]={"RGB", "RGBA", "BGR", "BGRA", "ABGR", "ARGB"};
|
||||
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
|
||||
const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
|
||||
const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
|
||||
const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
|
||||
|
||||
void printsigfig(double val, int figs)
|
||||
{
|
||||
|
@ -63,7 +68,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
|
||||
{
|
||||
char tempstr[1024];
|
||||
FILE *outfile; tjhandle hnd;
|
||||
FILE *outfile=NULL; tjhandle hnd;
|
||||
unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
|
||||
rrtimer timer; double elapsed;
|
||||
int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
|
||||
|
@ -72,24 +77,28 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
|(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0)
|
||||
|(fastupsample?TJ_FASTUPSAMPLE:0);
|
||||
int ps=_ps[pf];
|
||||
int pitch=w*ps;
|
||||
int pitch=w*ps, yuvsize;
|
||||
int hsf=_hsf[jpegsub], vsf=_vsf[jpegsub];
|
||||
int pw=PAD(w, 8), ph=PAD(h, 8), cw=PAD(pw/hsf, 8), ch=PAD(ph/vsf, 8);
|
||||
|
||||
flags |= _flags[pf];
|
||||
if(bu) flags |= TJ_BOTTOMUP;
|
||||
if(yuv) flags |= TJ_YUV;
|
||||
if(yuv==YUVENCODE) flags |= TJ_YUV;
|
||||
|
||||
if((rgbbuf=(unsigned char *)malloc(pitch*h)) == NULL)
|
||||
yuvsize=pw*ph + (jpegsub==TJ_GRAYSCALE? 0:cw*ch*2);
|
||||
if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
|
||||
_throwunix("allocating image buffer");
|
||||
|
||||
if(!quiet)
|
||||
{
|
||||
if(yuv)
|
||||
if(yuv==YUVENCODE)
|
||||
printf("\n>>>>> %s (%s) <--> YUV %s <<<<<\n", _pfname[pf],
|
||||
bu?"Bottom-up":"Top-down", _subnamel[jpegsub]);
|
||||
else
|
||||
printf("\n>>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", _pfname[pf],
|
||||
bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
|
||||
}
|
||||
if(yuv==YUVDECODE) dotile=0;
|
||||
if(dotile) {tilesizex=tilesizey=4;} else {tilesizex=w; tilesizey=h;}
|
||||
|
||||
do
|
||||
|
@ -163,7 +172,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
}
|
||||
if(tilesizex==w && tilesizey==h)
|
||||
{
|
||||
if(yuv)
|
||||
if(yuv==YUVENCODE)
|
||||
sprintf(tempstr, "%s_%s.yuv", filename, _subnames[jpegsub]);
|
||||
else
|
||||
sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
|
||||
|
@ -171,13 +180,14 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
_throwunix("opening reference image");
|
||||
if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
|
||||
_throwunix("writing reference image");
|
||||
fclose(outfile);
|
||||
fclose(outfile); outfile=NULL;
|
||||
if(!quiet) printf("Reference image written to %s\n", tempstr);
|
||||
}
|
||||
if(yuv) goto bailout;
|
||||
if(yuv==YUVENCODE) goto bailout;
|
||||
|
||||
// Decompression test
|
||||
memset(rgbbuf, 127, pitch*h); // Grey image means decompressor did nothing
|
||||
if(yuv==YUVDECODE) flags |= TJ_YUV;
|
||||
memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
|
||||
if((hnd=tjInitDecompress())==NULL)
|
||||
_throwtj("executing tjInitDecompress()");
|
||||
if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
|
||||
|
@ -214,41 +224,54 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
printf(" Dest. throughput: %f Megapixels/sec\n",
|
||||
(double)(w*h)/1000000.*(double)ITER/elapsed);
|
||||
}
|
||||
if(tilesizex==w && tilesizey==h)
|
||||
sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
|
||||
useppm?"ppm":"bmp");
|
||||
else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
|
||||
qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
|
||||
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
|
||||
_throwbmp("saving bitmap");
|
||||
sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
|
||||
if(!quiet)
|
||||
printf("Computing compression error and saving to %s.\n", tempstr);
|
||||
if(jpegsub==TJ_GRAYSCALE)
|
||||
if(yuv==YUVDECODE)
|
||||
{
|
||||
for(j=0; j<h; j++)
|
||||
{
|
||||
for(i=0; i<w*ps; i+=ps)
|
||||
{
|
||||
int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
|
||||
+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
|
||||
+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
|
||||
if(y>255) y=255; if(y<0) y=0;
|
||||
rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
|
||||
rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
|
||||
rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
|
||||
}
|
||||
}
|
||||
}
|
||||
sprintf(tempstr, "%s_%sQ%d.yuv", filename, _subnames[jpegsub], qual);
|
||||
if((outfile=fopen(tempstr, "wb"))==NULL)
|
||||
_throwunix("opening YUV image for output");
|
||||
if(fwrite(rgbbuf, yuvsize, 1, outfile)!=1)
|
||||
_throwunix("writing YUV image");
|
||||
fclose(outfile); outfile=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
|
||||
rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
|
||||
if(tilesizex==w && tilesizey==h)
|
||||
sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
|
||||
useppm?"ppm":"bmp");
|
||||
else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
|
||||
qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
|
||||
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
|
||||
_throwbmp("saving bitmap");
|
||||
sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
|
||||
if(!quiet)
|
||||
printf("Computing compression error and saving to %s.\n", tempstr);
|
||||
if(jpegsub==TJ_GRAYSCALE)
|
||||
{
|
||||
for(j=0; j<h; j++)
|
||||
{
|
||||
for(i=0; i<w*ps; i+=ps)
|
||||
{
|
||||
int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
|
||||
+ (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
|
||||
+ (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
|
||||
if(y>255) y=255; if(y<0) y=0;
|
||||
rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
|
||||
rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
|
||||
rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
|
||||
rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
|
||||
}
|
||||
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
|
||||
_throwbmp("saving bitmap");
|
||||
}
|
||||
if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
|
||||
_throwbmp("saving bitmap");
|
||||
|
||||
// Cleanup
|
||||
if(outfile) {fclose(outfile); outfile=NULL;}
|
||||
if(jpegbuf)
|
||||
{
|
||||
for(i=0; i<numtilesx*numtilesy; i++)
|
||||
|
@ -262,6 +285,7 @@ void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
|
|||
return;
|
||||
|
||||
bailout:
|
||||
if(outfile) {fclose(outfile); outfile=NULL;}
|
||||
if(jpegbuf)
|
||||
{
|
||||
for(i=0; i<numtilesx*numtilesy; i++)
|
||||
|
@ -384,8 +408,10 @@ void usage(char *progname)
|
|||
printf(" YUV decoding in libjpeg decompressor\n\n");
|
||||
printf(" [-quiet]\n");
|
||||
printf(" Output in tabular rather than verbose format\n\n");
|
||||
printf(" [-yuv]\n");
|
||||
printf(" [-yuvencode]\n");
|
||||
printf(" Encode RGB input as planar YUV rather than compressing as JPEG\n\n");
|
||||
printf(" [-yuvdecode]\n");
|
||||
printf(" Decode JPEG image to planar YUV rather than RGB\n\n");
|
||||
printf(" NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
|
||||
printf(" test will be performed for all quality values in the range.\n");
|
||||
exit(1);
|
||||
|
@ -414,15 +440,20 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
for(i=minarg; i<argc; i++)
|
||||
{
|
||||
if(!stricmp(argv[i], "-yuv"))
|
||||
if(!stricmp(argv[i], "-yuvencode"))
|
||||
{
|
||||
printf("Testing YUV planar encoding\n");
|
||||
yuv=1; hiqual=qual=100;
|
||||
yuv=YUVENCODE; hiqual=qual=100;
|
||||
}
|
||||
if(!stricmp(argv[i], "-yuvdecode"))
|
||||
{
|
||||
printf("Testing YUV planar decoding\n");
|
||||
yuv=YUVDECODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!decomponly && !yuv)
|
||||
if(!decomponly && yuv!=YUVENCODE)
|
||||
{
|
||||
minarg=3;
|
||||
if(argc<minarg) usage(argv[0]);
|
||||
|
|
21
turbojpeg.h
21
turbojpeg.h
|
@ -54,13 +54,22 @@ enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE};
|
|||
/* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines
|
||||
(libjpeg version only) */
|
||||
#define TJ_YUV 512
|
||||
/* Use the TurboJPEG YUV encoder to produce a planar YUV image that is
|
||||
suitable for X Video. Specifically, if either the width or the height is
|
||||
subsampled, then that dimension is padded to 2 in the output image. Also,
|
||||
each line of each plane in the output image is padded to 4 bytes.
|
||||
/* If passed to tjCompress(), this causes TurboJPEG/OSS to use the
|
||||
accelerated color conversion routines in libjpeg-turbo to produce a planar
|
||||
YUV image that is suitable for X Video. Specifically, if a component is
|
||||
subsampled along the horizontal dimension, then the width of the plane for
|
||||
that component is padded to 2 in the output image (same goes for the
|
||||
height, if the component is subsampled along the vertical dimension.)
|
||||
Also, each line of each plane in the output image is padded to 4 bytes.
|
||||
Although this will work with any subsampling option, it is really only
|
||||
useful in combination with TJ_420, which produces an image compatible
|
||||
with the I420 format. */
|
||||
useful in combination with TJ_420, which produces an image compatible with
|
||||
the I420 (AKA "YUV420P") format.
|
||||
|
||||
If passed to tjDecompress(), this tells TurboJPEG/OSS to perform JPEG
|
||||
decompression but to leave out the color conversion step, so a planar YUV
|
||||
image is generated instead of an RGB image. In this case, the width and
|
||||
height of all planes are padded to 8 in the output image.
|
||||
*/
|
||||
|
||||
typedef void* tjhandle;
|
||||
|
||||
|
|
69
turbojpegl.c
69
turbojpegl.c
|
@ -356,7 +356,7 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
|
|||
if(setjmp(j->jerr.jb))
|
||||
{ // this will execute if LIBJPEG has an error
|
||||
free(j); return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
jpeg_create_decompress(&j->dinfo);
|
||||
j->dinfo.src=&j->jsms;
|
||||
|
@ -405,10 +405,13 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
|
|||
unsigned char *dstbuf, int width, int pitch, int height, int ps,
|
||||
int flags)
|
||||
{
|
||||
int i; JSAMPROW *row_pointer=NULL;
|
||||
int i, row; JSAMPROW *row_pointer=NULL, *outbuf[MAX_COMPONENTS];
|
||||
int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS];
|
||||
|
||||
checkhandle(h);
|
||||
|
||||
for(i=0; i<MAX_COMPONENTS; i++) outbuf[i]=NULL;
|
||||
|
||||
if(srcbuf==NULL || size<=0
|
||||
|| dstbuf==NULL || width<=0 || pitch<0 || height<=0)
|
||||
_throw("Invalid argument in tjDecompress()");
|
||||
|
@ -424,21 +427,45 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
|
|||
|
||||
if(setjmp(j->jerr.jb))
|
||||
{ // this will execute if LIBJPEG has an error
|
||||
for(i=0; i<MAX_COMPONENTS; i++)
|
||||
if(outbuf[i]!=NULL) free(outbuf[i]);
|
||||
if(row_pointer) free(row_pointer);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
j->jsms.bytes_in_buffer = size;
|
||||
j->jsms.next_input_byte = srcbuf;
|
||||
|
||||
jpeg_read_header(&j->dinfo, TRUE);
|
||||
|
||||
if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
|
||||
_throw("Memory allocation failed in tjInitDecompress()");
|
||||
for(i=0; i<height; i++)
|
||||
if(flags&TJ_YUV)
|
||||
{
|
||||
if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
|
||||
else row_pointer[i]= &dstbuf[i*pitch];
|
||||
j_decompress_ptr dinfo=&j->dinfo;
|
||||
JSAMPLE *ptr=dstbuf;
|
||||
|
||||
for(i=0; i<dinfo->num_components; i++)
|
||||
{
|
||||
jpeg_component_info *compptr=&dinfo->comp_info[i];
|
||||
cw[i]=compptr->width_in_blocks*DCTSIZE;
|
||||
ch[i]=compptr->height_in_blocks*DCTSIZE;
|
||||
if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
|
||||
_throw("Memory allocation failed in tjInitDecompress()");
|
||||
for(row=0; row<ch[i]; row++)
|
||||
{
|
||||
outbuf[i][row]=ptr;
|
||||
ptr+=cw[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -459,15 +486,35 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
|
|||
#endif
|
||||
|
||||
if(flags&TJ_FASTUPSAMPLE) j->dinfo.do_fancy_upsampling=FALSE;
|
||||
if(flags&TJ_YUV) j->dinfo.raw_data_out=TRUE;
|
||||
|
||||
jpeg_start_decompress(&j->dinfo);
|
||||
while(j->dinfo.output_scanline<j->dinfo.output_height)
|
||||
if(flags&TJ_YUV)
|
||||
{
|
||||
jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
|
||||
j->dinfo.output_height-j->dinfo.output_scanline);
|
||||
for(row=0; row<j->dinfo.output_height;
|
||||
row+=j->dinfo.max_v_samp_factor*DCTSIZE)
|
||||
{
|
||||
JSAMPARRAY yuvptr[MAX_COMPONENTS];
|
||||
for(i=0; i<j->dinfo.num_components; i++)
|
||||
{
|
||||
jpeg_component_info *compptr=&j->dinfo.comp_info[i];
|
||||
yuvptr[i]=&outbuf[i][row*compptr->v_samp_factor/j->dinfo.max_v_samp_factor];
|
||||
}
|
||||
jpeg_read_raw_data(&j->dinfo, yuvptr, j->dinfo.max_v_samp_factor*DCTSIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(j->dinfo.output_scanline<j->dinfo.output_height)
|
||||
{
|
||||
jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
|
||||
j->dinfo.output_height-j->dinfo.output_scanline);
|
||||
}
|
||||
}
|
||||
jpeg_finish_decompress(&j->dinfo);
|
||||
|
||||
for(i=0; i<MAX_COMPONENTS; i++)
|
||||
if(outbuf[i]) free(outbuf[i]);
|
||||
if(row_pointer) free(row_pointer);
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче