예제 #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;
}
예제 #2
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 );
}
예제 #3
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;
}
예제 #4
0
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;
}
예제 #5
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;
}
예제 #6
0
int main(int argc, char *argv[])
{
  unsigned char *srcBuf = NULL;
  int w = 0, h = 0, i, j, minQual = -1, maxQual = -1;
  char *temp;
  int minArg = 2, retval = 0, subsamp = -1;

  if ((scalingFactors = tjGetScalingFactors(&nsf)) == NULL || nsf == 0)
    _throw("executing tjGetScalingFactors()", tjGetErrorStr());

  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;
      } else if (!strcasecmp(argv[i], "-fastupsample")) {
        printf("Using fast upsampling code\n\n");
        flags |= TJFLAG_FASTUPSAMPLE;
      } else if (!strcasecmp(argv[i], "-fastdct")) {
        printf("Using fastest DCT/IDCT algorithm\n\n");
        flags |= TJFLAG_FASTDCT;
      } else if (!strcasecmp(argv[i], "-accuratedct")) {
        printf("Using most accurate DCT/IDCT algorithm\n\n");
        flags |= TJFLAG_ACCURATEDCT;
      } else if (!strcasecmp(argv[i], "-progressive")) {
        printf("Using progressive entropy coding\n\n");
        flags |= TJFLAG_PROGRESSIVE;
      } else if (!strcasecmp(argv[i], "-rgb"))
        pf = TJPF_RGB;
      else if (!strcasecmp(argv[i], "-rgbx"))
        pf = TJPF_RGBX;
      else if (!strcasecmp(argv[i], "-bgr"))
        pf = TJPF_BGR;
      else if (!strcasecmp(argv[i], "-bgrx"))
        pf = TJPF_BGRX;
      else if (!strcasecmp(argv[i], "-xbgr"))
        pf = TJPF_XBGR;
      else if (!strcasecmp(argv[i], "-xrgb"))
        pf = TJPF_XRGB;
      else if (!strcasecmp(argv[i], "-cmyk"))
        pf = TJPF_CMYK;
      else if (!strcasecmp(argv[i], "-bottomup"))
        flags |= TJFLAG_BOTTOMUP;
      else if (!strcasecmp(argv[i], "-quiet"))
        quiet = 1;
      else if (!strcasecmp(argv[i], "-qq"))
        quiet = 2;
      else 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]);
      } else if (!strcasecmp(argv[i], "-hflip"))
        xformOp = TJXOP_HFLIP;
      else if (!strcasecmp(argv[i], "-vflip"))
        xformOp = TJXOP_VFLIP;
      else if (!strcasecmp(argv[i], "-transpose"))
        xformOp = TJXOP_TRANSPOSE;
      else if (!strcasecmp(argv[i], "-transverse"))
        xformOp = TJXOP_TRANSVERSE;
      else if (!strcasecmp(argv[i], "-rot90"))
        xformOp = TJXOP_ROT90;
      else if (!strcasecmp(argv[i], "-rot180"))
        xformOp = TJXOP_ROT180;
      else if (!strcasecmp(argv[i], "-rot270"))
        xformOp = TJXOP_ROT270;
      else if (!strcasecmp(argv[i], "-grayscale"))
        xformOpt |= TJXOPT_GRAY;
      else if (!strcasecmp(argv[i], "-custom"))
        customFilter = dummyDCTFilter;
      else if (!strcasecmp(argv[i], "-nooutput"))
        xformOpt |= TJXOPT_NOOUTPUT;
      else if (!strcasecmp(argv[i], "-copynone"))
        xformOpt |= TJXOPT_COPYNONE;
      else if (!strcasecmp(argv[i], "-benchtime") && i < argc - 1) {
        double temp = atof(argv[++i]);

        if (temp > 0.0) benchTime = temp;
        else usage(argv[0]);
      } else if (!strcasecmp(argv[i], "-warmup") && i < argc - 1) {
        double temp = atof(argv[++i]);

        if (temp >= 0.0) warmup = temp;
        else usage(argv[0]);
        printf("Warmup time = %.1f seconds\n\n", warmup);
      } else if (!strcasecmp(argv[i], "-alloc"))
        flags &= (~TJFLAG_NOREALLOC);
      else if (!strcasecmp(argv[i], "-bmp"))
        ext = "bmp";
      else if (!strcasecmp(argv[i], "-yuv")) {
        printf("Testing YUV planar encoding/decoding\n\n");
        doYUV = 1;
      } else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
        int temp = atoi(argv[++i]);

        if (temp >= 1) yuvPad = temp;
      } else 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;
          }
        }
      } else if (!strcasecmp(argv[i], "-componly"))
        compOnly = 1;
      else if (!strcasecmp(argv[i], "-nowrite"))
        doWrite = 0;
      else if (!strcasecmp(argv[i], "-stoponwarning"))
        flags |= TJFLAG_STOPONWARNING;
      else usage(argv[0]);
    }
  }

  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 ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
      _throwtjg("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) tjFree(srcBuf);
  return retval;
}