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:
@@ -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
167
jpgtest.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ TURBOJPEG_1.2
|
||||
{
|
||||
global:
|
||||
tjGetScaledSize;
|
||||
tjInitTransform;
|
||||
tjTransform;
|
||||
} TURBOJPEG_1.1;
|
||||
|
||||
@@ -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;
|
||||
|
||||
114
turbojpeg.h
114
turbojpeg.h
@@ -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
|
||||
*/
|
||||
|
||||
149
turbojpegl.c
149
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 @@ 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)
|
||||
|
||||
Reference in New Issue
Block a user