Ejemplo n.º 1
0
bool WriteJpeg( const char * destinationFile, const unsigned char * rgbxBuffer, int width, int height )
{
	tjhandle tj = tjInitCompress();

	unsigned char * jpegBuf = NULL;
	unsigned long jpegSize = 0;

	const int r = tjCompress2( tj, ( unsigned char * )rgbxBuffer,	// TJ isn't const correct...
		width, width * 4, height, TJPF_RGBX, &jpegBuf,
		&jpegSize, TJSAMP_444 /* TJSAMP_422 */, 90 /* jpegQual */, 0 /* flags */ );
	if ( r != 0 )
	{
		LOG_TJ( "tjCompress2 returned %s for %s", tjGetErrorStr(), destinationFile );
		return false;
	}

	FILE * f = fopen( destinationFile, "wb" );
	if ( f != NULL )
	{
		fwrite( jpegBuf, jpegSize, 1, f );
		fclose( f );
	}
	else
	{
		LOG_TJ( "WriteJpeg failed to write to %s", destinationFile );
		return false;
	}

	tjFree( jpegBuf );

	tjDestroy( tj );

	return true;
}
Ejemplo n.º 2
0
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
	(JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
		jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
		jint jpegQual, jint flags)
{
	tjhandle handle=0;
	unsigned long jpegSize=0;
	jsize arraySize=0, actualStride;
	unsigned char *srcBuf=NULL, *jpegBuf=NULL;

	gethandle();

	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
		|| stride<0)
		_throw("Invalid argument in compress()");
	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
		_throw("Mismatch between Java and C API");
	if(tjPixelSize[pf]!=sizeof(jint))
		_throw("Pixel format must be 32-bit when compressing from an integer buffer.");

	actualStride=(stride==0)? width:stride;
	arraySize=(y+height-1)*actualStride + x+width;
	if((*env)->GetArrayLength(env, src)<arraySize)
		_throw("Source buffer is not large enough");
	jpegSize=tjBufSize(width, height, jpegSubsamp);
	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
		_throw("Destination buffer is not large enough");

	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));

	if(tjCompress2(handle, &srcBuf[(y*actualStride + x)*sizeof(int)], width,
		stride*sizeof(jint), height, pf, &jpegBuf, &jpegSize, jpegSubsamp,
		jpegQual, flags|TJFLAG_NOREALLOC)==-1)
	{
		(*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
		jpegBuf=srcBuf=NULL;
		_throw(tjGetErrorStr());
	}

	bailout:
	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
	return (jint)jpegSize;
}
Ejemplo n.º 3
0
	static Shared<Buffer> save_to_buffer(const LayoutT & layout, const Byte * input, int format, std::uint32_t quality)
	{
		std::size_t output_size = 0;
		Byte * output_data = NULL; //!< Memory is allocated by tjCompress2 if _jpegSize == 0

		tjhandle compressor = tjInitCompress();

		tjCompress2(compressor, input, static_cast<int>(layout.size[WIDTH]), static_cast<int>(layout.stride[0]), static_cast<int>(layout.size[HEIGHT]), TJPF_RGBX, &output_data, &output_size, TJSAMP_444, quality, TJFLAG_FASTDCT);

		tjDestroy(compressor);

		if (output_data) {
			return shared<ForeignBuffer<Byte, tjFree>>(output_data, output_size);
		} else {
			return nullptr;
		}
	}
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
	(JNIEnv *env, jobject obj, jbyteArray src, 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;
	unsigned char *srcBuf=NULL, *jpegBuf=NULL;

	gethandle();

	if(pf<0 || pf>=org_libjpegturbo_turbojpeg_TJ_NUMPF || width<1 || height<1
		|| pitch<0)
		_throw("Invalid argument in compress()");
	if(org_libjpegturbo_turbojpeg_TJ_NUMPF!=TJ_NUMPF)
		_throw("Mismatch between Java and C API");

	arraySize=(pitch==0)? width*tjPixelSize[pf]*height:pitch*height;
	if((*env)->GetArrayLength(env, src)<arraySize)
		_throw("Source buffer is not large enough");
	jpegSize=tjBufSize(width, height, jpegSubsamp);
	if((*env)->GetArrayLength(env, dst)<(jsize)jpegSize)
		_throw("Destination buffer is not large enough");

	bailif0(srcBuf=(*env)->GetPrimitiveArrayCritical(env, src, 0));
	bailif0(jpegBuf=(*env)->GetPrimitiveArrayCritical(env, dst, 0));

	if(tjCompress2(handle, srcBuf, width, pitch, height, pf, &jpegBuf,
		&jpegSize, jpegSubsamp, jpegQual, flags|TJFLAG_NOREALLOC)==-1)
	{
		(*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
		(*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
		jpegBuf=srcBuf=NULL;
		_throw(tjGetErrorStr());
	}

	bailout:
	if(jpegBuf) (*env)->ReleasePrimitiveArrayCritical(env, dst, jpegBuf, 0);
	if(srcBuf) (*env)->ReleasePrimitiveArrayCritical(env, src, srcBuf, 0);
	return (jint)jpegSize;
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
void WriteJpeg( const char * fullName, const unsigned char * rgbxBuffer, int width, int height )
{
	tjhandle tj = tjInitCompress();

	unsigned char * jpegBuf = NULL;
	unsigned long jpegSize = 0;

	const int r = tjCompress2( tj, ( unsigned char * )rgbxBuffer,	// TJ isn't const correct...
		width, width * 4, height, TJPF_RGBX, &jpegBuf,
		&jpegSize, TJSAMP_444 /* TJSAMP_422 */, 90 /* jpegQual */, 0 /* flags */ );
	if ( r != 0 )
	{
		LOG( "tjCompress2 returned %s for %s", tjGetErrorStr(), fullName );
		return;
	}
	MemBuffer toFile( jpegBuf, jpegSize );
	toFile.WriteToFile( fullName );
	tjFree( jpegBuf );

	tjDestroy( tj );
}
Ejemplo n.º 7
0
QByteArray ImageJpegCompressor::computeJpeg(const ImageWrapper& sourceImage,
                                            const QRect& imageRegion)
{
    // tjCompress API is incorrect and takes a non-const input buffer, even
    // though it does not modify it. It can "safely" be cast to non-const
    // pointer to comply to the incorrect API.
    unsigned char* tjSrcBuffer = (unsigned char*)sourceImage.data;
    tjSrcBuffer +=
        imageRegion.y() * sourceImage.width * sourceImage.getBytesPerPixel();
    tjSrcBuffer += imageRegion.x() * sourceImage.getBytesPerPixel();

    const int tjWidth = imageRegion.width();
    // assume imageBuffer isn't padded
    const int tjPitch = sourceImage.width * sourceImage.getBytesPerPixel();
    const int tjHeight = imageRegion.height();
    const int tjPixelFormat = getTurboJpegFormat(sourceImage.pixelFormat);
    unsigned char* tjJpegBuf = 0;
    unsigned long tjJpegSize = 0;
    const int tjJpegSubsamp = TJSAMP_444;
    const int tjJpegQual = sourceImage.compressionQuality;
    const int tjFlags = 0; // or: TJFLAG_BOTTOMUP

    int err = tjCompress2(_tjHandle, tjSrcBuffer, tjWidth, tjPitch, tjHeight,
                          tjPixelFormat, &tjJpegBuf, &tjJpegSize, tjJpegSubsamp,
                          tjJpegQual, tjFlags);
    if (err != 0)
    {
        std::cerr << "libjpeg-turbo image conversion failure" << std::endl;
        return QByteArray();
    }

    // move the JPEG buffer to a byte array
    const QByteArray jpegData((char*)tjJpegBuf, tjJpegSize);

    // free the libjpeg-turbo allocated memory
    tjFree(tjJpegBuf);

    return jpegData;
}
Ejemplo n.º 8
0
void BEJPEG::compress ( void )
{
    tjhandle jpeg_compressor = tjInitCompress();
    if ( NULL != jpeg_compressor ) {

        unsigned long image_size = width * height * tjPixelSize[pixel_format];
        std::vector<unsigned char> image ( image_size );
        unsigned char * compressed_image = &image[0];

        int error = tjCompress2 ( jpeg_compressor, &data[0], width, 0, height, pixel_format, &compressed_image, &image_size, chrominance_subsampling, compression_level, 0 );
        tjDestroy ( jpeg_compressor ); // error =

        if ( 0 == error ) {
            image.resize ( image_size );
            data = image;
        } else {
            throw BEPlugin_Exception ( kJPEGCompressionError, tjGetErrorStr() );
        }

    } else {
        throw BEPlugin_Exception ( kJPEGInitCcompressorError, tjGetErrorStr() );
    }

}
Ejemplo n.º 9
0
{
#ifdef LIVRE_USE_LIBJPEGTURBO
    uint8_t* tjSrcBuffer = const_cast< uint8_t* >(rawData);
    const int32_t pixelFormat = TJPF_BGRA;
    const int32_t color_components = 4; // Color Depth
    const int32_t tjPitch = width * color_components;
    const int32_t tjPixelFormat = pixelFormat;

    uint8_t* tjJpegBuf = 0;
    const int32_t tjJpegSubsamp = TJSAMP_444;
    const int32_t tjJpegQual = 100; // Image Quality
    const int32_t tjFlags = TJXOP_ROT180;

    const int32_t success =
        tjCompress2( _compressor, tjSrcBuffer, width, tjPitch, height,
                     tjPixelFormat, &tjJpegBuf, &dataSize, tjJpegSubsamp,
                     tjJpegQual, tjFlags);

    if(success != 0)
    {
        LBERROR << "libjpeg-turbo image conversion failure" << std::endl;
        return 0;
    }
    return static_cast<uint8_t *>(tjJpegBuf);
#else
    if( !_compressor ) // just to silence unused private field warning
        return nullptr;
    return nullptr;
#endif
}
Ejemplo n.º 10
0
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;
}
Ejemplo n.º 11
0
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;
}