snprintf(tempstr, 1024, "%s_%s%s_full.%s", filename,
_subnames[jpegsub], qualstr, useppm?"ppm":"bmp");
}
- else snprintf(tempstr, 1024, "%s_%s%s_%dx%d.%s", filename,
- _subnames[jpegsub], qualstr, tilesizex, tilesizey, useppm?"ppm":"bmp");
+ else
+ {
+ if(decomponly)
+ snprintf(tempstr, 1024, "%s_%dx%d.%s", filename, tilesizex, tilesizey,
+ useppm?"ppm":"bmp");
+ else snprintf(tempstr, 1024, "%s_%s%s_%dx%d.%s", filename,
+ _subnames[jpegsub], qualstr, tilesizex, tilesizey, useppm?"ppm":"bmp");
+ }
if(savebmp(tempstr, rgbbuf, scaledw, scaledh, pf, pitch, bu)==-1)
_throwbmp("saving bitmap");
ptr=strrchr(tempstr, '.');
FILE *file=NULL; tjhandle hnd=NULL;
unsigned char **jpegbuf=NULL, *srcbuf=NULL;
unsigned long *comptilesize=NULL, srcbufsize, jpgbufsize;
+ tjtransform *t=NULL;
int w=0, h=0, jpegsub=-1;
char *temp=NULL;
int i, j, tilesizex, tilesizey, numtilesx, numtilesy, retval=0;
if(dotile)
{
- tilesizex=tilesizey=512;
+ tilesizex=tilesizey=8;
if(quiet==1)
{
printf("All performance values in Mpixels/sec\n\n");
}
else if(!quiet)
{
- printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
- bu?"Bottom-up":"Top-down");
+ printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", _subnamel[jpegsub],
+ _pfname[pf], bu?"Bottom-up":"Top-down");
}
do
{
tilesizey*=2; if(tilesizey>h) tilesizey=h;
numtilesx=(w+tilesizex-1)/tilesizex;
numtilesy=(h+tilesizey-1)/tilesizey;
+
+ if((jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
+ *numtilesx*numtilesy))==NULL)
+ _throwunix("allocating image buffer array");
if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)
- *numtilesx*numtilesy))==NULL
- || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
*numtilesx*numtilesy))==NULL)
- _throwunix("allocating image buffers");
+ _throwunix("allocating image size array");
+ if((t=(tjtransform *)malloc(sizeof(tjtransform)*numtilesx*numtilesy))
+ ==NULL)
+ _throwunix("allocating image transform array");
memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
for(i=0; i<numtilesx*numtilesy; i++)
else printf("%-4d %-4d\t", tilesizex, tilesizey);
}
- start=rrtime();
- jpgbufsize=0; tilen=0;
- for(i=0; i<h; i+=tilesizey)
+ for(i=0, tilen=0; i<h; i+=tilesizey)
{
- for(j=0; j<w; j+=tilesizex)
- {
- int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
- if(tjTransform(hnd, srcbuf, srcbufsize, jpegbuf[tilen],
- &comptilesize[tilen], j, i, tempw, temph, TJXFORM_NONE,
- TJXFORM_CROP, flags)
- ==-1)
- _throwtj("executing tjTransform()");
- jpgbufsize+=comptilesize[tilen];
- tilen++;
+ for(j=0; j<w; j+=tilesizex, tilen++)
+ {
+ t[tilen].r.x=j;
+ t[tilen].r.y=i;
+ t[tilen].r.w=min(tilesizex, w-j);
+ t[tilen].r.h=min(tilesizey, h-i);
+ t[tilen].op=TJXFORM_NONE;
+ t[tilen].options=TJXFORM_CROP;
}
}
+
+ start=rrtime();
+ if(tjTransform(hnd, srcbuf, srcbufsize, numtilesx*numtilesy, jpegbuf,
+ comptilesize, t, flags)==-1)
+ _throwtj("executing tjTransform()");
elapsed=rrtime()-start;
+ for(tilen=0, jpgbufsize=0; tilen<numtilesx*numtilesy; tilen++)
+ {
+ jpgbufsize+=comptilesize[tilen];
+ }
+
if(quiet)
{
printsigfig((double)(w*h)/1000000./elapsed, 4);
if(yuv==YUVDECODE)
printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
else
- printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
- bu?"Bottom-up":"Top-down");
+ printf(">>>>> JPEG %s --> %s (%s) <<<<<\n", _subnamel[jpegsub],
+ _pfname[pf], bu?"Bottom-up":"Top-down");
printf("\nImage size: %d x %d", w, h);
if(scale_num!=1 || scale_denom!=1)
printf(" --> %d x %d", (w*scale_num+scale_denom-1)/scale_denom,
#define TJ_411 TJ_420 /* for backward compatibility with VirtualGL <= 2.1.x,
TurboVNC <= 0.6, and TurboJPEG/IPP */
+static const int tjmcuw[NUMSUBOPT]={8, 16, 16, 8};
+static const int tjmcuh[NUMSUBOPT]={8, 8, 16, 8};
+
/* Flags */
#define TJ_BGR 1
/* The components of each pixel in the uncompressed source/destination image
/*
- int tjTransform(tjhandle j,
+ int tjTransform(tjhandle hnd,
unsigned char *srcbuf, unsigned long srcsize,
- unsigned char *dstbuf, unsigned long *dstsize,
- int x, int y, int w, int h, int op, int options, int flags)
+ int n, unsigned char **dstbufs, unsigned long *dstsizes,
+ tjtransform *transforms, int flags);
+
+ This function can losslessly transform a JPEG image into another JPEG image.
+ Lossless transforms work by moving the raw coefficients from one JPEG image
+ structure to another without altering the values of the coefficients. While
+ this is typically faster than decompressing the image, transforming it, and
+ re-compressing it, lossless transforms are not free. Each lossless transform
+ requires reading and Huffman decoding all of the coefficients in the source
+ image, regardless of the size of the destination image. Thus, this function
+ provides a means of generating multiple transformed images from the same
+ source or of applying multiple transformations simultaneously, in order to
+ eliminate the need to read the source coefficients multiple times.
- [INPUT] j = instance handle previously returned from a call to
+ [INPUT] hnd = instance handle previously returned from a call to
tjInitTransform()
[INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
to transform
[INPUT] srcsize = size of the source JPEG image buffer (in bytes)
- [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
- the transformed JPEG image. Use the TJBUFSIZE(width, height) function to
- determine the appropriate size for this buffer based on the cropped width
- and height.
- [OUTPUT] dstsize = pointer to unsigned long which receives the size (in
- bytes) of the transformed image
- [INPUT] x, y, w, h = the left edge, top edge, width, and height of the
- cropping region. If (x, y) does not fall on an MCU boundary, then x and
- y will be silently moved left and/or up to the nearest MCU boundary. You
- can call tjGetCroppedSize() to determine how (or if) x, y, w, and h will
- be modified ahead of time, so you can allocate the output buffer
- appropriately.
- [INPUT] op = one of the transform operations described in the "Transform
- operations" section above.
- [INPUT] options = the bitwise OR of one or more of the transform options
- described in the "Transform options" section above.
+ [INPUT] n = the number of transformed JPEG images to generate
+ [INPUT] dstbufs = pointer to an array of n user-allocated image buffers.
+ dstbufs[i] will receive a JPEG image that has been transformed using the
+ parameters in transforms[i]. Use the TJBUFSIZE(width, height) function to
+ determine the maximum size for each buffer based on the cropped width and
+ height.
+ [OUTPUT] dstsizes = pointer to an array of n unsigned longs which will
+ receive the actual sizes (in bytes) of each transformed JPEG image
+ [INPUT] transforms = pointer to an array of n tjtransform structures, each of
+ which specifies the transform parameters and/or cropping region for the
+ corresponding transformed output image. The structure members are as
+ follows:
+
+ r.x = the left boundary of the cropping region. This must be evenly
+ divisible by tjmcuw[subsamp] (the MCU block width corresponding to the
+ level of chrominance subsampling used in the source image)
+ r.y = the upper boundary of the cropping region. This must be evenly
+ divisible by tjmcuh[subsamp] (the MCU block height corresponding to the
+ level of chrominance subsampling used in the source image)
+ r.w = the width of the cropping region. Setting this to 0 is the
+ equivalent of setting it to the width of the source JPEG image.
+ r.h = the height of the cropping region. Setting this to 0 is the
+ equivalent of setting it to the height of the source JPEG image.
+ op = one of the transform operations described in the
+ "Transform operations" section above
+ options = the bitwise OR of one or more of the transform options described
+ in the "Transform options" section above.
+
[INPUT] flags = the bitwise OR of one or more of the flags described in the
"Flags" section above.
RETURNS: 0 on success, -1 on error
*/
-DLLEXPORT int DLLCALL tjTransform(tjhandle j,
- unsigned char *srcbuf, unsigned long size,
- unsigned char *dstbuf, unsigned long *dstsize,
- int x, int y, int w, int h, int op, int options, int flags);
+DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
+ unsigned char *srcbuf, unsigned long srcsize,
+ int n, unsigned char **dstbufs, unsigned long *dstsizes,
+ tjtransform *transforms, int flags);
/*
int initc, initd;
} jpgstruct;
-static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
-static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1};
static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
#define _throw(c) {snprintf(lasterror, JMSG_LENGTH_MAX, "%s", c); \
retval=-1; goto bailout;}
-#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
+#define checkhandle(hnd) jpgstruct *j=(jpgstruct *)hnd; \
if(!j) {snprintf(lasterror, JMSG_LENGTH_MAX, "Invalid handle"); return -1;}
int pw, ph, cw, ch;
if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT)
_throw("Invalid argument in TJBUFSIZEYUV()");
- pw=PAD(width, hsampfactor[subsamp]);
- ph=PAD(height, vsampfactor[subsamp]);
- cw=pw/hsampfactor[subsamp]; ch=ph/vsampfactor[subsamp];
+ pw=PAD(width, tjmcuw[subsamp]/8);
+ ph=PAD(height, tjmcuh[subsamp]/8);
+ cw=pw*8/tjmcuw[subsamp]; ch=ph*8/tjmcuh[subsamp];
retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
bailout:
}
-DLLEXPORT int DLLCALL tjCompress(tjhandle h,
+DLLEXPORT int DLLCALL tjCompress(tjhandle hnd,
unsigned char *srcbuf, int width, int pitch, int height, int ps,
unsigned char *dstbuf, unsigned long *size,
int jpegsub, int qual, int flags)
JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS];
JSAMPROW *outbuf[MAX_COMPONENTS];
- checkhandle(h);
+ checkhandle(hnd);
for(i=0; i<MAX_COMPONENTS; i++)
{
if(qual>=96) j->cinfo.dct_method=JDCT_ISLOW;
else j->cinfo.dct_method=JDCT_FASTEST;
- j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
+ j->cinfo.comp_info[0].h_samp_factor=tjmcuw[jpegsub]/8;
j->cinfo.comp_info[1].h_samp_factor=1;
j->cinfo.comp_info[2].h_samp_factor=1;
- j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
+ j->cinfo.comp_info[0].v_samp_factor=tjmcuh[jpegsub]/8;
j->cinfo.comp_info[1].v_samp_factor=1;
j->cinfo.comp_info[2].v_samp_factor=1;
}
-DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle hnd,
unsigned char *srcbuf, int width, int pitch, int height, int ps,
unsigned char *dstbuf, int subsamp, int flags)
{
unsigned long size;
- return tjCompress(h, srcbuf, width, pitch, height, ps, dstbuf, &size,
+ return tjCompress(hnd, srcbuf, width, pitch, height, ps, dstbuf, &size,
subsamp, 0, flags|TJ_YUV);
}
}
-DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle hnd,
unsigned char *srcbuf, unsigned long size,
int *width, int *height, int *jpegsub)
{
int i, k, retval=0;
- checkhandle(h);
+ checkhandle(hnd);
if(srcbuf==NULL || size<=0 || width==NULL || height==NULL || jpegsub==NULL)
_throw("Invalid argument in tjDecompressHeader2()");
{
if(j->dinfo.num_components==pixelsize[i])
{
- if(j->dinfo.comp_info[0].h_samp_factor==hsampfactor[i]
- && j->dinfo.comp_info[0].v_samp_factor==vsampfactor[i])
+ if(j->dinfo.comp_info[0].h_samp_factor==tjmcuw[i]/8
+ && j->dinfo.comp_info[0].v_samp_factor==tjmcuh[i]/8)
{
int match=0;
for(k=1; k<j->dinfo.num_components; k++)
}
-DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle hnd,
unsigned char *srcbuf, unsigned long size,
int *width, int *height)
{
int jpegsub;
- return tjDecompressHeader2(h, srcbuf, size, width, height, &jpegsub);
+ return tjDecompressHeader2(hnd, srcbuf, size, width, height, &jpegsub);
}
}
-DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
+DLLEXPORT int DLLCALL tjDecompress(tjhandle hnd,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int width, int pitch, int height, int ps,
int flags)
JSAMPLE *_tmpbuf=NULL; JSAMPROW *tmpbuf[MAX_COMPONENTS];
int jpegwidth, jpegheight, scaledw, scaledh;
- checkhandle(h);
+ checkhandle(hnd);
for(i=0; i<MAX_COMPONENTS; i++)
{
}
-DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle hnd,
unsigned char *srcbuf, unsigned long size,
unsigned char *dstbuf, int flags)
{
- return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
+ return tjDecompress(hnd, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
}
DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
unsigned char *srcbuf, unsigned long srcsize,
- unsigned char *dstbuf, unsigned long *dstsize,
- int x, int y, int w, int h, int op, int options, int flags)
+ int n, unsigned char **dstbufs, unsigned long *dstsizes,
+ tjtransform *t, int flags)
{
- jpeg_transform_info xinfo;
+ jpeg_transform_info *xinfo=NULL;
jvirt_barray_ptr *srccoefs, *dstcoefs;
- int retval=0;
+ int retval=0, i;
checkhandle(hnd);
- if(srcbuf==NULL || srcsize<=0 || dstbuf==NULL || dstsize==NULL
- || x<0 || y<0 || w<0 || h<0 || op<0 || op>=NUMXFORMOPT
- || flags<0)
+ if(srcbuf==NULL || srcsize<=0 || n<1 || dstbufs==NULL || dstsizes==NULL
+ || t==NULL || flags<0)
_throw("Invalid argument in tjTransform()");
if(!j->initc || !j->initd)
_throw("Instance has not been initialized for transformation");
j->jsms.bytes_in_buffer=srcsize;
j->jsms.next_input_byte=srcbuf;
- xinfo.transform=xformtypes[op];
- xinfo.perfect=(options&TJXFORM_PERFECT)? 1:0;
- xinfo.trim=(options&TJXFORM_TRIM)? 1:0;
- xinfo.force_grayscale=(options&TJXFORM_GRAY)? 1:0;
- xinfo.crop=(options&TJXFORM_CROP)? 1:0;
+ if((xinfo=(jpeg_transform_info *)malloc(sizeof(jpeg_transform_info)*n))
+ ==NULL)
+ _throw("Memory allocation failed in tjTransform()");
- if(xinfo.crop)
+ for(i=0; i<n; i++)
{
- xinfo.crop_xoffset=x; xinfo.crop_xoffset_set=JCROP_POS;
- xinfo.crop_yoffset=y; xinfo.crop_yoffset_set=JCROP_POS;
- if(w!=0)
- {
- xinfo.crop_width=w; xinfo.crop_width_set=JCROP_POS;
- }
- if(h!=0)
+ xinfo[i].transform=xformtypes[t[i].op];
+ xinfo[i].perfect=(t[i].options&TJXFORM_PERFECT)? 1:0;
+ xinfo[i].trim=(t[i].options&TJXFORM_TRIM)? 1:0;
+ xinfo[i].force_grayscale=(t[i].options&TJXFORM_GRAY)? 1:0;
+ xinfo[i].crop=(t[i].options&TJXFORM_CROP)? 1:0;
+
+ if(xinfo[i].crop)
{
- xinfo.crop_height=h; xinfo.crop_height_set=JCROP_POS;
+ xinfo[i].crop_xoffset=t[i].r.x; xinfo[i].crop_xoffset_set=JCROP_POS;
+ xinfo[i].crop_yoffset=t[i].r.y; xinfo[i].crop_yoffset_set=JCROP_POS;
+ if(t[i].r.w!=0)
+ {
+ xinfo[i].crop_width=t[i].r.w; xinfo[i].crop_width_set=JCROP_POS;
+ }
+ if(t[i].r.h!=0)
+ {
+ xinfo[i].crop_height=t[i].r.h; xinfo[i].crop_height_set=JCROP_POS;
+ }
}
}
- jcopy_markers_setup(&j->dinfo, JCOPYOPT_NONE);
+ jcopy_markers_setup(&j->dinfo, JCOPYOPT_ALL);
jpeg_read_header(&j->dinfo, TRUE);
- if(!jtransform_request_workspace(&j->dinfo, &xinfo))
- _throw("Transform is not perfect");
-
- if(!xinfo.crop)
- {
- w=j->dinfo.image_width; h=j->dinfo.image_height;
- }
- else
+ for(i=0; i<n; i++)
{
- w=xinfo.crop_width; h=xinfo.crop_height;
+ if(!jtransform_request_workspace(&j->dinfo, &xinfo[i]))
+ _throw("Transform is not perfect");
+
+ if(xinfo[i].crop)
+ {
+ if((t[i].r.x%xinfo[i].iMCU_sample_width)!=0
+ || (t[i].r.y%xinfo[i].iMCU_sample_height)!=0)
+ {
+ snprintf(lasterror, JMSG_LENGTH_MAX,
+ "To crop this JPEG image, x must be a multiple of %d\n"
+ "and y must be a multiple of %d.\n",
+ xinfo[i].iMCU_sample_width, xinfo[i].iMCU_sample_height);
+ retval=-1; goto bailout;
+ }
+ }
}
- j->jdms.next_output_byte=dstbuf;
- j->jdms.free_in_buffer=TJBUFSIZE(w, h);
+ srccoefs=jpeg_read_coefficients(&j->dinfo);
- if(xinfo.crop)
+ for(i=0; i<n; i++)
{
- if((x%xinfo.iMCU_sample_width)!=0 || (y%xinfo.iMCU_sample_height)!=0)
+ int w, h;
+ j->jdms.next_output_byte=dstbufs[i];
+ if(!xinfo[i].crop)
{
- snprintf(lasterror, JMSG_LENGTH_MAX,
- "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n"
- "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height);
- retval=-1; goto bailout;
+ w=j->dinfo.image_width; h=j->dinfo.image_height;
}
+ else
+ {
+ w=xinfo[i].crop_width; h=xinfo[i].crop_height;
+ }
+ j->jdms.free_in_buffer=TJBUFSIZE(w, h);
+ jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
+ dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
+ &xinfo[i]);
+ jpeg_write_coefficients(&j->cinfo, dstcoefs);
+ jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
+ jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs,
+ &xinfo[i]);
+ jpeg_finish_compress(&j->cinfo);
+
+ dstsizes[i]=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
}
- srccoefs=jpeg_read_coefficients(&j->dinfo);
- jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
- dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
- &xinfo);
- jpeg_write_coefficients(&j->cinfo, dstcoefs);
- jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
- jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo);
-
- jpeg_finish_compress(&j->cinfo);
jpeg_finish_decompress(&j->dinfo);
- *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
-
bailout:
if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
+ if(xinfo) free(xinfo);
return retval;
}
return lasterror;
}
-DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
+DLLEXPORT int DLLCALL tjDestroy(tjhandle hnd)
{
- checkhandle(h);
+ checkhandle(hnd);
if(setjmp(j->jerr.jb)) return -1;
if(j->initc) jpeg_destroy_compress(&j->cinfo);
if(j->initd) jpeg_destroy_decompress(&j->dinfo);