images is not supported. Such conversion requires a color management system
and is out of scope for a codec library.
+[5] The TurboJPEG API can now be used to compress JPEG images from YUV planar
+source images.
+
1.3.1
=====
./tjunittest
./tjunittest -alloc
./tjunittest -yuv
+ ./tjunittest -yuv -alloc
./tjunittest -yuv -noyuvpad
endif
./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testimages/testorig.ppm
<tr class="memitem:gaba62b7a98f960839b588579898495cf2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2">tjCompress2</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *srcBuf, int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags)</td></tr>
<tr class="memdesc:gaba62b7a98f960839b588579898495cf2"><td class="mdescLeft"> </td><td class="mdescRight">Compress an RGB, grayscale, or CMYK image into a JPEG image. <a href="#gaba62b7a98f960839b588579898495cf2">More...</a><br/></td></tr>
<tr class="separator:gaba62b7a98f960839b588579898495cf2"><td class="memSeparator" colspan="2"> </td></tr>
+<tr class="memitem:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67">tjCompressFromYUV</a> (<a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> handle, unsigned char *srcBuf, int width, int pad, int height, int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags)</td></tr>
+<tr class="memdesc:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="mdescLeft"> </td><td class="mdescRight">Compress a YUV planar image into a JPEG image. <a href="#ga0b931126c7a615ddc3bbd0cca6698d67">More...</a><br/></td></tr>
+<tr class="separator:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="memSeparator" colspan="2"> </td></tr>
<tr class="memitem:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long DLLCALL </td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b">tjBufSize</a> (int width, int height, int jpegSubsamp)</td></tr>
<tr class="memdesc:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="mdescLeft"> </td><td class="mdescRight">The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters. <a href="#gaccc5bca7f12fcdcc302e6e1c6d4b311b">More...</a><br/></td></tr>
<tr class="separator:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="memSeparator" colspan="2"> </td></tr>
</dl>
<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+</div>
+</div>
+<a class="anchor" id="ga0b931126c7a615ddc3bbd0cca6698d67"></a>
+<div class="memitem">
+<div class="memproto">
+ <table class="memname">
+ <tr>
+ <td class="memname">DLLEXPORT int DLLCALL tjCompressFromYUV </td>
+ <td>(</td>
+ <td class="paramtype"><a class="el" href="group___turbo_j_p_e_g.html#ga758d2634ecb4949de7815cba621f5763">tjhandle</a> </td>
+ <td class="paramname"><em>handle</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">unsigned char * </td>
+ <td class="paramname"><em>srcBuf</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>width</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>pad</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>height</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>subsamp</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">unsigned char ** </td>
+ <td class="paramname"><em>jpegBuf</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">unsigned long * </td>
+ <td class="paramname"><em>jpegSize</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>jpegQual</em>, </td>
+ </tr>
+ <tr>
+ <td class="paramkey"></td>
+ <td></td>
+ <td class="paramtype">int </td>
+ <td class="paramname"><em>flags</em> </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td>)</td>
+ <td></td><td></td>
+ </tr>
+ </table>
+</div><div class="memdoc">
+
+<p>Compress a YUV planar image into a JPEG image. </p>
+<dl class="params"><dt>Parameters</dt><dd>
+ <table class="params">
+ <tr><td class="paramname">handle</td><td>a handle to a TurboJPEG compressor or transformer instance </td></tr>
+ <tr><td class="paramname">srcBuf</td><td>pointer to an image buffer containing a YUV planar image to be compressed. The Y, U (Cb), and V (Cr) image planes should be stored sequentially in the buffer, and the size of each plane is determined by the specified width, height, padding, and level of chrominance subsampling. If the chrominance components are subsampled along the horizontal dimension, then the width of the luminance plane should be padded to the nearest multiple of 2 (same goes for the height of the luminance plane, if the chrominance components are subsampled along the vertical dimension.) This is irrespective of any additional padding specified in the <code>pad</code> parameter. </td></tr>
+ <tr><td class="paramname">width</td><td>width (in pixels) of the source image </td></tr>
+ <tr><td class="paramname">pad</td><td>the line padding used in the source image. For instance, if each line in each plane of the YUV image is padded to the nearest multiple of 4 bytes, then <code>pad</code> should be set to 4. </td></tr>
+ <tr><td class="paramname">height</td><td>height (in pixels) of the source image </td></tr>
+ <tr><td class="paramname">subsamp</td><td>the level of chrominance subsampling used in the source image (see <a class="el" href="group___turbo_j_p_e_g.html#ga1d047060ea80bb9820d540bb928e9074">Chrominance subsampling options</a>.) </td></tr>
+ <tr><td class="paramname">jpegBuf</td><td>address of a pointer to an image buffer that will receive the JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to accommodate the size of the JPEG image. Thus, you can choose to:<ol type="1">
+<li>pre-allocate the JPEG buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#ga5c9234bda6d993cdaffdd89bf81a00ff" title="Allocate an image buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
+<li>set <code>*jpegBuf</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
+<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters...">tjBufSize()</a>. This should ensure that the buffer never has to be re-allocated (setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a> guarantees this.)</li>
+</ol>
+If you choose option 1, <code>*jpegSize</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>*jpegBuf</code> upon return from this function, as it may have changed. </td></tr>
+ <tr><td class="paramname">jpegSize</td><td>pointer to an unsigned long variable that holds the size of the JPEG image buffer. If <code>*jpegBuf</code> points to a pre-allocated buffer, then <code>*jpegSize</code> should be set to the size of the buffer. Upon return, <code>*jpegSize</code> will contain the size of the JPEG image (in bytes.) </td></tr>
+ <tr><td class="paramname">jpegQual</td><td>the image quality of the generated JPEG image (1 = worst, 100 = best) </td></tr>
+ <tr><td class="paramname">flags</td><td>the bitwise OR of one or more of the <a class="el" href="group___turbo_j_p_e_g.html#ga72ecf4ebe6eb702d3c6f5ca27455e1ec">flags</a>.</td></tr>
+ </table>
+ </dd>
+</dl>
+<dl class="section return"><dt>Returns</dt><dd>0 if successful, or -1 if an error occurred (see <a class="el" href="group___turbo_j_p_e_g.html#ga9af79c908ec131b1ae8d52fe40375abf" title="Returns a descriptive error message explaining why the last command failed.">tjGetErrorStr()</a>.) </dd></dl>
+
</div>
</div>
<a class="anchor" id="gada69cc6443d1bb493b40f1626259e5e9"></a>
['tjbufsize',['tjBufSize',['../group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b',1,'turbojpeg.h']]],
['tjbufsizeyuv2',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#gaf451664a62c1f6c7cc5a6401f32908c9',1,'turbojpeg.h']]],
['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2',1,'turbojpeg.h']]],
+ ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67',1,'turbojpeg.h']]],
['tjcs',['TJCS',['../group___turbo_j_p_e_g.html#ga4f83ad3368e0e29d1957be0efa7c3720',1,'turbojpeg.h']]],
['tjcs_5fcmyk',['TJCS_CMYK',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720a6c8b636152ac8195b869587db315ee53',1,'turbojpeg.h']]],
['tjcs_5fgray',['TJCS_GRAY',['../group___turbo_j_p_e_g.html#gga4f83ad3368e0e29d1957be0efa7c3720ab3e7d6a87f695e45b81c1b5262b5a50a',1,'turbojpeg.h']]],
['tjsamp_5fgray',['TJSAMP_GRAY',['../group___turbo_j_p_e_g.html#gga1d047060ea80bb9820d540bb928e9074a3f1c9504842ddc7a48d0f690754b6248',1,'turbojpeg.h']]],
['tjscaled',['TJSCALED',['../group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df',1,'turbojpeg.h']]],
['tjscalingfactor',['tjscalingfactor',['../structtjscalingfactor.html',1,'']]],
- ['tjtransform',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform(): turbojpeg.h'],['../group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616',1,'tjTransform(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags): turbojpeg.h']]],
+ ['tjtransform',['tjtransform',['../structtjtransform.html',1,'tjtransform'],['../group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616',1,'tjTransform(tjhandle handle, unsigned char *jpegBuf, unsigned long jpegSize, int n, unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *transforms, int flags): turbojpeg.h'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform(): turbojpeg.h']]],
['tjxop',['TJXOP',['../group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866',1,'turbojpeg.h']]],
['tjxop_5fhflip',['TJXOP_HFLIP',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aa0df69776caa30f0fa28e26332d311ce',1,'turbojpeg.h']]],
['tjxop_5fnone',['TJXOP_NONE',['../group___turbo_j_p_e_g.html#gga2de531af4e7e6c4f124908376b354866aad88c0366cd3f7d0eac9d7a3fa1c2c27',1,'turbojpeg.h']]],
['tjbufsize',['tjBufSize',['../group___turbo_j_p_e_g.html#gaccc5bca7f12fcdcc302e6e1c6d4b311b',1,'turbojpeg.h']]],
['tjbufsizeyuv2',['tjBufSizeYUV2',['../group___turbo_j_p_e_g.html#gaf451664a62c1f6c7cc5a6401f32908c9',1,'turbojpeg.h']]],
['tjcompress2',['tjCompress2',['../group___turbo_j_p_e_g.html#gaba62b7a98f960839b588579898495cf2',1,'turbojpeg.h']]],
+ ['tjcompressfromyuv',['tjCompressFromYUV',['../group___turbo_j_p_e_g.html#ga0b931126c7a615ddc3bbd0cca6698d67',1,'turbojpeg.h']]],
['tjdecompress2',['tjDecompress2',['../group___turbo_j_p_e_g.html#gada69cc6443d1bb493b40f1626259e5e9',1,'turbojpeg.h']]],
['tjdecompressheader3',['tjDecompressHeader3',['../group___turbo_j_p_e_g.html#gacd0fac3af74b3511d39b4781b7103086',1,'turbojpeg.h']]],
['tjdecompresstoyuv2',['tjDecompressToYUV2',['../group___turbo_j_p_e_g.html#ga7c08b340ad7f8e85d407bd9e81d44d07',1,'turbojpeg.h']]],
#define PAD(v, p) ((v+(p)-1)&(~((p)-1)))
+void initBufYUV(unsigned char *buf, int w, int pad, int h, int subsamp)
+{
+ int row, col;
+ int hsf=tjMCUWidth[subsamp]/8, vsf=tjMCUHeight[subsamp]/8;
+ int pw=PAD(w, hsf), ph=PAD(h, vsf);
+ int cw=pw/hsf, ch=ph/vsf;
+ int ypitch=PAD(pw, pad), uvpitch=PAD(cw, pad);
+ int halfway=16, blocksize=8;
+
+ memset(buf, 0, tjBufSizeYUV2(w, pad, h, subsamp));
+
+ for(row=0; row<ph; row++)
+ {
+ for(col=0; col<pw; col++)
+ {
+ unsigned char *y=&buf[ypitch*row+col];
+ if(((row/blocksize)+(col/blocksize))%2==0)
+ {
+ if(row<halfway) *y=255; else *y=0;
+ }
+ else
+ {
+ if(row<halfway) *y=76; else *y=226;
+ }
+ }
+ }
+ if(subsamp!=TJSAMP_GRAY)
+ {
+ halfway=16/vsf;
+ for(row=0; row<ch; row++)
+ {
+ for(col=0; col<cw; col++)
+ {
+ unsigned char *u=&buf[ypitch*ph + (uvpitch*row+col)],
+ *v=&buf[ypitch*ph + uvpitch*ch + (uvpitch*row+col)];
+ if(((row*vsf/blocksize)+(col*hsf/blocksize))%2==0)
+ *u=*v=128;
+ else
+ {
+ if(row<halfway)
+ {
+ *u=85; *v=255;
+ }
+ else
+ {
+ *u=0; *v=149;
+ }
+ }
+ }
+ }
+ }
+}
+
+
int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
tjscalingfactor sf)
{
char tempStr[1024]; unsigned char *srcBuf=NULL;
double t;
- if(yuv==YUVENCODE)
- printf("%s %s -> %s YUV ... ", pixFormatStr[pf],
- (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp]);
+ if(yuv==YUVDECODE)
+ {
+ printf("YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp],
+ (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", jpegQual);
+ if((srcBuf=(unsigned char *)malloc(tjBufSizeYUV2(w, pad, h, subsamp)))
+ ==NULL)
+ _throw("Memory allocation failure");
+ initBufYUV(srcBuf, w, pad, h, subsamp);
+ }
else
- printf("%s %s -> %s Q%d ... ", pixFormatStr[pf],
- (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp],
- jpegQual);
+ {
+ if(yuv==YUVENCODE)
+ printf("%s %s -> %s YUV ... ", pixFormatStr[pf],
+ (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp]);
+ else
+ printf("%s %s -> %s Q%d ... ", pixFormatStr[pf],
+ (flags&TJFLAG_BOTTOMUP)? "Bottom-Up":"Top-Down ", subNameLong[subsamp],
+ jpegQual);
+ if((srcBuf=(unsigned char *)malloc(w*h*tjPixelSize[pf]))==NULL)
+ _throw("Memory allocation failure");
+ initBuf(srcBuf, w, h, pf, flags);
+ }
- if((srcBuf=(unsigned char *)malloc(w*h*tjPixelSize[pf]))==NULL)
- _throw("Memory allocation failure");
- initBuf(srcBuf, w, h, pf, flags);
if(*dstBuf && *dstSize>0) memset(*dstBuf, 0, *dstSize);
t=gettime();
}
else
{
- if(!alloc)
+ if(!alloc) flags|=TJFLAG_NOREALLOC;
+ if(yuv==YUVDECODE)
+ {
+ _tj(tjCompressFromYUV(handle, srcBuf, w, pad, h, subsamp, dstBuf,
+ dstSize, jpegQual, flags));
+ }
+ else
{
- flags|=TJFLAG_NOREALLOC;
- *dstSize=(yuv==YUVENCODE? tjBufSizeYUV2(w, pad, h, subsamp)
- : tjBufSize(w, h, subsamp));
+ _tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
+ jpegQual, flags));
}
- _tj(tjCompress2(handle, srcBuf, w, 0, h, pf, dstBuf, dstSize, subsamp,
- jpegQual, flags));
}
t=gettime()-t;
unsigned char *dstBuf=NULL;
unsigned long size=0; int pfi, pf, i;
- if(!alloc)
- {
- size=(yuv==YUVENCODE? tjBufSizeYUV2(w, pad, h, subsamp)
- : tjBufSize(w, h, subsamp));
+ if(yuv==YUVENCODE)
+ size=tjBufSizeYUV2(w, pad, h, subsamp);
+ else if(!alloc)
+ size=tjBufSize(w, h, subsamp);
+ if(size!=0)
if((dstBuf=(unsigned char *)tjAlloc(size))==NULL)
_throw("Memory allocation failure.");
- }
if((chandle=tjInitCompress())==NULL || (dhandle=tjInitDecompress())==NULL)
_throwtj();
}
}
if(alloc) printf("Testing automatic buffer allocation\n");
- if(doyuv) {yuv=YUVENCODE; alloc=0; num4bf=4;}
+ if(doyuv) {yuv=YUVENCODE; num4bf=4;}
doTest(35, 39, _3byteFormats, 2, TJSAMP_444, "test");
doTest(39, 41, _4byteFormats, num4bf, TJSAMP_444, "test");
doTest(41, 35, _3byteFormats, 2, TJSAMP_422, "test");
{
global:
tjBufSizeYUV2;
+ tjCompressFromYUV;
tjDecompressHeader3;
tjDecompressToYUV2;
tjEncodeYUV3;
{
global:
tjBufSizeYUV2;
+ tjCompressFromYUV;
tjDecompressHeader3;
tjDecompressToYUV2;
tjEncodeYUV3;
}
+DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
+ int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual, int flags)
+{
+ int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS];
+ int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS],
+ tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS];
+ JSAMPLE *_tmpbuf=NULL, *ptr=srcBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS];
+
+ for(i=0; i<MAX_COMPONENTS; i++)
+ {
+ tmpbuf[i]=NULL; inbuf[i]=NULL;
+ }
+
+ getinstance(handle)
+ if((this->init&COMPRESS)==0)
+ _throw("tjCompressFromYUV(): Instance has not been initialized for compression");
+
+ if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0
+ || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0
+ || jpegQual>100)
+ _throw("tjCompressFromYUV(): Invalid argument");
+
+ if(setjmp(this->jerr.setjmp_buffer))
+ {
+ /* If we get here, the JPEG code has signaled an error. */
+ retval=-1;
+ goto bailout;
+ }
+
+ cinfo->image_width=width;
+ cinfo->image_height=height;
+
+ if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
+ else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1");
+ else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+
+ if(flags&TJFLAG_NOREALLOC)
+ {
+ alloc=0; *jpegSize=tjBufSize(width, height, subsamp);
+ }
+ jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc);
+ if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1)
+ return -1;
+ cinfo->raw_data_in=TRUE;
+
+ jpeg_start_compress(cinfo, TRUE);
+ for(i=0; i<cinfo->num_components; i++)
+ {
+ jpeg_component_info *compptr=&cinfo->comp_info[i];
+ int ih;
+ iw[i]=compptr->width_in_blocks*DCTSIZE;
+ ih=compptr->height_in_blocks*DCTSIZE;
+ cw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor)
+ *compptr->h_samp_factor/cinfo->max_h_samp_factor;
+ ch[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor)
+ *compptr->v_samp_factor/cinfo->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];
+ if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL)
+ _throw("tjCompressFromYUV(): Memory allocation failure");
+ for(row=0; row<ch[i]; row++)
+ {
+ inbuf[i][row]=ptr;
+ ptr+=PAD(cw[i], pad);
+ }
+ }
+ if(usetmpbuf)
+ {
+ if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL)
+ _throw("tjCompressFromYUV(): Memory allocation failure");
+ ptr=_tmpbuf;
+ for(i=0; i<cinfo->num_components; i++)
+ {
+ if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL)
+ _throw("tjCompressFromYUV(): Memory allocation failure");
+ for(row=0; row<th[i]; row++)
+ {
+ tmpbuf[i][row]=ptr;
+ ptr+=iw[i];
+ }
+ }
+ }
+
+ for(row=0; row<(int)cinfo->image_height;
+ row+=cinfo->max_v_samp_factor*DCTSIZE)
+ {
+ JSAMPARRAY yuvptr[MAX_COMPONENTS];
+ int crow[MAX_COMPONENTS];
+ for(i=0; i<cinfo->num_components; i++)
+ {
+ jpeg_component_info *compptr=&cinfo->comp_info[i];
+ crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor;
+ if(usetmpbuf)
+ {
+ int j, k;
+ for(j=0; j<min(th[i], ch[i]-crow[i]); j++)
+ {
+ memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], cw[i]);
+ // Duplicate last sample in row to fill out MCU
+ for(k=cw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][cw[i]-1];
+ }
+ // Duplicate last row to fill out MCU
+ for(j=ch[i]-crow[i]; j<th[i]; j++)
+ memcpy(tmpbuf[i][j], tmpbuf[i][ch[i]-crow[i]-1], iw[i]);
+ yuvptr[i]=tmpbuf[i];
+ }
+ else
+ yuvptr[i]=&inbuf[i][crow[i]];
+ }
+ jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE);
+ }
+ jpeg_finish_compress(cinfo);
+
+ bailout:
+ if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo);
+ for(i=0; i<MAX_COMPONENTS; i++)
+ {
+ if(tmpbuf[i]) free(tmpbuf[i]);
+ if(inbuf[i]) free(inbuf[i]);
+ }
+ if(_tmpbuf) free(_tmpbuf);
+ return retval;
+}
+
+
/* Decompressor */
static tjhandle _tjInitDecompress(tjinstance *this)
jpeg_read_header(dinfo, TRUE);
jpegSubsamp=getSubsamp(dinfo);
if(jpegSubsamp<0)
- _throw("tjDecompressToYUV2: Could not determine subsampling type for JPEG image");
+ _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image");
jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height;
if(width==0) width=jpegwidth;
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags);
+/**
+ * Compress a YUV planar image into a JPEG image.
+ *
+ * @param handle a handle to a TurboJPEG compressor or transformer instance
+ * @param srcBuf pointer to an image buffer containing a YUV planar image
+ * to be compressed. The Y, U (Cb), and V (Cr) image planes should be
+ * stored sequentially in the buffer, and the size of each plane
+ * is determined by the specified width, height, padding, and level of
+ * chrominance subsampling. If the chrominance components are
+ * subsampled along the horizontal dimension, then the width of the
+ * luminance plane should be padded to the nearest multiple of 2 (same
+ * goes for the height of the luminance plane, if the chrominance
+ * components are subsampled along the vertical dimension.) This is
+ * irrespective of any additional padding specified in the <tt>pad</tt>
+ * parameter.
+ * @param width width (in pixels) of the source image
+ * @param pad the line padding used in the source image. For instance, if each
+ * line in each plane of the YUV image is padded to the nearest multiple
+ * of 4 bytes, then <tt>pad</tt> should be set to 4.
+ * @param height height (in pixels) of the source image
+ * @param subsamp the level of chrominance subsampling used in the source
+ * image (see @ref TJSAMP "Chrominance subsampling options".)
+ * @param jpegBuf address of a pointer to an image buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer
+ * to accommodate the size of the JPEG image. Thus, you can choose to:
+ * -# pre-allocate the JPEG buffer with an arbitrary size using
+ * #tjAlloc() and let TurboJPEG grow the buffer as needed,
+ * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the
+ * buffer for you, or
+ * -# pre-allocate the buffer to a "worst case" size determined by
+ * calling #tjBufSize(). This should ensure that the buffer never has
+ * to be re-allocated (setting #TJFLAG_NOREALLOC guarantees this.)
+ * .
+ * If you choose option 1, <tt>*jpegSize</tt> should be set to the
+ * size of your pre-allocated buffer. In any case, unless you have
+ * set #TJFLAG_NOREALLOC, you should always check <tt>*jpegBuf</tt> upon
+ * return from this function, as it may have changed.
+ * @param jpegSize pointer to an unsigned long variable that holds the size of
+ * the JPEG image buffer. If <tt>*jpegBuf</tt> points to a
+ * pre-allocated buffer, then <tt>*jpegSize</tt> should be set to the
+ * size of the buffer. Upon return, <tt>*jpegSize</tt> will contain the
+ * size of the JPEG image (in bytes.)
+ * @param jpegQual the image quality of the generated JPEG image (1 = worst,
+ 100 = best)
+ * @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
+ * "flags".
+ *
+ * @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr().)
+*/
+DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, unsigned char *srcBuf,
+ int width, int pad, int height, int subsamp, unsigned char **jpegBuf,
+ unsigned long *jpegSize, int jpegQual, int flags);
+
+
/**
* The maximum size of the buffer (in bytes) required to hold a JPEG image with
* the given parameters. The number of bytes returned by this function is