endif
-libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h
+libturbojpeg_la_SOURCES = $(libjpeg_la_SOURCES) turbojpegl.c turbojpeg.h \
+ transupp.c transupp.h
if WITH_JNI
{
for(j=0; j<w; j+=tilesizex)
{
- int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
+ int tempw=dotile? min(tilesizex, w-j):scaledw;
+ int temph=dotile? min(tilesizey, h-i):scaledh;
if(yuv==YUVDECODE)
{
if(tjDecompressToYUV(hnd, jpegbuf[tilen], comptilesize[tilen],
_throwtj("executing tjDecompressToYUV()");
}
else if(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
- &rgbbuf[pitch*i+ps*j], scaledw, pitch, scaledh, ps, flags)==-1)
+ &rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags)==-1)
_throwtj("executing tjDecompress()");
tilen++;
}
void dodecomptest(char *filename)
{
FILE *file=NULL; tjhandle hnd=NULL;
- unsigned char *jpegbuf=NULL;
+ unsigned char **jpegbuf=NULL, *srcbuf=NULL;
+ unsigned long *comptilesize=NULL, srcbufsize, jpgbufsize;
int w=0, h=0, jpegsub=-1;
- unsigned long jpgbufsize=0;
char *temp=NULL;
+ int i, j, tilesizex, tilesizey, numtilesx, numtilesy;
+ double start, elapsed;
+ int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
+ |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0);
+ int ps=_ps[pf], tilen;
useppm=1;
if((file=fopen(filename, "rb"))==NULL)
_throwunix("opening file");
- if(fseek(file, 0, SEEK_END)<0 || (jpgbufsize=ftell(file))<0)
+ if(fseek(file, 0, SEEK_END)<0 || (srcbufsize=ftell(file))<0)
_throwunix("determining file size");
- if((jpegbuf=(unsigned char *)malloc(jpgbufsize))==NULL)
+ if((srcbuf=(unsigned char *)malloc(srcbufsize))==NULL)
_throwunix("allocating memory");
if(fseek(file, 0, SEEK_SET)<0)
_throwunix("setting file position");
- if(fread(jpegbuf, jpgbufsize, 1, file)<1)
+ if(fread(srcbuf, srcbufsize, 1, file)<1)
_throwunix("reading JPEG data");
fclose(file); file=NULL;
temp=strrchr(filename, '.');
if(temp!=NULL) *temp='\0';
- if((hnd=tjInitDecompress())==NULL) _throwtj("executing tjInitDecompress()");
- if(tjDecompressHeader2(hnd, jpegbuf, jpgbufsize, &w, &h, &jpegsub)==-1)
+ if((hnd=tjInitTransform())==NULL) _throwtj("executing tjInitTransform()");
+ if(tjDecompressHeader2(hnd, srcbuf, srcbufsize, &w, &h, &jpegsub)==-1)
_throwtj("executing tjDecompressHeader2()");
- if(tjDestroy(hnd)==-1) _throwtj("executing tjDestroy()");
- hnd=NULL;
- if(quiet==1)
- {
- printf("All performance values in Mpixels/sec\n\n");
- printf("Bitmap\tBitmap\tJPEG\tImage Size\tDecomp\n"),
- printf("Format\tOrder\tFormat\t X Y \tPerf\n\n");
- printf("%s\t%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD",
- _subnamel[jpegsub], w, h);
- }
- else
+ if(yuv) dotile=0;
+
+ if(dotile)
{
- if(yuv==YUVDECODE)
- printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
- else
+ tilesizex=tilesizey=512;
+ if(quiet==1)
+ {
+ printf("All performance values in Mpixels/sec\n\n");
+ printf("Bitmap\tBitmap\tJPEG\tTile Size\tXform\tCompr\tDecomp\n");
+ printf("Format\tOrder\tFormat\t X Y \tPerf \tRatio\tPerf\n\n");
+ }
+ else if(!quiet)
+ {
printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
bu?"Bottom-up":"Top-down");
- printf("\nImage size: %d x %d", w, h);
- if(scalefactor!=1) printf(" --> %d x %d", (w+scalefactor-1)/scalefactor,
- (h+scalefactor-1)/scalefactor);
- printf("\n");
+ }
+ do
+ {
+ tilesizex*=2; if(tilesizex>w) tilesizex=w;
+ tilesizey*=2; if(tilesizey>h) tilesizey=h;
+ numtilesx=(w+tilesizex-1)/tilesizex;
+ numtilesy=(h+tilesizey-1)/tilesizey;
+ if((comptilesize=(unsigned long *)malloc(sizeof(unsigned long)
+ *numtilesx*numtilesy))==NULL
+ || (jpegbuf=(unsigned char **)malloc(sizeof(unsigned char *)
+ *numtilesx*numtilesy))==NULL)
+ _throwunix("allocating image buffers");
+ memset(jpegbuf, 0, sizeof(unsigned char *)*numtilesx*numtilesy);
+
+ for(i=0; i<numtilesx*numtilesy; i++)
+ {
+ if((jpegbuf[i]=(unsigned char *)malloc(
+ TJBUFSIZE(tilesizex, tilesizey))) == NULL)
+ _throwunix("allocating image buffers");
+ }
+
+ if(quiet==1)
+ {
+ printf("%s\t%s\t%s\t", _pfname[pf], bu?"BU":"TD", _subnamel[jpegsub]);
+ if(tilesizex==w && tilesizey==h) printf("Full \t");
+ else printf("%-4d %-4d\t", tilesizex, tilesizey);
+ }
+
+ start=rrtime();
+ jpgbufsize=0; tilen=0;
+ for(i=0; i<h; i+=tilesizey)
+ {
+ for(j=0; j<w; j+=tilesizex)
+ {
+ int tempw=min(tilesizex, w-j), temph=min(tilesizey, h-i);
+ if(tjTransform(hnd, srcbuf, srcbufsize, jpegbuf[tilen],
+ &comptilesize[tilen], j, i, tempw, temph, TJXFORM_NONE,
+ TJXFORM_CROP, flags)
+ ==-1)
+ _throwtj("executing tjTransform()");
+ jpgbufsize+=comptilesize[tilen];
+ tilen++;
+ }
+ }
+ elapsed=rrtime()-start;
+
+ if(quiet)
+ {
+ printsigfig((double)(w*h)/1000000./elapsed, 4);
+ printf("%c", quiet==2? '\n':'\t');
+ printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
+ printf("%c", quiet==2? '\n':'\t');
+ }
+ else if(!quiet)
+ {
+ if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
+ else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
+ printf("X--> Frame rate: %f fps\n", 1.0/elapsed);
+ printf(" Output image size: %lu bytes\n", jpgbufsize);
+ printf(" Compression ratio: %f:1\n",
+ (double)(w*h*ps)/(double)jpgbufsize);
+ printf(" Source throughput: %f Megapixels/sec\n",
+ (double)(w*h)/1000000./elapsed);
+ printf(" Output bit stream: %f Megabits/sec\n",
+ (double)jpgbufsize*8./1000000./elapsed);
+ }
+
+ if(decomptest(NULL, jpegbuf, comptilesize, NULL, w, h, jpegsub, 0,
+ filename, tilesizex, tilesizey)==-1)
+ goto bailout;
+
+ // Cleanup
+ for(i=0; i<numtilesx*numtilesy; i++)
+ {free(jpegbuf[i]); jpegbuf[i]=NULL;}
+ free(jpegbuf); jpegbuf=NULL;
+ if(comptilesize) {free(comptilesize); comptilesize=NULL;}
+ } while(tilesizex<w || tilesizey<h);
}
+ else
+ {
+ if(quiet==1)
+ {
+ printf("All performance values in Mpixels/sec\n\n");
+ printf("Bitmap\tBitmap\tJPEG\tImage Size\tDecomp\n");
+ printf("Format\tOrder\tFormat\t X Y \tPerf\n\n");
+ printf("%s\t%s\t%s\t%-4d %-4d\t", _pfname[pf], bu?"BU":"TD",
+ _subnamel[jpegsub], w, h);
+ }
+ else if(!quiet)
+ {
+ if(yuv==YUVDECODE)
+ printf(">>>>> JPEG --> YUV %s <<<<<\n", _subnamel[jpegsub]);
+ else
+ printf(">>>>> JPEG --> %s (%s) <<<<<\n", _pfname[pf],
+ bu?"Bottom-up":"Top-down");
+ printf("\nImage size: %d x %d", w, h);
+ if(scalefactor!=1) printf(" --> %d x %d", (w+scalefactor-1)/scalefactor,
+ (h+scalefactor-1)/scalefactor);
+ printf("\n");
+ }
- decomptest(NULL, &jpegbuf, &jpgbufsize, NULL, w, h, jpegsub, 0, filename, w,
- h);
+ decomptest(NULL, &srcbuf, &srcbufsize, NULL, w, h, jpegsub, 0, filename,
+ w, h);
+ }
bailout:
if(file) {fclose(file); file=NULL;}
- if(jpegbuf) {free(jpegbuf); jpegbuf=NULL;}
+ if(jpegbuf)
+ {
+ for(i=0; i<numtilesx*numtilesy; i++)
+ {if(jpegbuf[i]) free(jpegbuf[i]); jpegbuf[i]=NULL;}
+ free(jpegbuf); jpegbuf=NULL;
+ }
+ if(comptilesize) {free(comptilesize); comptilesize=NULL;}
+ if(srcbuf) {free(srcbuf); srcbuf=NULL;}
if(hnd) {tjDestroy(hnd); hnd=NULL;}
return;
}
{
global:
tjGetScaledSize;
+ tjInitTransform;
+ tjTransform;
} TURBOJPEG_1.1;
{
global:
tjGetScaledSize;
+ tjInitTransform;
+ tjTransform;
Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV;
Java_org_libjpegturbo_turbojpeg_TJCompressor_init;
#define TJ_YUV 512
/* Nothing to see here. Pay no attention to the man behind the curtain. */
+/* Transform operations for tjTransform() */
+#define NUMXFORMOPT 8
+
+enum {
+TJXFORM_NONE=0, /* Do not transform the position of the image pixels */
+TJXFORM_HFLIP, /* Flip (mirror) image horizontally. This transform is
+ imperfect if there are any partial MCU blocks on the
+ right edge (see below for explanation.) */
+TJXFORM_VFLIP, /* Flip (mirror) image vertically. This transform is
+ imperfect if there are any partial MCU blocks on the
+ bottom edge. */
+TJXFORM_TRANSPOSE, /* Transpose image (flip/mirror along upper left to lower
+ right axis.) This transform is always perfect. */
+TJXFORM_TRANSVERSE, /* Transpose image (flip/mirror along upper right to lower
+ left axis.) This transform is imperfect if there are
+ any partial MCU blocks in the image. */
+TJXFORM_ROT90, /* Rotate image clockwise by 90 degrees. This transform
+ is imperfect if there are any partial MCU blocks on the
+ bottom edge. */
+TJXFORM_ROT180, /* Rotate image 180 degrees. This transform is imperfect
+ if there are any partial MCU blocks in the image. */
+TJXFORM_ROT270 /* Rotate image counter-clockwise by 90 degrees. This
+ transform is imperfect if there are any partial MCU
+ blocks on the right edge. */
+};
+
+/* Transform options (these can be OR'ed together) */
+#define TJXFORM_PERFECT 1
+ /* This will cause the tjTransform() function to return an error if the
+ transform is not perfect. Lossless transforms operate on MCU blocks,
+ which are 8x8 pixels if no chrominance subsampling is used, or 16x8 for
+ 4:2:2 or 16x16 for 4:2:0. If the image's width or height is not evenly
+ divisible by the MCU size, then there will be partial MCU blocks on the
+ right and/or bottom edges. It is not possible to move these partial MCU
+ blocks to the top or left of the image, so any transform that would
+ require that is "imperfect." If this option is not specified, then any
+ partial MCU blocks that cannot be transformed will be left in place, which
+ will create odd-looking strips on the right or bottom edge of the image.
+ */
+#define TJXFORM_TRIM 2
+ /* This option will cause tjTransform() to discard any partial MCU blocks
+ that cannot be transformed. */
+#define TJXFORM_CROP 4
+ /* This option will enable lossless cropping. See the description of
+ tjTransform() below for more information. */
+#define TJXFORM_GRAY 8
+ /* This option will discard the color data in the input image and produce
+ a grayscale output image. */
+
typedef void* tjhandle;
#define TJPAD(p) (((p)+3)&(~3))
int jpegsubsamp, int jpegqual, int flags)
[INPUT] j = instance handle previously returned from a call to
- tjInitCompress()
+ tjInitCompress() or tjInitTransform()
[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
(AKA "YUV420P") format.
[INPUT] j = instance handle previously returned from a call to
- tjInitCompress()
+ tjInitCompress() or tjInitTransform()
[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
int *width, int *height, int *jpegsubsamp)
[INPUT] j = instance handle previously returned from a call to
- tjInitDecompress()
+ tjInitDecompress() or tjInitTransform()
[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
int flags)
[INPUT] j = instance handle previously returned from a call to
- tjInitDecompress()
+ tjInitDecompress() or tjInitTransform()
[INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
to decompress
[INPUT] size = size of the JPEG image buffer (in bytes)
used), then an intermediate buffer copy will be performed within TurboJPEG.
[INPUT] j = instance handle previously returned from a call to
- tjInitDecompress()
+ tjInitDecompress() or tjInitTransform()
[INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
to decompress
[INPUT] size = size of the JPEG image buffer (in bytes)
unsigned char *dstbuf, int flags);
+/*
+ tjhandle tjInitTransform(void)
+
+ Creates a new JPEG transformer instance, allocates memory for the 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 transform an
+ image, because this may cause performance to suffer in some TurboJPEG
+ implementations.
+
+ RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitTransform(void);
+
+
+/*
+ int tjTransform(tjhandle j,
+ 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)
+
+ [INPUT] j = instance handle previously returned from a call to
+ tjInitTransform()
+ [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+ to transform
+ [INPUT] srcsize = size of the source JPEG image buffer (in bytes)
+ [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+ the transformed JPEG image. Use the TJBUFSIZE(width, height) function to
+ determine the appropriate size for this buffer based on the cropped width
+ and height.
+ [OUTPUT] dstsize = pointer to unsigned long which receives the size (in
+ bytes) of the transformed image
+ [INPUT] x, y, w, h = the left edge, top edge, width, and height of the
+ cropping region. If (x, y) does not fall on an MCU boundary, then x and
+ y will be silently moved left and/or up to the nearest MCU boundary. You
+ can call tjGetCroppedSize() to determine how (or if) x, y, w, and h will
+ be modified ahead of time, so you can allocate the output buffer
+ appropriately.
+ [INPUT] op = one of the transform operations described in the "Transform
+ operations" section above.
+ [INPUT] options = the bitwise OR of one or more of the transform options
+ described in the "Transform options" section above.
+ [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 tjTransform(tjhandle j,
+ unsigned char *srcbuf, unsigned long size,
+ unsigned char *dstbuf, unsigned long *dstsize,
+ int x, int y, int w, int h, int op, int options, int flags);
+
+
/*
int tjDestroy(tjhandle h)
Frees structures associated with a compression or decompression instance
[INPUT] h = instance handle (returned from a previous call to
- tjInitCompress() or tjInitDecompress()
+ tjInitCompress(), tjInitDecompress(), or tjInitTransform()
RETURNS: 0 on success, -1 on error
*/
#include <jerror.h>
#include <setjmp.h>
#include "./turbojpeg.h"
+#include "transupp.h"
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
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; \
{
}
-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;
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)
{
{
}
-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;
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,
}
+// 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)