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
This commit is contained in:
DRC
2011-02-26 22:02:37 +00:00
parent 17ac3720f1
commit 890f1e0413
6 changed files with 390 additions and 47 deletions

View File

@@ -34,7 +34,8 @@ libjpeg_la_SOURCES += jdarith.c
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

167
jpgtest.c
View File

@@ -119,7 +119,8 @@ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
{
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],
@@ -127,7 +128,7 @@ int decomptest(unsigned char *srcbuf, unsigned char **jpegbuf,
_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++;
}
@@ -390,61 +391,167 @@ void dotest(unsigned char *srcbuf, int w, int h, int jpegsub, int qual,
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)
if(yuv) dotile=0;
if(dotile)
{
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);
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");
}
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(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");
}
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;
}

View File

@@ -26,4 +26,6 @@ TURBOJPEG_1.2
{
global:
tjGetScaledSize;
tjInitTransform;
tjTransform;
} TURBOJPEG_1.1;

View File

@@ -26,6 +26,8 @@ TURBOJPEG_1.2
{
global:
tjGetScaledSize;
tjInitTransform;
tjTransform;
Java_org_libjpegturbo_turbojpeg_TJ_bufSize;
Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV;
Java_org_libjpegturbo_turbojpeg_TJCompressor_init;

View File

@@ -56,6 +56,55 @@ enum {TJ_444=0, TJ_422, TJ_420, TJ_GRAYSCALE};
#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))
@@ -92,7 +141,7 @@ DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
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
@@ -177,7 +226,7 @@ DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height,
(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
@@ -227,7 +276,7 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
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
@@ -276,7 +325,7 @@ DLLEXPORT int DLLCALL tjGetScaledSize(int input_width, int input_height,
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)
@@ -332,7 +381,7 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle j,
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)
@@ -350,13 +399,66 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle j,
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
*/

View File

@@ -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 @@ typedef struct _jpgstruct
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 @@ static void destination_noop(struct jpeg_compress_struct *cinfo)
{
}
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 @@ DLLEXPORT tjhandle DLLCALL tjInitCompress(void)
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 @@ static void source_noop (struct jpeg_decompress_struct *dinfo)
{
}
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 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void)
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 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle h,
}
// 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)