Expose libjpeg lossless transform feature in TurboJPEG/OSS
git-svn-id: svn+ssh://svn.code.sf.net/p/libjpeg-turbo/code/trunk@464 632fc199-4ca6-4c93-a231-07263d6284db
diff --git a/turbojpegl.c b/turbojpegl.c
index 010a072..4755144 100644
--- a/turbojpegl.c
+++ b/turbojpegl.c
@@ -23,6 +23,7 @@
#include <jerror.h>
#include <setjmp.h>
#include "./turbojpeg.h"
+#include "transupp.h"
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
@@ -69,6 +70,10 @@
static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
static const int pixelsize[NUMSUBOPT]={3, 3, 3, 1};
+static const JXFORM_CODE xformtypes[NUMXFORMOPT]={
+ JXFORM_NONE, JXFORM_FLIP_H, JXFORM_FLIP_V, JXFORM_TRANSPOSE,
+ JXFORM_TRANSVERSE, JXFORM_ROT_90, JXFORM_ROT_180, JXFORM_ROT_270
+};
#define _throw(c) {sprintf(lasterror, "%s", c); retval=-1; goto bailout;}
#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
@@ -87,12 +92,8 @@
{
}
-DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
+static tjhandle _tjInitCompress(jpgstruct *j)
{
- jpgstruct *j=NULL;
- if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
- {sprintf(lasterror, "Memory allocation failure"); return NULL;}
- memset(j, 0, sizeof(jpgstruct));
j->cinfo.err=jpeg_std_error(&j->jerr.pub);
j->jerr.pub.error_exit=my_error_exit;
j->jerr.pub.output_message=my_output_message;
@@ -112,6 +113,15 @@
return (tjhandle)j;
}
+DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
+{
+ jpgstruct *j=NULL;
+ if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+ {sprintf(lasterror, "Memory allocation failure"); return NULL;}
+ memset(j, 0, sizeof(jpgstruct));
+ return _tjInitCompress(j);
+}
+
DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
{
@@ -364,12 +374,8 @@
{
}
-DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
+static tjhandle _tjInitDecompress(jpgstruct *j)
{
- jpgstruct *j;
- if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
- {sprintf(lasterror, "Memory allocation failure"); return NULL;}
- memset(j, 0, sizeof(jpgstruct));
j->dinfo.err=jpeg_std_error(&j->jerr.pub);
j->jerr.pub.error_exit=my_error_exit;
j->jerr.pub.output_message=my_output_message;
@@ -391,6 +397,15 @@
return (tjhandle)j;
}
+DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
+{
+ jpgstruct *j;
+ if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+ {sprintf(lasterror, "Memory allocation failure"); return NULL;}
+ memset(j, 0, sizeof(jpgstruct));
+ return _tjInitDecompress(j);
+}
+
DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle h,
unsigned char *srcbuf, unsigned long size,
@@ -682,6 +697,120 @@
}
+// Transformation
+
+DLLEXPORT tjhandle DLLCALL tjInitTransform(void)
+{
+ jpgstruct *j=NULL; tjhandle tj=NULL;
+ if((j=(jpgstruct *)malloc(sizeof(jpgstruct)))==NULL)
+ {sprintf(lasterror, "Memory allocation failure"); return NULL;}
+ memset(j, 0, sizeof(jpgstruct));
+ tj=_tjInitCompress(j);
+ if(!tj) return NULL;
+ tj=_tjInitDecompress(j);
+ return tj;
+}
+
+
+DLLEXPORT int DLLCALL tjTransform(tjhandle hnd,
+ unsigned char *srcbuf, unsigned long srcsize,
+ unsigned char *dstbuf, unsigned long *dstsize,
+ int x, int y, int w, int h, int op, int options, int flags)
+{
+ jpeg_transform_info xinfo;
+ jvirt_barray_ptr *srccoefs, *dstcoefs;
+ int retval=0;
+
+ checkhandle(hnd);
+
+ if(srcbuf==NULL || srcsize<=0 || dstbuf==NULL || dstsize==NULL
+ || x<0 || y<0 || w<0 || h<0 || op<0 || op>=NUMXFORMOPT
+ || flags<0)
+ _throw("Invalid argument in tjTransform()");
+ if(!j->initc || !j->initd)
+ _throw("Instance has not been initialized for transformation");
+
+ if(flags&TJ_FORCEMMX) putenv("JSIMD_FORCEMMX=1");
+ else if(flags&TJ_FORCESSE) putenv("JSIMD_FORCESSE=1");
+ else if(flags&TJ_FORCESSE2) putenv("JSIMD_FORCESSE2=1");
+
+ if(setjmp(j->jerr.jb))
+ { // this will execute if LIBJPEG has an error
+ retval=-1;
+ goto bailout;
+ }
+
+ j->jsms.bytes_in_buffer=srcsize;
+ j->jsms.next_input_byte=srcbuf;
+
+ xinfo.transform=xformtypes[op];
+ xinfo.perfect=(options&TJXFORM_PERFECT)? 1:0;
+ xinfo.trim=(options&TJXFORM_TRIM)? 1:0;
+ xinfo.force_grayscale=(options&TJXFORM_GRAY)? 1:0;
+ xinfo.crop=(options&TJXFORM_CROP)? 1:0;
+
+ if(xinfo.crop)
+ {
+ xinfo.crop_xoffset=x; xinfo.crop_xoffset_set=JCROP_POS;
+ xinfo.crop_yoffset=y; xinfo.crop_yoffset_set=JCROP_POS;
+ if(w!=0)
+ {
+ xinfo.crop_width=w; xinfo.crop_width_set=JCROP_POS;
+ }
+ if(h!=0)
+ {
+ xinfo.crop_height=h; xinfo.crop_height_set=JCROP_POS;
+ }
+ }
+
+ jcopy_markers_setup(&j->dinfo, JCOPYOPT_NONE);
+ jpeg_read_header(&j->dinfo, TRUE);
+
+ if(!jtransform_request_workspace(&j->dinfo, &xinfo))
+ _throw("Transform is not perfect");
+
+ if(!xinfo.crop)
+ {
+ w=j->dinfo.image_width; h=j->dinfo.image_height;
+ }
+ else
+ {
+ w=xinfo.crop_width; h=xinfo.crop_height;
+ }
+
+ j->jdms.next_output_byte=dstbuf;
+ j->jdms.free_in_buffer=TJBUFSIZE(w, h);
+
+ if(xinfo.crop)
+ {
+ if((x%xinfo.iMCU_sample_width)!=0 || (y%xinfo.iMCU_sample_height)!=0)
+ {
+ sprintf(lasterror, "To crop this JPEG image, x must be a multiple of %d and y must be a multiple\n"
+ "of %d.\n", xinfo.iMCU_sample_width, xinfo.iMCU_sample_height);
+ retval=-1; goto bailout;
+ }
+ }
+
+ srccoefs=jpeg_read_coefficients(&j->dinfo);
+ jpeg_copy_critical_parameters(&j->dinfo, &j->cinfo);
+ dstcoefs=jtransform_adjust_parameters(&j->dinfo, &j->cinfo, srccoefs,
+ &xinfo);
+ jpeg_write_coefficients(&j->cinfo, dstcoefs);
+ jcopy_markers_execute(&j->dinfo, &j->cinfo, JCOPYOPT_ALL);
+ jtransform_execute_transformation(&j->dinfo, &j->cinfo, srccoefs, &xinfo);
+
+ jpeg_finish_compress(&j->cinfo);
+ jpeg_finish_decompress(&j->dinfo);
+
+ *dstsize=TJBUFSIZE(w, h)-(unsigned long)(j->jdms.free_in_buffer);
+
+ bailout:
+ if(j->cinfo.global_state>CSTATE_START) jpeg_abort_compress(&j->cinfo);
+ if(j->dinfo.global_state>DSTATE_START) jpeg_abort_decompress(&j->dinfo);
+ return retval;
+}
+
+
// General
DLLEXPORT char* DLLCALL tjGetErrorStr(void)