/* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize) { tjhandle handle=0; unsigned char *jpegBuf=NULL; int width=0, height=0, jpegSubsamp=-1, jpegColorspace=-1; gethandle(); if((*env)->GetArrayLength(env, src)<jpegSize) _throwarg("Source buffer is not large enough"); bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); if(tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width, &height, &jpegSubsamp, &jpegColorspace)==-1) _throwtj(); (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); jpegBuf=NULL; bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); (*env)->SetIntField(env, obj, _fid, jpegSubsamp); if((_fid=(*env)->GetFieldID(env, _cls, "jpegColorspace", "I"))==0) (*env)->ExceptionClear(env); else (*env)->SetIntField(env, obj, _fid, jpegColorspace); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); (*env)->SetIntField(env, obj, _fid, width); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); (*env)->SetIntField(env, obj, _fid, height); bailout: if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); return; }
JNIEXPORT void JNICALL TJCompressor_encodeYUV_12 (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width, jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags) { tjhandle handle=0; jsize arraySize=0; unsigned char *srcBuf=NULL, *dstBuf=NULL; gethandle(); if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 || pitch<0) _throwarg("Invalid argument in encodeYUV()"); if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) _throwarg("Mismatch between Java and C API"); arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height; if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize) _throwarg("Source buffer is not large enough"); if((*env)->GetArrayLength(env, dst) <(jsize)tjBufSizeYUV(width, height, subsamp)) _throwarg("Destination buffer is not large enough"); bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp, flags)==-1) _throwtj(); bailout: if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); return; }
/* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst, jint flags) { tjhandle handle=0; unsigned char *jpegBuf=NULL, *dstBuf=NULL; int jpegSubsamp=-1, jpegWidth=0, jpegHeight=0; gethandle(); if((*env)->GetArrayLength(env, src)<jpegSize) _throwarg("Source buffer is not large enough"); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); if((*env)->GetArrayLength(env, dst) <(jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp)) _throwarg("Destination buffer is not large enough"); bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf, flags)==-1) _throwtj(); bailout: if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); return; }
/* TurboJPEG 1.2.x: TJCompressor::destroy() */ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy (JNIEnv *env, jobject obj) { tjhandle handle=0; gethandle(); if(tjDestroy(handle)==-1) _throwtj(); (*env)->SetLongField(env, obj, _fid, 0); bailout: return; }
/* TurboJPEG 1.2.x: TJTransformer::init() */ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init (JNIEnv *env, jobject obj) { jclass cls; jfieldID fid; tjhandle handle; if((handle=tjInitTransform())==NULL) _throwtj(); bailif0(cls=(*env)->GetObjectClass(env, obj)); bailif0(fid=(*env)->GetFieldID(env, cls, "handle", "J")); (*env)->SetLongField(env, obj, fid, (size_t)handle); bailout: return; }
static jint TJCompressor_compress (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y, jint width, jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual, jint flags) { tjhandle handle=0; unsigned long jpegSize=0; jsize arraySize=0, actualPitch; unsigned char *srcBuf=NULL, *jpegBuf=NULL; gethandle(); if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1 || pitch<0) _throwarg("Invalid argument in compress()"); if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) _throwarg("Mismatch between Java and C API"); actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; if((*env)->GetArrayLength(env, src)*srcElementSize<arraySize) _throwarg("Source buffer is not large enough"); jpegSize=tjBufSize(width, height, jpegSubsamp); if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize) _throwarg("Destination buffer is not large enough"); bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(ProcessSystemProperties(env)<0) goto bailout; if(tjCompress2(handle, &srcBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp, jpegQual, flags|TJFLAG_NOREALLOC)==-1) _throwtj(); bailout: if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0); return (jint)jpegSize; }
static void TJDecompressor_decompress (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst, jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags) { tjhandle handle=0; jsize arraySize=0, actualPitch; unsigned char *jpegBuf=NULL, *dstBuf=NULL; gethandle(); if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF) _throwarg("Invalid argument in decompress()"); if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF) _throwarg("Mismatch between Java and C API"); if((*env)->GetArrayLength(env, src)<jpegSize) _throwarg("Source buffer is not large enough"); actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize) _throwarg("Destination buffer is not large enough"); bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize, &dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf, flags)==-1) _throwtj(); bailout: if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); return; }
/* Decompression test */ int decomp(unsigned char *srcbuf, unsigned char **jpegbuf, unsigned long *jpegsize, unsigned char *dstbuf, int w, int h, int subsamp, int jpegqual, char *filename, int tilew, int tileh) { char tempstr[1024], sizestr[20]="\0", qualstr[6]="\0", *ptr; FILE *file=NULL; tjhandle handle=NULL; int row, col, iter=0, dstbufalloc=0, retval=0; double elapsed, elapsedDecode; int ps=tjPixelSize[pf]; int scaledw=TJSCALED(w, sf); int scaledh=TJSCALED(h, sf); int pitch=scaledw*ps; int ntilesw=(w+tilew-1)/tilew, ntilesh=(h+tileh-1)/tileh; unsigned char *dstptr, *dstptr2, *yuvbuf=NULL; if(jpegqual>0) { snprintf(qualstr, 6, "_Q%d", jpegqual); qualstr[5]=0; } if((handle=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()"); if(dstbuf==NULL) { if((dstbuf=(unsigned char *)malloc(pitch*scaledh))==NULL) _throwunix("allocating destination buffer"); dstbufalloc=1; } /* Set the destination buffer to gray so we know whether the decompressor attempted to write to it */ memset(dstbuf, 127, pitch*scaledh); if(doyuv) { int width=dotile? tilew:scaledw; int height=dotile? tileh:scaledh; int yuvsize=tjBufSizeYUV2(width, yuvpad, height, subsamp); if((yuvbuf=(unsigned char *)malloc(yuvsize))==NULL) _throwunix("allocating YUV buffer"); memset(yuvbuf, 127, yuvsize); } /* Benchmark */ iter=-warmup; elapsed=elapsedDecode=0.; while(1) { int tile=0; double start=gettime(); for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=pitch*tileh) { for(col=0, dstptr2=dstptr; col<ntilesw; col++, tile++, dstptr2+=ps*tilew) { int width=dotile? min(tilew, w-col*tilew):scaledw; int height=dotile? min(tileh, h-row*tileh):scaledh; if(doyuv) { double startDecode; if(tjDecompressToYUV2(handle, jpegbuf[tile], jpegsize[tile], yuvbuf, width, yuvpad, height, flags)==-1) _throwtj("executing tjDecompressToYUV2()"); startDecode=gettime(); if(tjDecodeYUV(handle, yuvbuf, yuvpad, subsamp, dstptr2, width, pitch, height, pf, flags)==-1) _throwtj("executing tjDecodeYUV()"); if(iter>=0) elapsedDecode+=gettime()-startDecode; } else if(tjDecompress2(handle, jpegbuf[tile], jpegsize[tile], dstptr2, width, pitch, height, pf, flags)==-1) _throwtj("executing tjDecompress2()"); } } iter++; if(iter>=1) { elapsed+=gettime()-start; if(elapsed>=benchtime) break; } } if(doyuv) elapsed-=elapsedDecode; if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); handle=NULL; if(quiet) { printf("%-6s%s", sigfig((double)(w*h)/1000000.*(double)iter/elapsed, 4, tempstr, 1024), quiet==2? "\n":" "); if(doyuv) printf("%s\n", sigfig((double)(w*h)/1000000.*(double)iter/elapsedDecode, 4, tempstr, 1024)); else if(quiet!=2) printf("\n"); } else { printf("%s --> Frame rate: %f fps\n", doyuv? "Decomp to YUV":"Decompress ", (double)iter/elapsed); printf(" Throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)iter/elapsed); if(doyuv) { printf("YUV Decode --> Frame rate: %f fps\n", (double)iter/elapsedDecode); printf(" Throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)iter/elapsedDecode); } } if(sf.num!=1 || sf.denom!=1) snprintf(sizestr, 20, "%d_%d", sf.num, sf.denom); else if(tilew!=w || tileh!=h) snprintf(sizestr, 20, "%dx%d", tilew, tileh); else snprintf(sizestr, 20, "full"); if(decomponly) snprintf(tempstr, 1024, "%s_%s.%s", filename, sizestr, ext); else snprintf(tempstr, 1024, "%s_%s%s_%s.%s", filename, subName[subsamp], qualstr, sizestr, ext); if(savebmp(tempstr, dstbuf, scaledw, scaledh, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("saving bitmap"); ptr=strrchr(tempstr, '.'); snprintf(ptr, 1024-(ptr-tempstr), "-err.%s", ext); if(srcbuf && sf.num==1 && sf.denom==1) { if(!quiet) printf("Compression error written to %s.\n", tempstr); if(subsamp==TJ_GRAYSCALE) { int index, index2; for(row=0, index=0; row<h; row++, index+=pitch) { for(col=0, index2=index; col<w; col++, index2+=ps) { int rindex=index2+tjRedOffset[pf]; int gindex=index2+tjGreenOffset[pf]; int bindex=index2+tjBlueOffset[pf]; int y=(int)((double)srcbuf[rindex]*0.299 + (double)srcbuf[gindex]*0.587 + (double)srcbuf[bindex]*0.114 + 0.5); if(y>255) y=255; if(y<0) y=0; dstbuf[rindex]=abs(dstbuf[rindex]-y); dstbuf[gindex]=abs(dstbuf[gindex]-y); dstbuf[bindex]=abs(dstbuf[bindex]-y); } } } else { for(row=0; row<h; row++) for(col=0; col<w*ps; col++) dstbuf[pitch*row+col] =abs(dstbuf[pitch*row+col]-srcbuf[pitch*row+col]); } if(savebmp(tempstr, dstbuf, w, h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("saving bitmap"); } bailout: if(file) fclose(file); if(handle) tjDestroy(handle); if(dstbuf && dstbufalloc) free(dstbuf); if(yuvbuf) free(yuvbuf); return retval; }
static void TJDecompressor_decodeYUV (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags) { tjhandle handle=0; jsize arraySize=0, actualPitch; jbyteArray jSrcPlanes[3]={NULL, NULL, NULL}; unsigned char *srcPlanes[3], *dstBuf=NULL; int *srcOffsets=NULL, *srcStrides=NULL; int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i; gethandle(); if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP) _throwarg("Invalid argument in decodeYUV()"); if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF || org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP) _throwarg("Mismatch between Java and C API"); if((*env)->GetArrayLength(env, srcobjs)<nc) _throwarg("Planes array is too small for the subsampling type"); if((*env)->GetArrayLength(env, jSrcOffsets)<nc) _throwarg("Offsets array is too small for the subsampling type"); if((*env)->GetArrayLength(env, jSrcStrides)<nc) _throwarg("Strides array is too small for the subsampling type"); actualPitch=(pitch==0)? width*tjPixelSize[pf]:pitch; arraySize=(y+height-1)*actualPitch + (x+width)*tjPixelSize[pf]; if((*env)->GetArrayLength(env, dst)*dstElementSize<arraySize) _throwarg("Destination buffer is not large enough"); bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); for(i=0; i<nc; i++) { int planeSize=tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); int pw=tjPlaneWidth(i, width, subsamp); if(planeSize<0 || pw<0) _throwarg(tjGetErrorStr()); if(srcOffsets[i]<0) _throwarg("Invalid argument in decodeYUV()"); if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0) _throwarg("Negative plane stride would cause memory to be accessed below plane boundary"); bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i)); if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize) _throwarg("Source plane is not large enough"); bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); srcPlanes[i]=&srcPlanes[i][srcOffsets[i]]; } bailif0(dstBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp, &dstBuf[y*actualPitch + x*tjPixelSize[pf]], width, pitch, height, pf, flags)==-1) _throwtj(); bailout: if(dstBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, dstBuf, 0); for(i=0; i<nc; i++) { if(srcPlanes[i] && jSrcPlanes[i]) (*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i], 0); } if(srcStrides) (*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0); if(srcOffsets) (*env)->ReleasePrimitiveArrayCritical(env, jSrcOffsets, srcOffsets, 0); return; }
int decompTest(char *filename) { FILE *file=NULL; tjhandle handle=NULL; unsigned char **jpegbuf=NULL, *srcbuf=NULL; unsigned long *jpegsize=NULL, srcsize, totaljpegsize; tjtransform *t=NULL; int w=0, h=0, subsamp=-1, cs=-1, _w, _h, _tilew, _tileh, _ntilesw, _ntilesh, _subsamp; char *temp=NULL, tempstr[80], tempstr2[80]; int row, col, i, iter, tilew, tileh, ntilesw=1, ntilesh=1, retval=0; double start, elapsed; int ps=tjPixelSize[pf], tile; if((file=fopen(filename, "rb"))==NULL) _throwunix("opening file"); if(fseek(file, 0, SEEK_END)<0 || (srcsize=ftell(file))==(unsigned long)-1) _throwunix("determining file size"); if((srcbuf=(unsigned char *)malloc(srcsize))==NULL) _throwunix("allocating memory"); if(fseek(file, 0, SEEK_SET)<0) _throwunix("setting file position"); if(fread(srcbuf, srcsize, 1, file)<1) _throwunix("reading JPEG data"); fclose(file); file=NULL; temp=strrchr(filename, '.'); if(temp!=NULL) *temp='\0'; if((handle=tjInitTransform())==NULL) _throwtj("executing tjInitTransform()"); if(tjDecompressHeader3(handle, srcbuf, srcsize, &w, &h, &subsamp, &cs)==-1) _throwtj("executing tjDecompressHeader3()"); if(cs==TJCS_YCCK || cs==TJCS_CMYK) { pf=TJPF_CMYK; ps=tjPixelSize[pf]; } if(quiet==1) { printf("All performance values in Mpixels/sec\n\n"); printf("Bitmap JPEG JPEG %s %s Xform Comp Decomp ", dotile? "Tile ":"Image", dotile? "Tile ":"Image"); if(doyuv) printf("Decode"); printf("\n"); printf("Format CS Subsamp Width Height Perf Ratio Perf "); if(doyuv) printf("Perf"); printf("\n\n"); } else if(!quiet) printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", formatName(subsamp, cs, tempstr), pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down"); for(tilew=dotile? 16:w, tileh=dotile? 16:h; ; tilew*=2, tileh*=2) { if(tilew>w) tilew=w; if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG tile array"); memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG size array"); memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); if((flags&TJFLAG_NOREALLOC)!=0 || !dotile) for(i=0; i<ntilesw*ntilesh; i++) { if((jpegbuf[i]=(unsigned char *)tjAlloc(tjBufSize(tilew, tileh, subsamp)))==NULL) _throwunix("allocating JPEG tiles"); } _w=w; _h=h; _tilew=tilew; _tileh=tileh; if(!quiet) { printf("\n%s size: %d x %d", dotile? "Tile":"Image", _tilew, _tileh); if(sf.num!=1 || sf.denom!=1) printf(" --> %d x %d", TJSCALED(_w, sf), TJSCALED(_h, sf)); printf("\n"); } else if(quiet==1) { printf("%-4s (%s) %-5s %-5s ", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", csName[cs], subNameLong[subsamp]); printf("%-5d %-5d ", tilew, tileh); } _subsamp=subsamp; if(dotile || xformop!=TJXOP_NONE || xformopt!=0 || customFilter) { if((t=(tjtransform *)malloc(sizeof(tjtransform)*ntilesw*ntilesh)) ==NULL) _throwunix("allocating image transform array"); if(xformop==TJXOP_TRANSPOSE || xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90 || xformop==TJXOP_ROT270) { _w=h; _h=w; _tilew=tileh; _tileh=tilew; } if(xformopt&TJXOPT_GRAY) _subsamp=TJ_GRAYSCALE; if(xformop==TJXOP_HFLIP || xformop==TJXOP_ROT180) _w=_w-(_w%tjMCUWidth[_subsamp]); if(xformop==TJXOP_VFLIP || xformop==TJXOP_ROT180) _h=_h-(_h%tjMCUHeight[_subsamp]); if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90) _w=_w-(_w%tjMCUHeight[_subsamp]); if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT270) _h=_h-(_h%tjMCUWidth[_subsamp]); _ntilesw=(_w+_tilew-1)/_tilew; _ntilesh=(_h+_tileh-1)/_tileh; if(xformop==TJXOP_TRANSPOSE || xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90 || xformop==TJXOP_ROT270) { if(_subsamp==TJSAMP_422) _subsamp=TJSAMP_440; else if(_subsamp==TJSAMP_440) _subsamp=TJSAMP_422; } for(row=0, tile=0; row<_ntilesh; row++) { for(col=0; col<_ntilesw; col++, tile++) { t[tile].r.w=min(_tilew, _w-col*_tilew); t[tile].r.h=min(_tileh, _h-row*_tileh); t[tile].r.x=col*_tilew; t[tile].r.y=row*_tileh; t[tile].op=xformop; t[tile].options=xformopt|TJXOPT_TRIM; t[tile].customFilter=customFilter; if(t[tile].options&TJXOPT_NOOUTPUT && jpegbuf[tile]) { tjFree(jpegbuf[tile]); jpegbuf[tile]=NULL; } } } iter=-warmup; elapsed=0.; while(1) { start=gettime(); if(tjTransform(handle, srcbuf, srcsize, _ntilesw*_ntilesh, jpegbuf, jpegsize, t, flags)==-1) _throwtj("executing tjTransform()"); iter++; if(iter>=1) { elapsed+=gettime()-start; if(elapsed>=benchtime) break; } } free(t); t=NULL; for(tile=0, totaljpegsize=0; tile<_ntilesw*_ntilesh; tile++) totaljpegsize+=jpegsize[tile]; if(quiet) { printf("%-6s%s%-6s%s", sigfig((double)(w*h)/1000000./elapsed, 4, tempstr, 80), quiet==2? "\n":" ", sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), quiet==2? "\n":" "); } else if(!quiet) { printf("Transform --> Frame rate: %f fps\n", 1.0/elapsed); printf(" Output image size: %lu bytes\n", totaljpegsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)totaljpegsize); printf(" Throughput: %f Megapixels/sec\n", (double)(w*h)/1000000./elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)totaljpegsize*8./1000000./elapsed); } } else { if(quiet==1) printf("N/A N/A "); jpegsize[0]=srcsize; memcpy(jpegbuf[0], srcbuf, srcsize); } if(w==tilew) _tilew=_w; if(h==tileh) _tileh=_h; if(!(xformopt&TJXOPT_NOOUTPUT)) { if(decomp(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0, filename, _tilew, _tileh)==-1) goto bailout; } else if(quiet==1) printf("N/A\n"); for(i=0; i<ntilesw*ntilesh; i++) { tjFree(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(tilew==w && tileh==h) break; } bailout: if(file) {fclose(file); file=NULL;} if(jpegbuf) { for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) tjFree(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; } if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(srcbuf) {free(srcbuf); srcbuf=NULL;} if(t) {free(t); t=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} return retval; }
/* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */ JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth, jintArray jDstStrides, jint desiredHeight, jint flags) { tjhandle handle=0; jbyteArray jDstPlanes[3]={NULL, NULL, NULL}; unsigned char *jpegBuf=NULL, *dstPlanes[3]; int *dstOffsets=NULL, *dstStrides=NULL; int jpegSubsamp=-1, jpegWidth=0, jpegHeight=0; int nc=0, i, width, height, scaledWidth, scaledHeight, nsf=0; tjscalingfactor *sf; gethandle(); if((*env)->GetArrayLength(env, src)<jpegSize) _throwarg("Source buffer is not large enough"); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); nc=(jpegSubsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3); width=desiredWidth; height=desiredHeight; if(width==0) width=jpegWidth; if(height==0) height=jpegHeight; sf=tjGetScalingFactors(&nsf); if(!sf || nsf<1) _throwarg(tjGetErrorStr()); for(i=0; i<nsf; i++) { scaledWidth=TJSCALED(jpegWidth, sf[i]); scaledHeight=TJSCALED(jpegHeight, sf[i]); if(scaledWidth<=width && scaledHeight<=height) break; } bailif0(dstOffsets=(*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0)); bailif0(dstStrides=(*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0)); for(i=0; i<nc; i++) { int planeSize=tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight, jpegSubsamp); int pw=tjPlaneWidth(i, scaledWidth, jpegSubsamp); if(planeSize<0 || pw<0) _throwarg(tjGetErrorStr()); if(dstOffsets[i]<0) _throwarg("Invalid argument in decompressToYUV()"); if(dstStrides[i]<0 && dstOffsets[i]-planeSize+pw<0) _throwarg("Negative plane stride would cause memory to be accessed below plane boundary"); bailif0(jDstPlanes[i]=(*env)->GetObjectArrayElement(env, dstobjs, i)); if((*env)->GetArrayLength(env, jDstPlanes[i])<dstOffsets[i]+planeSize) _throwarg("Destination plane is not large enough"); bailif0(dstPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0)); dstPlanes[i]=&dstPlanes[i][dstOffsets[i]]; } bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0)); if(tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize, dstPlanes, desiredWidth, dstStrides, desiredHeight, flags)==-1) _throwtj(); bailout: if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, jpegBuf, 0); for(i=0; i<nc; i++) { if(dstPlanes[i] && jDstPlanes[i]) (*env)->ReleasePrimitiveArrayCritical(env, jDstPlanes[i], dstPlanes[i], 0); } if(dstStrides) (*env)->ReleasePrimitiveArrayCritical(env, jDstStrides, dstStrides, 0); if(dstOffsets) (*env)->ReleasePrimitiveArrayCritical(env, jDstOffsets, dstOffsets, 0); return; }
void dotestyuv(unsigned char *srcbuf, int w, int h, int subsamp, char *filename) { char tempstr[1024], tempstr2[80]; FILE *file=NULL; tjhandle handle=NULL; unsigned char *dstbuf=NULL; double start, elapsed; int i, retval=0, ps=tjPixelSize[pf]; int yuvsize=0; yuvsize=tjBufSizeYUV(w, h, subsamp); if((dstbuf=(unsigned char *)malloc(yuvsize)) == NULL) _throwunix("allocating image buffer"); if(!quiet) printf(">>>>> %s (%s) <--> YUV %s <<<<<\n", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp]); if(quiet==1) printf("%s\t%s\t%s\tN/A\t", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp]); if((handle=tjInitCompress())==NULL) _throwtj("executing tjInitCompress()"); /* Execute once to preload cache */ if(tjEncodeYUV2(handle, srcbuf, w, 0, h, pf, dstbuf, subsamp, flags)==-1) _throwtj("executing tjEncodeYUV2()"); /* Benchmark */ for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) { if(tjEncodeYUV2(handle, srcbuf, w, 0, h, pf, dstbuf, subsamp, flags)==-1) _throwtj("executing tjEncodeYUV2()"); } if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); handle=NULL; if(quiet==1) printf("%-4d %-4d\t", w, h); if(quiet) { printf("%s%c%s%c", sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024), quiet==2? '\n':'\t', sigfig((double)(w*h*ps)/(double)yuvsize, 4, tempstr2, 80), quiet==2? '\n':'\t'); } else { printf("\n%s size: %d x %d\n", "Image", w, h); printf("C--> Frame rate: %f fps\n", (double)i/elapsed); printf(" Output image size: %d bytes\n", yuvsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)yuvsize); printf(" Source throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)i/elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)yuvsize*8./1000000.*(double)i/elapsed); } snprintf(tempstr, 1024, "%s_%s.yuv", filename, subName[subsamp]); if((file=fopen(tempstr, "wb"))==NULL) _throwunix("opening reference image"); if(fwrite(dstbuf, yuvsize, 1, file)!=1) _throwunix("writing reference image"); fclose(file); file=NULL; if(!quiet) printf("Reference image written to %s\n", tempstr); bailout: if(file) {fclose(file); file=NULL;} if(dstbuf) {free(dstbuf); dstbuf=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} return; }
int main(int argc, char *argv[]) { unsigned char *srcbuf=NULL; int w=0, h=0, i, j; int minqual=-1, maxqual=-1; char *temp; int minarg=2, retval=0, subsamp=-1; if((scalingfactors=tjGetScalingFactors(&nsf))==NULL || nsf==0) _throwtj("executing tjGetScalingFactors()"); if(argc<minarg) usage(argv[0]); temp=strrchr(argv[1], '.'); if(temp!=NULL) { if(!strcasecmp(temp, ".bmp")) ext="bmp"; if(!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) decomponly=1; } printf("\n"); if(!decomponly) { minarg=3; if(argc<minarg) usage(argv[0]); if((minqual=atoi(argv[2]))<1 || minqual>100) { puts("ERROR: Quality must be between 1 and 100."); exit(1); } if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1 && sscanf(&temp[1], "%d", &maxqual)==1 && maxqual>minqual && maxqual>=1 && maxqual<=100) {} else maxqual=minqual; } if(argc>minarg) { for(i=minarg; i<argc; i++) { if(!strcasecmp(argv[i], "-tile")) { dotile=1; xformopt|=TJXOPT_CROP; } if(!strcasecmp(argv[i], "-fastupsample")) { printf("Using fast upsampling code\n\n"); flags|=TJFLAG_FASTUPSAMPLE; } if(!strcasecmp(argv[i], "-fastdct")) { printf("Using fastest DCT/IDCT algorithm\n\n"); flags|=TJFLAG_FASTDCT; } if(!strcasecmp(argv[i], "-accuratedct")) { printf("Using most accurate DCT/IDCT algorithm\n\n"); flags|=TJFLAG_ACCURATEDCT; } if(!strcasecmp(argv[i], "-rgb")) pf=TJPF_RGB; if(!strcasecmp(argv[i], "-rgbx")) pf=TJPF_RGBX; if(!strcasecmp(argv[i], "-bgr")) pf=TJPF_BGR; if(!strcasecmp(argv[i], "-bgrx")) pf=TJPF_BGRX; if(!strcasecmp(argv[i], "-xbgr")) pf=TJPF_XBGR; if(!strcasecmp(argv[i], "-xrgb")) pf=TJPF_XRGB; if(!strcasecmp(argv[i], "-cmyk")) pf=TJPF_CMYK; if(!strcasecmp(argv[i], "-bottomup")) flags|=TJFLAG_BOTTOMUP; if(!strcasecmp(argv[i], "-quiet")) quiet=1; if(!strcasecmp(argv[i], "-qq")) quiet=2; if(!strcasecmp(argv[i], "-scale") && i<argc-1) { int temp1=0, temp2=0, match=0; if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2) { for(j=0; j<nsf; j++) { if((double)temp1/(double)temp2 == (double)scalingfactors[j].num/(double)scalingfactors[j].denom) { sf=scalingfactors[j]; match=1; break; } } if(!match) usage(argv[0]); } else usage(argv[0]); } if(!strcasecmp(argv[i], "-hflip")) xformop=TJXOP_HFLIP; if(!strcasecmp(argv[i], "-vflip")) xformop=TJXOP_VFLIP; if(!strcasecmp(argv[i], "-transpose")) xformop=TJXOP_TRANSPOSE; if(!strcasecmp(argv[i], "-transverse")) xformop=TJXOP_TRANSVERSE; if(!strcasecmp(argv[i], "-rot90")) xformop=TJXOP_ROT90; if(!strcasecmp(argv[i], "-rot180")) xformop=TJXOP_ROT180; if(!strcasecmp(argv[i], "-rot270")) xformop=TJXOP_ROT270; if(!strcasecmp(argv[i], "-grayscale")) xformopt|=TJXOPT_GRAY; if(!strcasecmp(argv[i], "-custom")) customFilter=dummyDCTFilter; if(!strcasecmp(argv[i], "-nooutput")) xformopt|=TJXOPT_NOOUTPUT; if(!strcasecmp(argv[i], "-benchtime") && i<argc-1) { double temp=atof(argv[++i]); if(temp>0.0) benchtime=temp; else usage(argv[0]); } if(!strcasecmp(argv[i], "-warmup") && i<argc-1) { int temp=atoi(argv[++i]); if(temp>=0) { warmup=temp; printf("Warmup runs = %d\n\n", warmup); } else usage(argv[0]); } if(!strcmp(argv[i], "-?")) usage(argv[0]); if(!strcasecmp(argv[i], "-alloc")) flags&=(~TJFLAG_NOREALLOC); if(!strcasecmp(argv[i], "-bmp")) ext="bmp"; if(!strcasecmp(argv[i], "-yuv")) { printf("Testing YUV planar encoding/decoding\n\n"); doyuv=1; } if(!strcasecmp(argv[i], "-yuvpad") && i<argc-1) { int temp=atoi(argv[++i]); if(temp>=1) yuvpad=temp; } if(!strcasecmp(argv[i], "-subsamp") && i<argc-1) { i++; if(toupper(argv[i][0])=='G') subsamp=TJSAMP_GRAY; else { int temp=atoi(argv[i]); switch(temp) { case 444: subsamp=TJSAMP_444; break; case 422: subsamp=TJSAMP_422; break; case 440: subsamp=TJSAMP_440; break; case 420: subsamp=TJSAMP_420; break; case 411: subsamp=TJSAMP_411; break; } } } if(!strcasecmp(argv[i], "-componly")) componly=1; } } if((sf.num!=1 || sf.denom!=1) && dotile) { printf("Disabling tiled compression/decompression tests, because those tests do not\n"); printf("work when scaled decompression is enabled.\n"); dotile=0; } if((flags&TJFLAG_NOREALLOC)==0 && dotile) { printf("Disabling tiled compression/decompression tests, because those tests do not\n"); printf("work when dynamic JPEG buffer allocation is enabled.\n\n"); dotile=0; } if(!decomponly) { if(loadbmp(argv[1], &srcbuf, &w, &h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("loading bitmap"); temp=strrchr(argv[1], '.'); if(temp!=NULL) *temp='\0'; } if(quiet==1 && !decomponly) { printf("All performance values in Mpixels/sec\n\n"); printf("Bitmap JPEG JPEG %s %s ", dotile? "Tile ":"Image", dotile? "Tile ":"Image"); if(doyuv) printf("Encode "); printf("Comp Comp Decomp "); if(doyuv) printf("Decode"); printf("\n"); printf("Format Subsamp Qual Width Height "); if(doyuv) printf("Perf "); printf("Perf Ratio Perf "); if(doyuv) printf("Perf"); printf("\n\n"); } if(decomponly) { decompTest(argv[1]); printf("\n"); goto bailout; } if(subsamp>=0 && subsamp<TJ_NUMSAMP) { for(i=maxqual; i>=minqual; i--) fullTest(srcbuf, w, h, subsamp, i, argv[1]); printf("\n"); } else { if(pf!=TJPF_CMYK) { for(i=maxqual; i>=minqual; i--) fullTest(srcbuf, w, h, TJSAMP_GRAY, i, argv[1]); printf("\n"); } for(i=maxqual; i>=minqual; i--) fullTest(srcbuf, w, h, TJSAMP_420, i, argv[1]); printf("\n"); for(i=maxqual; i>=minqual; i--) fullTest(srcbuf, w, h, TJSAMP_422, i, argv[1]); printf("\n"); for(i=maxqual; i>=minqual; i--) fullTest(srcbuf, w, h, TJSAMP_444, i, argv[1]); printf("\n"); } bailout: if(srcbuf) free(srcbuf); return retval; }
/* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets, jint width, jintArray jSrcStrides, jint height, jint subsamp, jbyteArray dst, jint jpegQual, jint flags) { tjhandle handle=0; unsigned long jpegSize=0; jbyteArray jSrcPlanes[3]={NULL, NULL, NULL}; unsigned char *srcPlanes[3], *jpegBuf=NULL; int *srcOffsets=NULL, *srcStrides=NULL; int nc=(subsamp==org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY? 1:3), i; gethandle(); if(subsamp<0 || subsamp>=org_libjpegturbo_turbojpeg_TJ_NUMSAMP) _throwarg("Invalid argument in compressFromYUV()"); if(org_libjpegturbo_turbojpeg_TJ_NUMSAMP!=TJ_NUMSAMP) _throwarg("Mismatch between Java and C API"); if((*env)->GetArrayLength(env, srcobjs)<nc) _throwarg("Planes array is too small for the subsampling type"); if((*env)->GetArrayLength(env, jSrcOffsets)<nc) _throwarg("Offsets array is too small for the subsampling type"); if((*env)->GetArrayLength(env, jSrcStrides)<nc) _throwarg("Strides array is too small for the subsampling type"); jpegSize=tjBufSize(width, height, subsamp); if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize) _throwarg("Destination buffer is not large enough"); bailif0(srcOffsets=(*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0)); bailif0(srcStrides=(*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0)); for(i=0; i<nc; i++) { int planeSize=tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp); int pw=tjPlaneWidth(i, width, subsamp); if(planeSize<0 || pw<0) _throwarg(tjGetErrorStr()); if(srcOffsets[i]<0) _throwarg("Invalid argument in compressFromYUV()"); if(srcStrides[i]<0 && srcOffsets[i]-planeSize+pw<0) _throwarg("Negative plane stride would cause memory to be accessed below plane boundary"); bailif0(jSrcPlanes[i]=(*env)->GetObjectArrayElement(env, srcobjs, i)); if((*env)->GetArrayLength(env, jSrcPlanes[i])<srcOffsets[i]+planeSize) _throwarg("Source plane is not large enough"); bailif0(srcPlanes[i]=(*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0)); srcPlanes[i]=&srcPlanes[i][srcOffsets[i]]; } bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0)); if(ProcessSystemProperties(env)<0) goto bailout; if(tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height, subsamp, &jpegBuf, &jpegSize, jpegQual, flags|TJFLAG_NOREALLOC)==-1) _throwtj(); bailout: if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0); for(i=0; i<nc; i++) { if(srcPlanes[i] && jSrcPlanes[i]) (*env)->ReleasePrimitiveArrayCritical(env, jSrcPlanes[i], srcPlanes[i], 0); } if(srcStrides) (*env)->ReleasePrimitiveArrayCritical(env, jSrcStrides, srcStrides, 0); if(srcOffsets) (*env)->ReleasePrimitiveArrayCritical(env, jSrcOffsets, srcOffsets, 0); return (jint)jpegSize; }
void dotest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual, char *filename) { char tempstr[1024], tempstr2[80]; FILE *file=NULL; tjhandle handle=NULL; unsigned char **jpegbuf=NULL, *tmpbuf=NULL, *srcptr, *srcptr2; double start, elapsed; int totaljpegsize=0, row, col, i, tilew=w, tileh=h, retval=0; unsigned long *jpegsize=NULL; int ps=tjPixelSize[pf], ntilesw=1, ntilesh=1, pitch=w*ps; if(yuv==YUVENCODE) {dotestyuv(srcbuf, w, h, subsamp, filename); return;} if((tmpbuf=(unsigned char *)malloc(pitch*h)) == NULL) _throwunix("allocating temporary image buffer"); if(!quiet) printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp], jpegqual); for(tilew=dotile? 8:w, tileh=dotile? 8:h; ; tilew*=2, tileh*=2) { if(tilew>w) tilew=w; if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG tile array"); memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG size array"); memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); if((flags&TJFLAG_NOREALLOC)!=0) for(i=0; i<ntilesw*ntilesh; i++) { if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh, subsamp)))==NULL) _throwunix("allocating JPEG tiles"); } /* Compression test */ if(quiet==1) printf("%s\t%s\t%s\t%d\t", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp], jpegqual); for(i=0; i<h; i++) memcpy(&tmpbuf[pitch*i], &srcbuf[w*ps*i], w*ps); if((handle=tjInitCompress())==NULL) _throwtj("executing tjInitCompress()"); /* Execute once to preload cache */ if(tjCompress2(handle, srcbuf, tilew, pitch, tileh, pf, &jpegbuf[0], &jpegsize[0], subsamp, jpegqual, flags)==-1) _throwtj("executing tjCompress2()"); /* Benchmark */ for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) { int tile=0; totaljpegsize=0; for(row=0, srcptr=srcbuf; row<ntilesh; row++, srcptr+=pitch*tileh) { for(col=0, srcptr2=srcptr; col<ntilesw; col++, tile++, srcptr2+=ps*tilew) { int width=min(tilew, w-col*tilew); int height=min(tileh, h-row*tileh); if(tjCompress2(handle, srcptr2, width, pitch, height, pf, &jpegbuf[tile], &jpegsize[tile], subsamp, jpegqual, flags)==-1) _throwtj("executing tjCompress()2"); totaljpegsize+=jpegsize[tile]; } } } if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); handle=NULL; if(quiet==1) printf("%-4d %-4d\t", tilew, tileh); if(quiet) { printf("%s%c%s%c", sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024), quiet==2? '\n':'\t', sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), quiet==2? '\n':'\t'); } else { printf("\n%s size: %d x %d\n", dotile? "Tile":"Image", tilew, tileh); printf("C--> Frame rate: %f fps\n", (double)i/elapsed); printf(" Output image size: %d bytes\n", totaljpegsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)totaljpegsize); printf(" Source throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)i/elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)totaljpegsize*8./1000000.*(double)i/elapsed); } if(tilew==w && tileh==h) { snprintf(tempstr, 1024, "%s_%s_Q%d.jpg", filename, subName[subsamp], jpegqual); if((file=fopen(tempstr, "wb"))==NULL) _throwunix("opening reference image"); if(fwrite(jpegbuf[0], jpegsize[0], 1, file)!=1) _throwunix("writing reference image"); fclose(file); file=NULL; if(!quiet) printf("Reference image written to %s\n", tempstr); } /* Decompression test */ if(decomptest(srcbuf, jpegbuf, jpegsize, tmpbuf, w, h, subsamp, jpegqual, filename, tilew, tileh)==-1) goto bailout; for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; free(jpegsize); jpegsize=NULL; if(tilew==w && tileh==h) break; } bailout: if(file) {fclose(file); file=NULL;} if(jpegbuf) { for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; } if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} return; }
int fullTest(unsigned char *srcbuf, int w, int h, int subsamp, int jpegqual, char *filename) { char tempstr[1024], tempstr2[80]; FILE *file=NULL; tjhandle handle=NULL; unsigned char **jpegbuf=NULL, *yuvbuf=NULL, *tmpbuf=NULL, *srcptr, *srcptr2; double start, elapsed, elapsedEncode; int totaljpegsize=0, row, col, i, tilew=w, tileh=h, retval=0; int iter, yuvsize=0; unsigned long *jpegsize=NULL; int ps=tjPixelSize[pf]; int ntilesw=1, ntilesh=1, pitch=w*ps; const char *pfStr=pixFormatStr[pf]; if((tmpbuf=(unsigned char *)malloc(pitch*h)) == NULL) _throwunix("allocating temporary image buffer"); if(!quiet) printf(">>>>> %s (%s) <--> JPEG %s Q%d <<<<<\n", pfStr, (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down", subNameLong[subsamp], jpegqual); for(tilew=dotile? 8:w, tileh=dotile? 8:h; ; tilew*=2, tileh*=2) { if(tilew>w) tilew=w; if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG tile array"); memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG size array"); memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); if((flags&TJFLAG_NOREALLOC)!=0) for(i=0; i<ntilesw*ntilesh; i++) { if((jpegbuf[i]=(unsigned char *)tjAlloc(tjBufSize(tilew, tileh, subsamp)))==NULL) _throwunix("allocating JPEG tiles"); } /* Compression test */ if(quiet==1) printf("%-4s (%s) %-5s %-3d ", pfStr, (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp], jpegqual); for(i=0; i<h; i++) memcpy(&tmpbuf[pitch*i], &srcbuf[w*ps*i], w*ps); if((handle=tjInitCompress())==NULL) _throwtj("executing tjInitCompress()"); if(doyuv) { yuvsize=tjBufSizeYUV2(tilew, yuvpad, tileh, subsamp); if((yuvbuf=(unsigned char *)malloc(yuvsize))==NULL) _throwunix("allocating YUV buffer"); memset(yuvbuf, 127, yuvsize); } /* Benchmark */ iter=-warmup; elapsed=elapsedEncode=0.; while(1) { int tile=0; totaljpegsize=0; start=gettime(); for(row=0, srcptr=srcbuf; row<ntilesh; row++, srcptr+=pitch*tileh) { for(col=0, srcptr2=srcptr; col<ntilesw; col++, tile++, srcptr2+=ps*tilew) { int width=min(tilew, w-col*tilew); int height=min(tileh, h-row*tileh); if(doyuv) { double startEncode=gettime(); if(tjEncodeYUV3(handle, srcptr2, width, pitch, height, pf, yuvbuf, yuvpad, subsamp, flags)==-1) _throwtj("executing tjEncodeYUV3()"); if(iter>=0) elapsedEncode+=gettime()-startEncode; if(tjCompressFromYUV(handle, yuvbuf, width, yuvpad, height, subsamp, &jpegbuf[tile], &jpegsize[tile], jpegqual, flags)==-1) _throwtj("executing tjCompressFromYUV()"); } else { if(tjCompress2(handle, srcptr2, width, pitch, height, pf, &jpegbuf[tile], &jpegsize[tile], subsamp, jpegqual, flags)==-1) _throwtj("executing tjCompress2()"); } totaljpegsize+=jpegsize[tile]; } } iter++; if(iter>=1) { elapsed+=gettime()-start; if(elapsed>=benchtime) break; } } if(doyuv) elapsed-=elapsedEncode; if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); handle=NULL; if(quiet==1) printf("%-5d %-5d ", tilew, tileh); if(quiet) { if(doyuv) printf("%-6s%s", sigfig((double)(w*h)/1000000.*(double)iter/elapsedEncode, 4, tempstr, 1024), quiet==2? "\n":" "); printf("%-6s%s", sigfig((double)(w*h)/1000000.*(double)iter/elapsed, 4, tempstr, 1024), quiet==2? "\n":" "); printf("%-6s%s", sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), quiet==2? "\n":" "); } else { printf("\n%s size: %d x %d\n", dotile? "Tile":"Image", tilew, tileh); if(doyuv) { printf("Encode YUV --> Frame rate: %f fps\n", (double)iter/elapsedEncode); printf(" Output image size: %d bytes\n", yuvsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)yuvsize); printf(" Throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)iter/elapsedEncode); printf(" Output bit stream: %f Megabits/sec\n", (double)yuvsize*8./1000000.*(double)iter/elapsedEncode); } printf("%s --> Frame rate: %f fps\n", doyuv? "Comp from YUV":"Compress ", (double)iter/elapsed); printf(" Output image size: %d bytes\n", totaljpegsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)totaljpegsize); printf(" Throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)iter/elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)totaljpegsize*8./1000000.*(double)iter/elapsed); } if(tilew==w && tileh==h) { snprintf(tempstr, 1024, "%s_%s_Q%d.jpg", filename, subName[subsamp], jpegqual); if((file=fopen(tempstr, "wb"))==NULL) _throwunix("opening reference image"); if(fwrite(jpegbuf[0], jpegsize[0], 1, file)!=1) _throwunix("writing reference image"); fclose(file); file=NULL; if(!quiet) printf("Reference image written to %s\n", tempstr); } /* Decompression test */ if(!componly) { if(decomp(srcbuf, jpegbuf, jpegsize, tmpbuf, w, h, subsamp, jpegqual, filename, tilew, tileh)==-1) goto bailout; } for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) tjFree(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; free(jpegsize); jpegsize=NULL; if(doyuv) { free(yuvbuf); yuvbuf=NULL; } if(tilew==w && tileh==h) break; } bailout: if(file) {fclose(file); file=NULL;} if(jpegbuf) { for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) tjFree(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; } if(yuvbuf) {free(yuvbuf); yuvbuf=NULL;} if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(tmpbuf) {free(tmpbuf); tmpbuf=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} return retval; }
/* TurboJPEG 1.2.x: TJTransformer::transform() */ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize, jobjectArray dstobjs, jobjectArray tobjs, jint flags) { tjhandle handle=0; int i; unsigned char *jpegBuf=NULL, **dstBufs=NULL; jsize n=0; unsigned long *dstSizes=NULL; tjtransform *t=NULL; jbyteArray *jdstBufs=NULL; int jpegWidth=0, jpegHeight=0, jpegSubsamp; jintArray jdstSizes=0; jint *dstSizesi=NULL; JNICustomFilterParams *params=NULL; gethandle(); if((*env)->GetArrayLength(env, jsrcBuf)<jpegSize) _throwarg("Source buffer is not large enough"); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegWidth", "I")); jpegWidth=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegHeight", "I")); jpegHeight=(int)(*env)->GetIntField(env, obj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "jpegSubsamp", "I")); jpegSubsamp=(int)(*env)->GetIntField(env, obj, _fid); n=(*env)->GetArrayLength(env, dstobjs); if(n!=(*env)->GetArrayLength(env, tobjs)) _throwarg("Mismatch between size of transforms array and destination buffers array"); if((dstBufs=(unsigned char **)malloc(sizeof(unsigned char *)*n))==NULL) _throwmem(); if((jdstBufs=(jbyteArray *)malloc(sizeof(jbyteArray)*n))==NULL) _throwmem(); if((dstSizes=(unsigned long *)malloc(sizeof(unsigned long)*n))==NULL) _throwmem(); if((t=(tjtransform *)malloc(sizeof(tjtransform)*n))==NULL) _throwmem(); if((params=(JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams)*n)) ==NULL) _throwmem(); for(i=0; i<n; i++) { dstBufs[i]=NULL; jdstBufs[i]=NULL; dstSizes[i]=0; memset(&t[i], 0, sizeof(tjtransform)); memset(¶ms[i], 0, sizeof(JNICustomFilterParams)); } for(i=0; i<n; i++) { jobject tobj, cfobj; bailif0(tobj=(*env)->GetObjectArrayElement(env, tobjs, i)); bailif0(_cls=(*env)->GetObjectClass(env, tobj)); bailif0(_fid=(*env)->GetFieldID(env, _cls, "op", "I")); t[i].op=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "options", "I")); t[i].options=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "x", "I")); t[i].r.x=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "y", "I")); t[i].r.y=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "width", "I")); t[i].r.w=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "height", "I")); t[i].r.h=(*env)->GetIntField(env, tobj, _fid); bailif0(_fid=(*env)->GetFieldID(env, _cls, "cf", "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;")); cfobj=(*env)->GetObjectField(env, tobj, _fid); if(cfobj) { params[i].env=env; params[i].tobj=tobj; params[i].cfobj=cfobj; t[i].customFilter=JNICustomFilter; t[i].data=(void *)¶ms[i]; } } for(i=0; i<n; i++) { int w=jpegWidth, h=jpegHeight; if(t[i].r.w!=0) w=t[i].r.w; if(t[i].r.h!=0) h=t[i].r.h; bailif0(jdstBufs[i]=(*env)->GetObjectArrayElement(env, dstobjs, i)); if((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) <tjBufSize(w, h, jpegSubsamp)) _throwarg("Destination buffer is not large enough"); } bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0)); for(i=0; i<n; i++) bailif0(dstBufs[i]=(*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0)); if(tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t, flags|TJFLAG_NOREALLOC)==-1) _throwtj(); for(i=0; i<n; i++) { (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0); dstBufs[i]=NULL; } (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0); jpegBuf=NULL; jdstSizes=(*env)->NewIntArray(env, n); bailif0(dstSizesi=(*env)->GetIntArrayElements(env, jdstSizes, 0)); for(i=0; i<n; i++) dstSizesi[i]=(int)dstSizes[i]; bailout: if(dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0); if(dstBufs) { for(i=0; i<n; i++) { if(dstBufs[i] && jdstBufs && jdstBufs[i]) (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0); } free(dstBufs); } if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, jsrcBuf, jpegBuf, 0); if(jdstBufs) free(jdstBufs); if(dstSizes) free(dstSizes); if(t) free(t); return jdstSizes; }
/* Decompression test */ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf, unsigned long *jpegsize, unsigned char *dstbuf, int w, int h, int subsamp, int jpegqual, char *filename, int tilew, int tileh) { char tempstr[1024], sizestr[20]="\0", qualstr[6]="\0", *ptr; FILE *file=NULL; tjhandle handle=NULL; int row, col, i, dstbufalloc=0, retval=0; double start, elapsed; int ps=tjPixelSize[pf]; int yuvsize=tjBufSizeYUV(w, h, subsamp), bufsize; int scaledw=(yuv==YUVDECODE)? w : TJSCALED(w, sf); int scaledh=(yuv==YUVDECODE)? h : TJSCALED(h, sf); int pitch=scaledw*ps; int ntilesw=(w+tilew-1)/tilew, ntilesh=(h+tileh-1)/tileh; unsigned char *dstptr, *dstptr2; if(jpegqual>0) { snprintf(qualstr, 6, "_Q%d", jpegqual); qualstr[5]=0; } if((handle=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()"); bufsize=(yuv==YUVDECODE? yuvsize:pitch*h); if(dstbuf==NULL) { if((dstbuf=(unsigned char *)malloc(bufsize)) == NULL) _throwunix("allocating image buffer"); dstbufalloc=1; } /* Set the destination buffer to gray so we know whether the decompressor attempted to write to it */ memset(dstbuf, 127, bufsize); /* Execute once to preload cache */ if(yuv==YUVDECODE) { if(tjDecompressToYUV(handle, jpegbuf[0], jpegsize[0], dstbuf, flags)==-1) _throwtj("executing tjDecompressToYUV()"); } else if(tjDecompress2(handle, jpegbuf[0], jpegsize[0], dstbuf, scaledw, pitch, scaledh, pf, flags)==-1) _throwtj("executing tjDecompress2()"); /* Benchmark */ for(i=0, start=gettime(); (elapsed=gettime()-start)<benchtime; i++) { int tile=0; if(yuv==YUVDECODE) { if(tjDecompressToYUV(handle, jpegbuf[0], jpegsize[0], dstbuf, flags)==-1) _throwtj("executing tjDecompressToYUV()"); } else for(row=0, dstptr=dstbuf; row<ntilesh; row++, dstptr+=pitch*tileh) { for(col=0, dstptr2=dstptr; col<ntilesw; col++, tile++, dstptr2+=ps*tilew) { int width=dotile? min(tilew, w-col*tilew):scaledw; int height=dotile? min(tileh, h-row*tileh):scaledh; if(tjDecompress2(handle, jpegbuf[tile], jpegsize[tile], dstptr2, width, pitch, height, pf, flags)==-1) _throwtj("executing tjDecompress2()"); } } } if(tjDestroy(handle)==-1) _throwtj("executing tjDestroy()"); handle=NULL; if(quiet) { printf("%s\n", sigfig((double)(w*h)/1000000.*(double)i/elapsed, 4, tempstr, 1024)); } else { printf("D--> Frame rate: %f fps\n", (double)i/elapsed); printf(" Dest. throughput: %f Megapixels/sec\n", (double)(w*h)/1000000.*(double)i/elapsed); } if(yuv==YUVDECODE) { snprintf(tempstr, 1024, "%s_%s%s.yuv", filename, subName[subsamp], qualstr); if((file=fopen(tempstr, "wb"))==NULL) _throwunix("opening YUV image for output"); if(fwrite(dstbuf, yuvsize, 1, file)!=1) _throwunix("writing YUV image"); fclose(file); file=NULL; } else { if(sf.num!=1 || sf.denom!=1) snprintf(sizestr, 20, "%d_%d", sf.num, sf.denom); else if(tilew!=w || tileh!=h) snprintf(sizestr, 20, "%dx%d", tilew, tileh); else snprintf(sizestr, 20, "full"); if(decomponly) snprintf(tempstr, 1024, "%s_%s.%s", filename, sizestr, ext); else snprintf(tempstr, 1024, "%s_%s%s_%s.%s", filename, subName[subsamp], qualstr, sizestr, ext); if(savebmp(tempstr, dstbuf, scaledw, scaledh, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("saving bitmap"); ptr=strrchr(tempstr, '.'); snprintf(ptr, 1024-(ptr-tempstr), "-err.%s", ext); if(srcbuf && sf.num==1 && sf.denom==1) { if(!quiet) printf("Compression error written to %s.\n", tempstr); if(subsamp==TJ_GRAYSCALE) { int index, index2; for(row=0, index=0; row<h; row++, index+=pitch) { for(col=0, index2=index; col<w; col++, index2+=ps) { int rindex=index2+tjRedOffset[pf]; int gindex=index2+tjGreenOffset[pf]; int bindex=index2+tjBlueOffset[pf]; int y=(int)((double)srcbuf[rindex]*0.299 + (double)srcbuf[gindex]*0.587 + (double)srcbuf[bindex]*0.114 + 0.5); if(y>255) y=255; if(y<0) y=0; dstbuf[rindex]=abs(dstbuf[rindex]-y); dstbuf[gindex]=abs(dstbuf[gindex]-y); dstbuf[bindex]=abs(dstbuf[bindex]-y); } } } else { for(row=0; row<h; row++) for(col=0; col<w*ps; col++) dstbuf[pitch*row+col] =abs(dstbuf[pitch*row+col]-srcbuf[pitch*row+col]); } if(savebmp(tempstr, dstbuf, w, h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("saving bitmap"); } } bailout: if(file) {fclose(file); file=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} if(dstbuf && dstbufalloc) {free(dstbuf); dstbuf=NULL;} return retval; }
int main(int argc, char *argv[]) { unsigned char *srcbuf=NULL; int w, h, i, j; int minqual=-1, maxqual=-1; char *temp; int minarg=2; int retval=0; if((scalingfactors=tjGetScalingFactors(&nsf))==NULL || nsf==0) _throwtj("executing tjGetScalingFactors()"); if(argc<minarg) usage(argv[0]); temp=strrchr(argv[1], '.'); if(temp!=NULL) { if(!strcasecmp(temp, ".bmp")) ext="bmp"; if(!strcasecmp(temp, ".jpg") || !strcasecmp(temp, ".jpeg")) decomponly=1; } printf("\n"); if(argc>minarg) { for(i=minarg; i<argc; i++) { if(!strcasecmp(argv[i], "-yuvencode")) { printf("Testing YUV planar encoding\n\n"); yuv=YUVENCODE; maxqual=minqual=100; } if(!strcasecmp(argv[i], "-yuvdecode")) { printf("Testing YUV planar decoding\n\n"); yuv=YUVDECODE; } } } if(!decomponly && yuv!=YUVENCODE) { minarg=3; if(argc<minarg) usage(argv[0]); if((minqual=atoi(argv[2]))<1 || minqual>100) { puts("ERROR: Quality must be between 1 and 100."); exit(1); } if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1 && sscanf(&temp[1], "%d", &maxqual)==1 && maxqual>minqual && maxqual>=1 && maxqual<=100) {} else maxqual=minqual; } if(argc>minarg) { for(i=minarg; i<argc; i++) { if(!strcasecmp(argv[i], "-tile")) { dotile=1; xformopt|=TJXOPT_CROP; } if(!strcasecmp(argv[i], "-forcesse3")) { printf("Forcing SSE3 code\n\n"); flags|=TJFLAG_FORCESSE3; } if(!strcasecmp(argv[i], "-forcesse2")) { printf("Forcing SSE2 code\n\n"); flags|=TJFLAG_FORCESSE2; } if(!strcasecmp(argv[i], "-forcesse")) { printf("Forcing SSE code\n\n"); flags|=TJFLAG_FORCESSE; } if(!strcasecmp(argv[i], "-forcemmx")) { printf("Forcing MMX code\n\n"); flags|=TJFLAG_FORCEMMX; } if(!strcasecmp(argv[i], "-fastupsample")) { printf("Using fast upsampling code\n\n"); flags|=TJFLAG_FASTUPSAMPLE; } if(!strcasecmp(argv[i], "-rgb")) pf=TJPF_RGB; if(!strcasecmp(argv[i], "-rgbx")) pf=TJPF_RGBX; if(!strcasecmp(argv[i], "-bgr")) pf=TJPF_BGR; if(!strcasecmp(argv[i], "-bgrx")) pf=TJPF_BGRX; if(!strcasecmp(argv[i], "-xbgr")) pf=TJPF_XBGR; if(!strcasecmp(argv[i], "-xrgb")) pf=TJPF_XRGB; if(!strcasecmp(argv[i], "-bottomup")) flags|=TJFLAG_BOTTOMUP; if(!strcasecmp(argv[i], "-quiet")) quiet=1; if(!strcasecmp(argv[i], "-qq")) quiet=2; if(!strcasecmp(argv[i], "-scale") && i<argc-1) { int temp1=0, temp2=0, match=0; if(sscanf(argv[++i], "%d/%d", &temp1, &temp2)==2) { for(j=0; j<nsf; j++) { if(temp1==scalingfactors[j].num && temp2==scalingfactors[j].denom) { sf=scalingfactors[j]; match=1; break; } } if(!match) usage(argv[0]); } else usage(argv[0]); } if(!strcasecmp(argv[i], "-hflip")) xformop=TJXOP_HFLIP; if(!strcasecmp(argv[i], "-vflip")) xformop=TJXOP_VFLIP; if(!strcasecmp(argv[i], "-transpose")) xformop=TJXOP_TRANSPOSE; if(!strcasecmp(argv[i], "-transverse")) xformop=TJXOP_TRANSVERSE; if(!strcasecmp(argv[i], "-rot90")) xformop=TJXOP_ROT90; if(!strcasecmp(argv[i], "-rot180")) xformop=TJXOP_ROT180; if(!strcasecmp(argv[i], "-rot270")) xformop=TJXOP_ROT270; if(!strcasecmp(argv[i], "-grayscale")) xformopt|=TJXOPT_GRAY; if(!strcasecmp(argv[i], "-benchtime") && i<argc-1) { double temp=atof(argv[++i]); if(temp>0.0) benchtime=temp; else usage(argv[0]); } if(!strcmp(argv[i], "-?")) usage(argv[0]); if(!strcasecmp(argv[i], "-alloc")) flags&=(~TJFLAG_NOREALLOC); if(!strcasecmp(argv[i], "-bmp")) ext="bmp"; } } if((sf.num!=1 || sf.denom!=1) && dotile) { printf("Disabling tiled compression/decompression tests, because those tests do not\n"); printf("work when scaled decompression is enabled.\n"); dotile=0; } if(yuv && dotile) { printf("Disabling tiled compression/decompression tests, because those tests do not\n"); printf("work when YUV encoding or decoding is enabled.\n\n"); dotile=0; } if(!decomponly) { if(loadbmp(argv[1], &srcbuf, &w, &h, pf, (flags&TJFLAG_BOTTOMUP)!=0)==-1) _throwbmp("loading bitmap"); temp=strrchr(argv[1], '.'); if(temp!=NULL) *temp='\0'; } if(quiet==1 && !decomponly) { printf("All performance values in Mpixels/sec\n\n"); printf("Bitmap\tBitmap\tJPEG\tJPEG\t%s %s \tComp\tComp\tDecomp\n", dotile? "Tile ":"Image", dotile? "Tile ":"Image"); printf("Format\tOrder\tSubsamp\tQual\tWidth Height\tPerf \tRatio\tPerf\n\n"); } if(decomponly) { dodecomptest(argv[1]); printf("\n"); goto bailout; } for(i=maxqual; i>=minqual; i--) dotest(srcbuf, w, h, TJ_GRAYSCALE, i, argv[1]); printf("\n"); for(i=maxqual; i>=minqual; i--) dotest(srcbuf, w, h, TJ_420, i, argv[1]); printf("\n"); for(i=maxqual; i>=minqual; i--) dotest(srcbuf, w, h, TJ_422, i, argv[1]); printf("\n"); for(i=maxqual; i>=minqual; i--) dotest(srcbuf, w, h, TJ_444, i, argv[1]); printf("\n"); bailout: if(srcbuf) free(srcbuf); return retval; }
void dodecomptest(char *filename) { FILE *file=NULL; tjhandle handle=NULL; unsigned char **jpegbuf=NULL, *srcbuf=NULL; unsigned long *jpegsize=NULL, srcsize, totaljpegsize; tjtransform *t=NULL; int w=0, h=0, subsamp=-1, _w, _h, _tilew, _tileh, _ntilesw, _ntilesh, _subsamp; char *temp=NULL, tempstr[80], tempstr2[80]; int row, col, i, tilew, tileh, ntilesw, ntilesh, retval=0; double start, elapsed; int ps=tjPixelSize[pf], tile; if((file=fopen(filename, "rb"))==NULL) _throwunix("opening file"); if(fseek(file, 0, SEEK_END)<0 || (srcsize=ftell(file))<0) _throwunix("determining file size"); if((srcbuf=(unsigned char *)malloc(srcsize))==NULL) _throwunix("allocating memory"); if(fseek(file, 0, SEEK_SET)<0) _throwunix("setting file position"); if(fread(srcbuf, srcsize, 1, file)<1) _throwunix("reading JPEG data"); fclose(file); file=NULL; temp=strrchr(filename, '.'); if(temp!=NULL) *temp='\0'; if((handle=tjInitTransform())==NULL) _throwtj("executing tjInitTransform()"); if(tjDecompressHeader2(handle, srcbuf, srcsize, &w, &h, &subsamp)==-1) _throwtj("executing tjDecompressHeader2()"); if(quiet==1) { printf("All performance values in Mpixels/sec\n\n"); printf("Bitmap\tBitmap\tJPEG\t%s %s \tXform\tComp\tDecomp\n", dotile? "Tile ":"Image", dotile? "Tile ":"Image"); printf("Format\tOrder\tSubsamp\tWidth Height\tPerf \tRatio\tPerf\n\n"); } else if(!quiet) { printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", subNameLong[subsamp], pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "Bottom-up":"Top-down"); } for(tilew=dotile? 16:w, tileh=dotile? 16:h; ; tilew*=2, tileh*=2) { if(tilew>w) tilew=w; if(tileh>h) tileh=h; ntilesw=(w+tilew-1)/tilew; ntilesh=(h+tileh-1)/tileh; if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG tile array"); memset(jpegbuf, 0, sizeof(unsigned char *)*ntilesw*ntilesh); if((jpegsize=(unsigned long *)malloc(sizeof(unsigned long) *ntilesw*ntilesh))==NULL) _throwunix("allocating JPEG size array"); memset(jpegsize, 0, sizeof(unsigned long)*ntilesw*ntilesh); if((flags&TJFLAG_NOREALLOC)!=0) for(i=0; i<ntilesw*ntilesh; i++) { if((jpegbuf[i]=(unsigned char *)malloc(tjBufSize(tilew, tileh, subsamp)))==NULL) _throwunix("allocating JPEG tiles"); } _w=w; _h=h; _tilew=tilew; _tileh=tileh; if(!quiet) { printf("\n%s size: %d x %d", dotile? "Tile":"Image", _tilew, _tileh); if(sf.num!=1 || sf.denom!=1) printf(" --> %d x %d", TJSCALED(_w, sf), TJSCALED(_h, sf)); printf("\n"); } else if(quiet==1) { printf("%s\t%s\t%s\t", pixFormatStr[pf], (flags&TJFLAG_BOTTOMUP)? "BU":"TD", subNameLong[subsamp]); printf("%-4d %-4d\t", tilew, tileh); } _subsamp=subsamp; if(dotile || xformop!=TJXOP_NONE || xformopt!=0) { if((t=(tjtransform *)malloc(sizeof(tjtransform)*ntilesw*ntilesh)) ==NULL) _throwunix("allocating image transform array"); if(xformop==TJXOP_TRANSPOSE || xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90 || xformop==TJXOP_ROT270) { _w=h; _h=w; _tilew=tileh; _tileh=tilew; } if(xformopt&TJXOPT_GRAY) _subsamp=TJ_GRAYSCALE; if(xformop==TJXOP_HFLIP || xformop==TJXOP_ROT180) _w=_w-(_w%tjMCUWidth[_subsamp]); if(xformop==TJXOP_VFLIP || xformop==TJXOP_ROT180) _h=_h-(_h%tjMCUHeight[_subsamp]); if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT90) _w=_w-(_w%tjMCUHeight[_subsamp]); if(xformop==TJXOP_TRANSVERSE || xformop==TJXOP_ROT270) _h=_h-(_h%tjMCUWidth[_subsamp]); _ntilesw=(_w+_tilew-1)/_tilew; _ntilesh=(_h+_tileh-1)/_tileh; for(row=0, tile=0; row<_ntilesh; row++) { for(col=0; col<_ntilesw; col++, tile++) { t[tile].r.w=min(_tilew, _w-col*_tilew); t[tile].r.h=min(_tileh, _h-row*_tileh); t[tile].r.x=col*_tilew; t[tile].r.y=row*_tileh; t[tile].op=xformop; t[tile].options=xformopt|TJXOPT_TRIM; } } start=gettime(); if(tjTransform(handle, srcbuf, srcsize, _ntilesw*_ntilesh, jpegbuf, jpegsize, t, flags)==-1) _throwtj("executing tjTransform()"); elapsed=gettime()-start; free(t); t=NULL; for(tile=0, totaljpegsize=0; tile<_ntilesw*_ntilesh; tile++) totaljpegsize+=jpegsize[tile]; if(quiet) { printf("%s%c%s%c", sigfig((double)(w*h)/1000000./elapsed, 4, tempstr, 80), quiet==2? '\n':'\t', sigfig((double)(w*h*ps)/(double)totaljpegsize, 4, tempstr2, 80), quiet==2? '\n':'\t'); } else if(!quiet) { printf("X--> Frame rate: %f fps\n", 1.0/elapsed); printf(" Output image size: %lu bytes\n", totaljpegsize); printf(" Compression ratio: %f:1\n", (double)(w*h*ps)/(double)totaljpegsize); printf(" Source throughput: %f Megapixels/sec\n", (double)(w*h)/1000000./elapsed); printf(" Output bit stream: %f Megabits/sec\n", (double)totaljpegsize*8./1000000./elapsed); } } else { if(quiet==1) printf("N/A\tN/A\t"); jpegsize[0]=srcsize; memcpy(jpegbuf[0], srcbuf, srcsize); } if(w==tilew) _tilew=_w; if(h==tileh) _tileh=_h; if(decomptest(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0, filename, _tilew, _tileh)==-1) goto bailout; for(i=0; i<ntilesw*ntilesh; i++) { free(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(tilew==w && tileh==h) break; } bailout: if(file) {fclose(file); file=NULL;} if(jpegbuf) { for(i=0; i<ntilesw*ntilesh; i++) { if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL; } free(jpegbuf); jpegbuf=NULL; } if(jpegsize) {free(jpegsize); jpegsize=NULL;} if(srcbuf) {free(srcbuf); srcbuf=NULL;} if(t) {free(t); t=NULL;} if(handle) {tjDestroy(handle); handle=NULL;} return; }