Implement a custom DCT filter callback for lossless transforms

git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@703 632fc199-4ca6-4c93-a231-07263d6284db
This commit is contained in:
DRC
2011-09-17 00:18:31 +00:00
parent 9a4570a501
commit 7bf04d399e
14 changed files with 157 additions and 20 deletions

View File

@@ -81,7 +81,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -80,7 +80,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -64,6 +64,9 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</div>
<div class="contents">
<div class="textblock">Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:</div><ul>
<li>customFilter
: <a class="el" href="structtjtransform.html#a3b9280f092324befdf4da07ac085d9dd">tjtransform</a>
</li>
<li>denom
: <a class="el" href="structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3">tjscalingfactor</a>
</li>
@@ -107,7 +110,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -64,6 +64,9 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</div>
<div class="contents">
&#160;<ul>
<li>customFilter
: <a class="el" href="structtjtransform.html#a3b9280f092324befdf4da07ac085d9dd">tjtransform</a>
</li>
<li>denom
: <a class="el" href="structtjscalingfactor.html#aefbcdf3e9e62274b2d312c695f133ce3">tjscalingfactor</a>
</li>
@@ -107,7 +110,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -103,6 +103,8 @@ Defines</h2></td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will enable lossless cropping. <a href="#ga9c771a757fc1294add611906b89ab2d2"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga3acee7b48ade1b99e5588736007c2589">TJXOPT_GRAY</a></td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will discard the color data in the input image and produce a grayscale output image. <a href="#ga3acee7b48ade1b99e5588736007c2589"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#gafbf992bbf6e006705886333703ffab31">TJXOPT_NOOUTPUT</a></td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> from outputting a JPEG image for this particular transform (this can be used in conjunction with a custom filter to capture the transformed DCT coefficients without transcoding them.) <a href="#gafbf992bbf6e006705886333703ffab31"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga0aba955473315e405295d978f0c16511">TJPAD</a>(width)</td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">Pad the given width to the nearest 32-bit boundary. <a href="#ga0aba955473315e405295d978f0c16511"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">#define&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="group___turbo_j_p_e_g.html#ga84878bb65404204743aa18cac02781df">TJSCALED</a>(dimension, scalingFactor)</td></tr>
@@ -430,6 +432,21 @@ Variables</h2></td></tr>
<p>This option will discard the color data in the input image and produce a grayscale output image. </p>
</div>
</div>
<a class="anchor" id="gafbf992bbf6e006705886333703ffab31"></a><!-- doxytag: member="turbojpeg.h::TJXOPT_NOOUTPUT" ref="gafbf992bbf6e006705886333703ffab31" args="" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">#define TJXOPT_NOOUTPUT</td>
</tr>
</table>
</div>
<div class="memdoc">
<p>This option will prevent <a class="el" href="group___turbo_j_p_e_g.html#gae403193ceb4aafb7e0f56ab587b48616" title="Losslessly transform a JPEG image into another JPEG image.">tjTransform()</a> from outputting a JPEG image for this particular transform (this can be used in conjunction with a custom filter to capture the transformed DCT coefficients without transcoding them.) </p>
</div>
</div>
<a class="anchor" id="ga50e03cb5ed115330e212417429600b00"></a><!-- doxytag: member="turbojpeg.h::TJXOPT_PERFECT" ref="ga50e03cb5ed115330e212417429600b00" args="" -->
@@ -1502,7 +1519,7 @@ If you choose option 1, <code>dstSizes[i]</code> should be set to the size of yo
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -69,7 +69,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:45 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -72,7 +72,7 @@ var searchBox = new SearchBox("searchBox", "search",false,'Search');
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -7,9 +7,9 @@
var indexSectionsWithContent =
{
0: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000011001010011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100010000011001010011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
2: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000011001000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
2: "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100010000011001000011100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
};
var indexSectionNames =

View File

@@ -165,7 +165,7 @@ Data Fields</h2></td></tr>
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -127,7 +127,7 @@ Data Fields</h2></td></tr>
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -77,10 +77,39 @@ Data Fields</h2></td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">One of the <a class="el" href="group___turbo_j_p_e_g.html#ga2de531af4e7e6c4f124908376b354866">transform operations</a>. <a href="#a2525aab4ba6978a1c273f74fef50e498"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#ac0e74655baa4402209a21e1ae481c8f6">options</a></td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">The bitwise OR of one of more of the <a class="el" href="group___turbo_j_p_e_g.html#ga9c771a757fc1294add611906b89ab2d2">transform options</a>. <a href="#ac0e74655baa4402209a21e1ae481c8f6"></a><br/></td></tr>
<tr><td class="memItemLeft" align="right" valign="top">int(*&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a3b9280f092324befdf4da07ac085d9dd">customFilter</a> )(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex)</td></tr>
<tr><td class="mdescLeft">&#160;</td><td class="mdescRight">A callback function that can be used to modify the DCT coefficients after they are losslessly transformed but before they are transcoded to a new JPEG file. <a href="#a3b9280f092324befdf4da07ac085d9dd"></a><br/></td></tr>
</table>
<hr/><a name="details" id="details"></a><h2>Detailed Description</h2>
<div class="textblock"><p>Lossless transform. </p>
</div><hr/><h2>Field Documentation</h2>
<a class="anchor" id="a3b9280f092324befdf4da07ac085d9dd"></a><!-- doxytag: member="tjtransform::customFilter" ref="a3b9280f092324befdf4da07ac085d9dd" args=")(short *coeffs, tjregion arrayRegion, tjregion planeRegion, int componentIndex, int transformIndex)" -->
<div class="memitem">
<div class="memproto">
<table class="memname">
<tr>
<td class="memname">int(* <a class="el" href="structtjtransform.html#a3b9280f092324befdf4da07ac085d9dd">tjtransform::customFilter</a>)(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex)</td>
</tr>
</table>
</div>
<div class="memdoc">
<p>A callback function that can be used to modify the DCT coefficients after they are losslessly transformed but before they are transcoded to a new JPEG file. </p>
<p>This allows for custom filters or other transformations to be applied in the frequency domain.</p>
<dl><dt><b>Parameters:</b></dt><dd>
<table class="params">
<tr><td class="paramname">coeffs</td><td>pointer to an array of DCT coefficients. (NOTE: this pointer is not guaranteed to be valid once the callback returns, so applications wishing to hand off the DCT coefficients to another function or library should make a copy of them within the body of the callback.) </td></tr>
<tr><td class="paramname">arrayRegion</td><td>region structure containing the width and height of the DCT coefficient array as well as its offset relative to the component plane. TurboJPEG implementations may choose to split each component plane into multiple DCT coefficient arrays and call the callback function once for each array. </td></tr>
<tr><td class="paramname">planeRegion</td><td>region structure containing the width and height of the component plane to which this DCT coefficient array belongs </td></tr>
<tr><td class="paramname">componentIndex</td><td>the component plane to which this DCT coefficient array belongs (Y, Cb, and Cr are, respectively, 0, 1, and 2 in typical JPEG images.) </td></tr>
<tr><td class="paramname">transformIndex</td><td>the transformed image to which this DCT coefficient array belongs</td></tr>
</table>
</dd>
</dl>
<dl class="return"><dt><b>Returns:</b></dt><dd>0 if the callback was successful, or -1 if an error occurred. </dd></dl>
</div>
</div>
<a class="anchor" id="a2525aab4ba6978a1c273f74fef50e498"></a><!-- doxytag: member="tjtransform::op" ref="a2525aab4ba6978a1c273f74fef50e498" args="" -->
<div class="memitem">
<div class="memproto">
@@ -144,7 +173,7 @@ Data Fields</h2></td></tr>
</iframe>
</div>
<hr class="footer"/><address class="footer"><small>Generated on Mon Jul 11 2011 22:02:02 for TurboJPEG by&#160;
<hr class="footer"/><address class="footer"><small>Generated on Fri Sep 16 2011 19:05:46 for TurboJPEG by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>

View File

@@ -59,6 +59,7 @@ const char *subNameLong[TJ_NUMSAMP]=
const char *subName[NUMSUBOPT]={"444", "422", "420", "GRAY", "440"};
tjscalingfactor *scalingfactors=NULL, sf={1, 1}; int nsf=0;
int xformop=TJXOP_NONE, xformopt=0;
int (*customFilter)(short *, tjregion, tjregion, int, int);
double benchtime=5.0;
@@ -73,6 +74,14 @@ char *sigfig(double val, int figs, char *buf, int len)
}
int dummyDCTFilter(short *coeffs, tjregion arrayRegion, tjregion planeRegion,
int componentIndex, int transformIndex)
{
int i;
for(i=0; i<arrayRegion.w*arrayRegion.h; i++) coeffs[i]=-coeffs[i];
return 0;
}
/* Decompression test */
int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
unsigned long *jpegsize, unsigned char *dstbuf, int w, int h,
@@ -534,7 +543,7 @@ void dodecomptest(char *filename)
}
_subsamp=subsamp;
if(dotile || xformop!=TJXOP_NONE || xformopt!=0)
if(dotile || xformop!=TJXOP_NONE || xformopt!=0 || customFilter)
{
if((t=(tjtransform *)malloc(sizeof(tjtransform)*ntilesw*ntilesh))
==NULL)
@@ -568,6 +577,11 @@ void dodecomptest(char *filename)
t[tile].r.y=row*_tileh;
t[tile].op=xformop;
t[tile].options=xformopt|TJXOPT_TRIM;
t[tile].customFilter=customFilter;
if(t[tile].options&TJXOPT_NOOUTPUT && jpegbuf[tile])
{
free(jpegbuf[tile]); jpegbuf[tile]=NULL;
}
}
}
@@ -611,9 +625,13 @@ void dodecomptest(char *filename)
if(w==tilew) _tilew=_w;
if(h==tileh) _tileh=_h;
if(decomptest(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0,
filename, _tilew, _tileh)==-1)
goto bailout;
if(!(xformopt&TJXOPT_NOOUTPUT))
{
if(decomptest(NULL, jpegbuf, jpegsize, NULL, _w, _h, _subsamp, 0,
filename, _tilew, _tileh)==-1)
goto bailout;
}
else if(quiet==1) printf("N/A\n");
for(i=0; i<ntilesw*ntilesh; i++)
{
@@ -809,6 +827,8 @@ int main(int argc, char *argv[])
if(!strcasecmp(argv[i], "-rot180")) xformop=TJXOP_ROT180;
if(!strcasecmp(argv[i], "-rot270")) xformop=TJXOP_ROT270;
if(!strcasecmp(argv[i], "-grayscale")) xformopt|=TJXOPT_GRAY;
if(!strcasecmp(argv[i], "-custom")) customFilter=dummyDCTFilter;
if(!strcasecmp(argv[i], "-nooutput")) xformopt|=TJXOPT_NOOUTPUT;
if(!strcasecmp(argv[i], "-benchtime") && i<argc-1)
{
double temp=atof(argv[++i]);

View File

@@ -1038,15 +1038,45 @@ DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf,
{
alloc=0; dstSizes[i]=tjBufSize(w, h, jpegSubsamp);
}
jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
if(!(t[i].options&TJXOPT_NOOUTPUT))
jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
jpeg_copy_critical_parameters(dinfo, cinfo);
dstcoefs=jtransform_adjust_parameters(dinfo, cinfo, srccoefs,
&xinfo[i]);
jpeg_write_coefficients(cinfo, dstcoefs);
jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
if(!(t[i].options&TJXOPT_NOOUTPUT))
{
jpeg_write_coefficients(cinfo, dstcoefs);
jcopy_markers_execute(dinfo, cinfo, JCOPYOPT_ALL);
}
else jinit_c_master_control(cinfo, TRUE);
jtransform_execute_transformation(dinfo, cinfo, srccoefs,
&xinfo[i]);
jpeg_finish_compress(cinfo);
if(t[i].customFilter)
{
int ci, by, y;
for(ci=0; ci<cinfo->num_components; ci++)
{
jpeg_component_info *compptr=&cinfo->comp_info[ci];
tjregion arrayRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
DCTSIZE};
tjregion planeRegion={0, 0, compptr->width_in_blocks*DCTSIZE,
compptr->height_in_blocks*DCTSIZE};
for(by=0; by<compptr->height_in_blocks; by+=compptr->v_samp_factor)
{
JBLOCKARRAY barray=(dinfo->mem->access_virt_barray)
((j_common_ptr)dinfo, dstcoefs[ci], by, compptr->v_samp_factor,
TRUE);
for(y=0; y<compptr->v_samp_factor; y++)
{
if(t[i].customFilter(barray[y][0], arrayRegion, planeRegion,
ci, i)==-1)
_throw("tjTransform(): Error in custom filter");
arrayRegion.y+=DCTSIZE;
}
}
}
}
if(!(t[i].options&TJXOPT_NOOUTPUT)) jpeg_finish_compress(cinfo);
}
jpeg_finish_decompress(dinfo);

View File

@@ -315,6 +315,13 @@ enum TJXOP
* a grayscale output image.
*/
#define TJXOPT_GRAY 8
/**
* This option will prevent #tjTransform() from outputting a JPEG image for
* this particular transform (this can be used in conjunction with a custom
* filter to capture the transformed DCT coefficients without transcoding
* them.)
*/
#define TJXOPT_NOOUTPUT 16
/**
@@ -376,6 +383,34 @@ typedef struct
* The bitwise OR of one of more of the @ref TJXOPT_CROP "transform options"
*/
int options;
/**
* A callback function that can be used to modify the DCT coefficients
* after they are losslessly transformed but before they are transcoded to a
* new JPEG file. This allows for custom filters or other transformations to
* be applied in the frequency domain.
*
* @param coeffs pointer to an array of DCT coefficients. (NOTE: this
* pointer is not guaranteed to be valid once the callback returns, so
* applications wishing to hand off the DCT coefficients to another
* function or library should make a copy of them within the body of
* the callback.)
* @param arrayRegion region structure containing the width and height of the
* DCT coefficient array as well as its offset relative to the
* component plane. TurboJPEG implementations may choose to split
* each component plane into multiple DCT coefficient arrays and call
* the callback function once for each array.
* @param planeRegion region structure containing the width and height of the
* component plane to which this DCT coefficient array belongs
* @param componentIndex the component plane to which this DCT coefficient
* array belongs (Y, Cb, and Cr are, respectively, 0, 1, and 2 in
* typical JPEG images.)
* @param transformIndex the transformed image to which this DCT coefficient
* array belongs
*
* @return 0 if the callback was successful, or -1 if an error occurred.
*/
int (*customFilter)(short *coeffs, tjregion arrayRegion,
tjregion planeRegion, int componentIndex, int transformIndex);
} tjtransform;
/**