#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
-int checkbufyuv(unsigned char *buf, unsigned long size, int w, int h,
- int subsamp)
+int checkbufyuv(unsigned char *buf, int w, int h, int subsamp)
{
int i, j;
int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
int cw=pw/hsf, ch=ph/vsf;
int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
int retval=1;
- unsigned long correctsize=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
-
- if(size!=correctsize)
- {
- printf("\nIncorrect size %lu. Should be %lu\n", size, correctsize);
- retval=0; goto bailout;
- }
for(i=0; i<16; i++)
{
char tempstr[1024]; unsigned char *bmpbuf=NULL;
const char *pixformat; double t;
- if(yuv==YUVENCODE) flags|=TJ_YUV;
-
if(flags&TJ_BGR)
{
if(ps==3) pixformat="BGR";
printf("ERROR: Could not allocate buffer\n"); bailout();
}
initbuf(bmpbuf, w, h, ps, flags);
- memset(jpegbuf, 0, TJBUFSIZE(w, h));
+ memset(jpegbuf, 0,
+ yuv==YUVENCODE? TJBUFSIZEYUV(w, h, subsamp):TJBUFSIZE(w, h));
t=rrtime();
- _catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
+ if(yuv==YUVENCODE)
+ {
+ _catch(tjEncodeYUV(hnd, bmpbuf, w, 0, h, ps, jpegbuf, subsamp, flags));
+ *size=TJBUFSIZEYUV(w, h, subsamp);
+ }
+ else
+ {
+ _catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual,
+ flags));
+ }
t=rrtime()-t;
if(yuv==YUVENCODE)
writejpeg(jpegbuf, *size, tempstr);
if(yuv==YUVENCODE)
{
- if(checkbufyuv(jpegbuf, *size, w, h, subsamp)) printf("Passed.");
+ if(checkbufyuv(jpegbuf, w, h, subsamp)) printf("Passed.");
else {printf("FAILED!"); exitstatus=-1;}
}
else printf("Done.");
unsigned char *bmpbuf=NULL;
const char *pixformat; int _w=0, _h=0; double t;
unsigned long size=0;
- int hsf=_hsf[subsamp], vsf=_vsf[subsamp];
- int pw=PAD(w, hsf), ph=PAD(h, vsf);
- int cw=pw/hsf, ch=ph/vsf;
- int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
- if(yuv==YUVDECODE) flags|=TJ_YUV;
- else if(yuv==YUVENCODE) return;
+ if(yuv==YUVENCODE) return;
if(flags&TJ_BGR)
{
printf("Incorrect JPEG header\n"); bailout();
}
- if(yuv==YUVDECODE)
- size=ypitch*ph + (subsamp==TJ_GRAYSCALE? 0:uvpitch*ch*2);
- else
- size=w*h*ps;
- if((bmpbuf=(unsigned char *)malloc(size+1))==NULL)
+ if(yuv==YUVDECODE) size=TJBUFSIZEYUV(w, h, subsamp);
+ else size=w*h*ps+1;
+ if((bmpbuf=(unsigned char *)malloc(size))==NULL)
{
printf("ERROR: Could not allocate buffer\n"); bailout();
}
- memset(bmpbuf, 0, size+1);
+ memset(bmpbuf, 0, size);
t=rrtime();
- _catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
+ if(yuv==YUVDECODE)
+ {
+ _catch(tjDecompressToYUV(hnd, jpegbuf, jpegsize, bmpbuf, flags));
+ }
+ else
+ {
+ _catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps,
+ flags));
+ }
t=rrtime()-t;
if(yuv==YUVDECODE)
{
- if(checkbufyuv(bmpbuf, size, pw, ph, subsamp))
- printf("Passed.");
+ if(checkbufyuv(bmpbuf, w, h, subsamp)) printf("Passed.");
else {printf("FAILED!"); exitstatus=-1;}
}
else
tjhandle hnd=NULL, dhnd=NULL; unsigned char *jpegbuf=NULL;
unsigned long size;
- if((jpegbuf=(unsigned char *)malloc(TJBUFSIZE(w, h))) == NULL)
+ size=(yuv==YUVENCODE? TJBUFSIZEYUV(w, h, subsamp):TJBUFSIZE(w, h));
+ if((jpegbuf=(unsigned char *)malloc(size)) == NULL)
{
puts("ERROR: Could not allocate buffer."); bailout();
}
const char *_pfname[]={"RGB", "RGBX", "BGR", "BGRX", "XBGR", "XRGB"};
const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:2:0", "GRAY"};
const char *_subnames[NUMSUBOPT]={"444", "422", "420", "GRAY"};
-const int _hsf[NUMSUBOPT]={1, 2, 2, 1};
-const int _vsf[NUMSUBOPT]={1, 1, 2, 1};
void printsigfig(double val, int figs)
{
|(fastupsample?TJ_FASTUPSAMPLE:0);
int ps=_ps[pf], tilen;
int pitch=w*ps, yuvsize;
- int hsf=_hsf[jpegsub], vsf=_vsf[jpegsub];
- int pw=PAD(w, hsf), ph=PAD(h, vsf);
- int cw=pw/hsf, ch=ph/vsf;
- int ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
flags |= _flags[pf];
if(bu) flags |= TJ_BOTTOMUP;
if(yuv==YUVENCODE) flags |= TJ_YUV;
- yuvsize=ypitch*ph + (jpegsub==TJ_GRAYSCALE? 0:uvpitch*ch*2);
+ yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h))) == NULL)
_throwunix("allocating image buffer");
for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
if((hnd=tjInitCompress())==NULL)
_throwtj("executing tjInitCompress()");
- if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
+ if(yuv==YUVENCODE)
+ {
+ if(tjEncodeYUV(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
+ jpegbuf[0], jpegsub, flags)==-1)
+ _throwtj("executing tjEncodeYUV()");
+ comptilesize[0]=TJBUFSIZEYUV(tilesizex, tilesizey, jpegsub);
+ }
+ else if(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
jpegbuf[0], &comptilesize[0], jpegsub, qual, flags)==-1)
_throwtj("executing tjCompress()");
ITER=0;
for(j=0; j<w; j+=tilesizex)
{
int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
- if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
+ if(yuv==YUVENCODE)
+ {
+ if(tjEncodeYUV(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
+ temph, ps, jpegbuf[tilen], jpegsub, flags)==-1)
+ _throwtj("executing tjEncodeYUV()");
+ comptilesize[tilen]=TJBUFSIZEYUV(tempw, temph, jpegsub);
+ }
+ else if(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
flags)==-1)
_throwtj("executing tjCompress()");
}
// Decompression test
- if(yuv==YUVDECODE) flags |= TJ_YUV;
memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
if((hnd=tjInitDecompress())==NULL)
_throwtj("executing tjInitDecompress()");
- if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
+ if(yuv==YUVDECODE)
+ {
+ if(tjDecompressToYUV(hnd, jpegbuf[0], jpgbufsize, rgbbuf, flags)==-1)
+ _throwtj("executing tjDecompressToYUV()");
+ }
+ else if(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
tilesizey, ps, flags)==-1)
_throwtj("executing tjDecompress()");
ITER=0;
for(j=0; j<w; j+=tilesizex)
{
int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
- if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
+ if(yuv==YUVDECODE)
+ {
+ if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
+ &rgbbuf[pitch*i+ps*j], flags)==-1)
+ _throwtj("executing tjDecompressToYUV()");
+ }
+ else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
&rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
_throwtj("executing tjDecompress()");
tilen++;
|(fastupsample?TJ_FASTUPSAMPLE:0);
int ps=_ps[pf], pitch, jpegsub=-1;
char *temp=NULL;
- int hsf, vsf, pw, ph, cw, ch, ypitch, uvpitch, yuvsize;
+ int yuvsize, bufsize;
flags |= _flags[pf];
if(bu) flags |= TJ_BOTTOMUP;
- if(yuv==YUVDECODE) flags |= TJ_YUV;
if((file=fopen(filename, "rb"))==NULL)
_throwunix("opening file");
if(tjDecompressHeader2(hnd, jpegbuf, jpgbufsize, &w, &h, &jpegsub)==-1)
_throwtj("executing tjDecompressHeader2()");
- hsf=_hsf[jpegsub], vsf=_vsf[jpegsub];
- pw=PAD(w, hsf), ph=PAD(h, vsf);
- cw=pw/hsf, ch=ph/vsf;
- ypitch=PAD(pw, 4), uvpitch=PAD(cw, 4);
- yuvsize=ypitch*ph + (jpegsub==TJ_GRAYSCALE? 0:uvpitch*ch*2);
+ yuvsize=TJBUFSIZEYUV(w, h, jpegsub);
pitch=w*ps;
printf("%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD", w, h);
}
- if((rgbbuf=(unsigned char *)malloc(max(yuvsize, pitch*h)))==NULL)
+ bufsize=(yuv==YUVDECODE? yuvsize:pitch*h);
+ if((rgbbuf=(unsigned char *)malloc(bufsize))==NULL)
_throwunix("allocating image buffer");
if(!quiet)
printf("\nImage size: %d x %d\n", w, h);
}
- memset(rgbbuf, 127, max(yuvsize, pitch*h)); // Grey image means decompressor did nothing
- if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps, flags)==-1)
+ memset(rgbbuf, 127, bufsize); // Grey image means decompressor did nothing
+ if(yuv==YUVDECODE)
+ {
+ if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
+ _throwtj("executing tjDecompressToYUV()");
+ }
+ else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
+ flags)==-1)
_throwtj("executing tjDecompress()");
ITER=0;
start=rrtime();
do
{
- if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps, flags)
- ==-1)
+ if(yuv==YUVDECODE)
+ {
+ if(tjDecompressToYUV(hnd, jpegbuf, jpgbufsize, rgbbuf, flags)==-1)
+ _throwtj("executing tjDecompressToYUV()");
+ }
+ else if(tjDecompress(hnd, jpegbuf, jpgbufsize, rgbbuf, w, pitch, h, ps,
+ flags)==-1)
_throwtj("executing tjDecompress()");
ITER++;
} while((elapsed=rrtime()-start)<5.);
TURBOJPEG_1.1
{
global:
+ TJBUFSIZEYUV;
tjDecompressHeader2;
+ tjDecompressToYUV;
+ tjEncodeYUV;
} TURBOJPEG_1.0;
/* Use fast, inaccurate 4:2:2 and 4:2:0 YUV upsampling routines
(libjpeg and libjpeg-turbo versions only) */
#define TJ_YUV 512
- /* If passed to tjCompress(), this causes TurboJPEG to use the accelerated
- color conversion routines in the underlying codec to produce a planar
- YUV image that is suitable for X Video. Specifically, if the chrominance
- components are subsampled along the horizontal dimension, then the width
- of the luminance plane is padded to 2 in the output image (same goes for
- the height of the luminance plane, if the chrominance components are
- subsampled along the vertical dimension.) Also, each line of each plane
- in the output image is padded to 4 bytes. Although this will work with
- any subsampling option, it is really only useful in combination with
- TJ_420, which produces an image compatible with the I420 (AKA "YUV420P")
- format.
-
- If passed to tjDecompress(), this tells TurboJPEG to perform JPEG
- decompression but to leave out the color conversion step, so a planar YUV
- image is generated instead of an RGB image. The padding of the planes in
- this image is the same as in the above case. Note that, if the width or
- height of the output image is not a multiple of 8 (or a multiple of 16
- along any dimension in which chrominance subsampling is used), then an
- intermediate buffer copy will be performed within TurboJPEG.
- */
+ /* Nothing to see here. Pay no attention to the man behind the curtain. */
typedef void* tjhandle;
and returns a handle to the instance. Most applications will only
need to call this once at the beginning of the program or once for each
concurrent thread. Don't try to create a new instance every time you
- compress an image, because this will cause performance to suffer.
+ compress an image, because this may cause performance to suffer in some
+ TurboJPEG implementations.
RETURNS: NULL on error
*/
tjInitCompress()
[INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
grayscale pixels to be compressed
- [INPUT] width = width (in pixels) of the source image
+ [INPUT] width = width (in pixels) of the source image
[INPUT] pitch = bytes per line of the source image (width*pixelsize if the
bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
is padded to the nearest 32-bit boundary, such as is the case for Windows
the appropriate size for this buffer based on the image width and height.
[OUTPUT] size = pointer to unsigned long which receives the size (in bytes)
of the compressed image
- [INPUT] jpegsubsamp = Specifies either 4:2:0, 4:2:2, or 4:4:4 subsampling.
- When the image is converted from the RGB to YCbCr colorspace as part of
- the JPEG compression process, every other Cb and Cr (chrominance) pixel
- can be discarded to produce a smaller image with little perceptible loss
- of image clarity (the human eye is more sensitive to small changes in
- brightness than small changes in color.)
+ [INPUT] jpegsubsamp = Specifies either 4:2:0, 4:2:2, 4:4:4, or grayscale
+ subsampling. When the image is converted from the RGB to YCbCr colorspace
+ as part of the JPEG compression process, every other Cb and Cr
+ (chrominance) pixel can be discarded to produce a smaller image with
+ little perceptible loss of image clarity (the human eye is more sensitive
+ to small changes in brightness than small changes in color.)
TJ_420: 4:2:0 subsampling. Discards every other Cb, Cr pixel in both
horizontal and vertical directions
unsigned char *dstbuf, unsigned long *size,
int jpegsubsamp, int jpegqual, int flags);
+
+/*
+ unsigned long TJBUFSIZE(int width, int height)
+
+ Convenience function which returns the maximum size of the buffer required to
+ hold a JPEG image with the given width and height
+
+ RETURNS: -1 if arguments are out of bounds
+*/
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
+
+/*
+ unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
+
+ Convenience function which returns the size of the buffer required to
+ hold a YUV planar image with the given width, height, and level of
+ chrominance subsampling
+
+ RETURNS: -1 if arguments are out of bounds
+*/
+DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
+ int subsamp);
+
+
+/*
+ int tjEncodeYUV(tjhandle j,
+ unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+ unsigned char *dstbuf, int subsamp, int flags)
+
+ This function uses the accelerated color conversion routines in TurboJPEG's
+ underlying codec to produce a planar YUV image that is suitable for X Video.
+ Specifically, if the chrominance components are subsampled along the
+ horizontal dimension, then the width of the luminance plane is padded to 2 in
+ the output image (same goes for the height of the luminance plane, if the
+ chrominance components are subsampled along the vertical dimension.) Also,
+ each line of each plane in the output image is padded to 4 bytes. Although
+ this will work with any subsampling option, it is really only useful in
+ combination with TJ_420, which produces an image compatible with the I420
+ (AKA "YUV420P") format.
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitCompress()
+ [INPUT] srcbuf = pointer to user-allocated image buffer containing RGB or
+ grayscale pixels to be encoded
+ [INPUT] width = width (in pixels) of the source image
+ [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
+ bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+ is padded to the nearest 32-bit boundary, such as is the case for Windows
+ bitmaps. You can also be clever and use this parameter to skip lines,
+ etc. Setting this parameter to 0 is the equivalent of setting it to
+ width*pixelsize.
+ [INPUT] height = height (in pixels) of the source image
+ [INPUT] pixelsize = size (in bytes) of each pixel in the source image
+ RGBX/BGRX/XRGB/XBGR: 4, RGB/BGR: 3, Grayscale: 1
+ [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+ the YUV image. Use the TJBUFSIZEYUV(width, height, subsamp) function to
+ determine the appropriate size for this buffer based on the image width,
+ height, and level of subsampling.
+ [INPUT] subsamp = Specifies either 4:2:0, 4:2:2, 4:4:4, or grayscale
+ subsampling (see description under tjCompress())
+ [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 tjEncodeYUV(tjhandle j,
+ unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+ unsigned char *dstbuf, int subsamp, int flags);
+
+
/*
tjhandle tjInitDecompress(void)
structures, and returns a handle to the instance. Most applications will
only need to call this once at the beginning of the program or once for each
concurrent thread. Don't try to create a new instance every time you
- decompress an image, because this will cause performance to suffer.
+ decompress an image, because this may cause performance to suffer in some
+ TurboJPEG implementations.
RETURNS: NULL on error
*/
[INPUT] j = instance handle previously returned from a call to
tjInitDecompress()
- [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
- to decompress
+ [INPUT] srcbuf = pointer to a user-allocated buffer containing a JPEG image
[INPUT] size = size of the JPEG image buffer (in bytes)
[OUTPUT] width = width (in pixels) of the JPEG image
[OUTPUT] height = height (in pixels) of the JPEG image
the bitmap image. This buffer should normally be pitch*height
bytes in size, although this pointer may also be used to decompress into
a specific region of a larger buffer.
- [INPUT] width = width (in pixels) of the destination image
+ [INPUT] width = width (in pixels) of the destination image
[INPUT] pitch = bytes per line of the destination image (width*pixelsize if
the bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the
bitmap is padded to the nearest 32-bit boundary, such as is the case for
int flags);
+/*
+ int tjDecompressToYUV(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, int flags)
+
+ This function performs JPEG decompression but leaves out the color conversion
+ step, so a planar YUV image is generated instead of an RGB image. The
+ padding of the planes in this image is the same as in tjEncodeYUV().
+ Note that, if the width or height of the output image is not a multiple of 8
+ (or a multiple of 16 along any dimension in which chrominance subsampling is
+ used), then an intermediate buffer copy will be performed within TurboJPEG.
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitDecompress()
+ [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+ to decompress
+ [INPUT] size = size of the JPEG image buffer (in bytes)
+ [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+ the YUV image. Use the TJBUFSIZEYUV(width, height, subsamp) function to
+ determine the appropriate size for this buffer based on the image width,
+ height, and level of subsampling.
+ [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 tjDecompressToYUV(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, int flags);
+
+
/*
int tjDestroy(tjhandle h)
return (tjhandle)j;
}
+
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
{
- // This allows enough room in case the image doesn't compress
- return ((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
+ unsigned long retval=0;
+ if(width<1 || height<1)
+ _throw("Invalid argument in TJBUFSIZE()");
+
+ // This allows for rare corner cases in which a JPEG image can actually be
+ // larger than the uncompressed input (we wouldn't mention it if it hadn't
+ // happened before.)
+ retval=((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
+
+ bailout:
+ return retval;
+}
+
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
+ int subsamp)
+{
+ unsigned long retval=0;
+ 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];
+ retval=PAD(pw, 4)*ph + (subsamp==TJ_GRAYSCALE? 0:PAD(cw, 4)*ch*2);
+
+ bailout:
+ return retval;
}
+
DLLEXPORT int DLLCALL tjCompress(tjhandle h,
unsigned char *srcbuf, int width, int pitch, int height, int ps,
unsigned char *dstbuf, unsigned long *size,
}
+DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle h,
+ 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,
+ subsamp, 0, flags|TJ_YUV);
+}
+
+
// DEC
static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
int ih;
iw[i]=compptr->width_in_blocks*DCTSIZE;
ih=compptr->height_in_blocks*DCTSIZE;
- cw[i]=PAD(width, dinfo->max_h_samp_factor)*compptr->h_samp_factor
- /dinfo->max_h_samp_factor;
- ch[i]=PAD(height, dinfo->max_v_samp_factor)*compptr->v_samp_factor
- /dinfo->max_v_samp_factor;
+ cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor)
+ *compptr->h_samp_factor/dinfo->max_h_samp_factor;
+ ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor)
+ *compptr->v_samp_factor/dinfo->max_v_samp_factor;
if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1;
th[i]=compptr->v_samp_factor*DCTSIZE;
tmpbufsize+=iw[i]*th[i];
}
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, int flags)
+{
+ return tjDecompress(h, srcbuf, size, dstbuf, 1, 0, 1, 3, flags|TJ_YUV);
+}
+
+
// General
DLLEXPORT char* DLLCALL tjGetErrorStr(void)