]> granicus.if.org Git - libjpeg-turbo/commitdiff
Extend the TurboJPEG C API to support compressing JPEG images from YUV planar images
authorDRC <dcommander@users.sourceforge.net>
Wed, 30 Oct 2013 23:02:57 +0000 (23:02 +0000)
committerDRC <dcommander@users.sourceforge.net>
Wed, 30 Oct 2013 23:02:57 +0000 (23:02 +0000)
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@1067 632fc199-4ca6-4c93-a231-07263d6284db

ChangeLog.txt
Makefile.am
doc/html/group___turbo_j_p_e_g.html
doc/html/search/all_74.js
doc/html/search/functions_74.js
tjunittest.c
turbojpeg-mapfile
turbojpeg-mapfile.jni
turbojpeg.c
turbojpeg.h

index 4236dfe017aa54eefbd20434c496f8353cde9b86..2ee2ca54d2bd8b5c38ad6911ffbd62dde7a39f85 100644 (file)
@@ -20,6 +20,9 @@ decompressed to CMYK destination images.  Conversion between CMYK and RGB
 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
 =====
index 6096049b3cf44a60daafe25ba6a7819c8b69ecab..a754fa37ea9ee656d66c89735a53aba3bf9da605 100644 (file)
@@ -207,6 +207,7 @@ endif
        ./tjunittest
        ./tjunittest -alloc
        ./tjunittest -yuv
+       ./tjunittest -yuv -alloc
        ./tjunittest -yuv -noyuvpad
 endif
        ./cjpeg -dct int -outfile testoutint.jpg $(srcdir)/testimages/testorig.ppm
index c1df1939fd7558645b20421292aede7e09bd61d1..d0c1303a08ed528638f37f038944c868d3dd3565 100644 (file)
@@ -240,6 +240,9 @@ Functions</h2></td></tr>
 <tr class="memitem:gaba62b7a98f960839b588579898495cf2"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
+<tr class="memitem:ga0b931126c7a615ddc3bbd0cca6698d67"><td class="memItemLeft" align="right" valign="top">DLLEXPORT int DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
 <tr class="memitem:gaccc5bca7f12fcdcc302e6e1c6d4b311b"><td class="memItemLeft" align="right" valign="top">DLLEXPORT unsigned long DLLCALL&#160;</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">&#160;</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">&#160;</td></tr>
@@ -1054,6 +1057,103 @@ If you choose option 1, <code>*jpegSize</code> should be set to the size of your
 </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>&#160;</td>
+          <td class="paramname"><em>handle</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char *&#160;</td>
+          <td class="paramname"><em>srcBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>width</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>pad</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>height</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>subsamp</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned char **&#160;</td>
+          <td class="paramname"><em>jpegBuf</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">unsigned long *&#160;</td>
+          <td class="paramname"><em>jpegSize</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>jpegQual</em>, </td>
+        </tr>
+        <tr>
+          <td class="paramkey"></td>
+          <td></td>
+          <td class="paramtype">int&#160;</td>
+          <td class="paramname"><em>flags</em>&#160;</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>
index 4aec52863fa1fb3ff45a6fef7690658081acb63f..a32ccde87f8c292df67469a542d0ab19ea62fd07 100644 (file)
@@ -9,6 +9,7 @@ var searchData=
   ['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']]],
@@ -65,7 +66,7 @@ var searchData=
   ['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():&#160;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):&#160;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):&#160;turbojpeg.h'],['../group___turbo_j_p_e_g.html#gaa29f3189c41be12ec5dee7caec318a31',1,'tjtransform():&#160;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']]],
index 8f92c26d63f76c0e28ed7ab57db5393d75cfef37..4a42d2aafc4c578e88119d1905a8dd4f5dc3a86b 100644 (file)
@@ -4,6 +4,7 @@ var searchData=
   ['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']]],
index b738c6c2b231cfcacd9b3826aee9fed4297e1aa9..77ccb5da5c35e66afc5b74694a5fd97753a855d8 100644 (file)
@@ -295,6 +295,60 @@ int checkBuf(unsigned char *buf, int w, int h, int pf, int subsamp,
 
 #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)
 {
@@ -400,17 +454,29 @@ void compTest(tjhandle handle, unsigned char **dstBuf,
        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();
@@ -421,14 +487,17 @@ void compTest(tjhandle handle, unsigned char **dstBuf,
        }
        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;
 
@@ -550,13 +619,13 @@ void doTest(int w, int h, const int *formats, int nformats, int subsamp,
        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();
@@ -684,7 +753,7 @@ int main(int argc, char *argv[])
                }
        }
        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");
index 46e6ca749eb6d24ab0d01d6165e7b40d3a82f2f4..d8cf41c312881364f5416de7c40241f09a60cd00 100755 (executable)
@@ -41,6 +41,7 @@ TURBOJPEG_1.4
 {
        global:
                tjBufSizeYUV2;
+               tjCompressFromYUV;
                tjDecompressHeader3;
                tjDecompressToYUV2;
                tjEncodeYUV3;
index 7a5f98e8fb32c9074f7fe36ae8a738ea91d235de..7b050cd25ae63df86f0ac61a2d3a54e54a3b5c62 100755 (executable)
@@ -67,6 +67,7 @@ TURBOJPEG_1.4
 {
        global:
                tjBufSizeYUV2;
+               tjCompressFromYUV;
                tjDecompressHeader3;
                tjDecompressToYUV2;
                tjEncodeYUV3;
index bd37f575c817109e3731295bf2df5c21df914312..d4ee84a813496516b8874d34793d6c533c4512d3 100644 (file)
@@ -861,6 +861,133 @@ DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf,
 }
 
 
+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)
@@ -1133,7 +1260,7 @@ DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle,
        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;
index 77019e0e58b41b0f87c008fb5a5022135018fb7a..b6597f1c40f143e7b627df534b81218b6180d30e 100644 (file)
@@ -655,6 +655,60 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf,
   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