Index: turbojpeg.c |
diff --git a/turbojpeg.c b/turbojpeg.c |
index 9117273df304e6b1d66b2352aa9e097a9cb2aa59..f51df789aec1c8c5378defacce9568b03014b70d 100644 |
--- a/turbojpeg.c |
+++ b/turbojpeg.c |
@@ -1,5 +1,5 @@ |
/* |
- * Copyright (C)2009-2012, 2014 D. R. Commander. All Rights Reserved. |
+ * Copyright (C)2009-2016 D. R. Commander. All Rights Reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions are met: |
@@ -31,6 +31,7 @@ |
#include <stdio.h> |
#include <stdlib.h> |
+#include <ctype.h> |
#include <jinclude.h> |
#define JPEG_INTERNALS |
#include <jpeglib.h> |
@@ -39,12 +40,15 @@ |
#include "./turbojpeg.h" |
#include "./tjutil.h" |
#include "transupp.h" |
+#include "./jpegcomp.h" |
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, |
unsigned long *, boolean); |
-extern void jpeg_mem_src_tj(j_decompress_ptr, unsigned char *, unsigned long); |
+extern void jpeg_mem_src_tj(j_decompress_ptr, const unsigned char *, |
+ unsigned long); |
#define PAD(v, p) ((v+(p)-1)&(~((p)-1))) |
+#define isPow2(x) (((x)&(x-1))==0) |
/* Error handling (based on example in example.c) */ |
@@ -55,6 +59,8 @@ struct my_error_mgr |
{ |
struct jpeg_error_mgr pub; |
jmp_buf setjmp_buffer; |
+ void (*emit_message)(j_common_ptr, int); |
+ boolean warning; |
}; |
typedef struct my_error_mgr *my_error_ptr; |
@@ -72,6 +78,13 @@ static void my_output_message(j_common_ptr cinfo) |
(*cinfo->err->format_message)(cinfo, errStr); |
} |
+static void my_emit_message(j_common_ptr cinfo, int msg_level) |
+{ |
+ my_error_ptr myerr=(my_error_ptr)cinfo->err; |
+ myerr->emit_message(cinfo, msg_level); |
+ if(msg_level<0) myerr->warning=TRUE; |
+} |
+ |
/* Global structures, macros, etc. */ |
@@ -82,10 +95,10 @@ typedef struct _tjinstance |
struct jpeg_compress_struct cinfo; |
struct jpeg_decompress_struct dinfo; |
struct my_error_mgr jerr; |
- int init; |
+ int init, headerRead; |
} tjinstance; |
-static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3}; |
+static const int pixelsize[TJ_NUMSAMP]={3, 3, 3, 1, 3, 3}; |
static const JXFORM_CODE xformtypes[TJ_NUMXOP]= |
{ |
@@ -119,7 +132,20 @@ static const tjscalingfactor sf[NUMSF]={ |
j_compress_ptr cinfo=NULL; j_decompress_ptr dinfo=NULL; \ |
if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ |
return -1;} \ |
- cinfo=&this->cinfo; dinfo=&this->dinfo; |
+ cinfo=&this->cinfo; dinfo=&this->dinfo; \ |
+ this->jerr.warning=FALSE; |
+#define getcinstance(handle) tjinstance *this=(tjinstance *)handle; \ |
+ j_compress_ptr cinfo=NULL; \ |
+ if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ |
+ return -1;} \ |
+ cinfo=&this->cinfo; \ |
+ this->jerr.warning=FALSE; |
+#define getdinstance(handle) tjinstance *this=(tjinstance *)handle; \ |
+ j_decompress_ptr dinfo=NULL; \ |
+ if(!this) {snprintf(errStr, JMSG_LENGTH_MAX, "Invalid handle"); \ |
+ return -1;} \ |
+ dinfo=&this->dinfo; \ |
+ this->jerr.warning=FALSE; |
static int getPixelFormat(int pixelSize, int flags) |
{ |
@@ -149,6 +175,7 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo, |
int pixelFormat, int subsamp, int jpegQual, int flags) |
{ |
int retval=0; |
+ char *env=NULL; |
switch(pixelFormat) |
{ |
@@ -185,10 +212,34 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo, |
cinfo->in_color_space=JCS_RGB; pixelFormat=TJPF_RGB; |
break; |
#endif |
+ case TJPF_CMYK: |
+ cinfo->in_color_space=JCS_CMYK; break; |
} |
cinfo->input_components=tjPixelSize[pixelFormat]; |
jpeg_set_defaults(cinfo); |
+ |
+#ifndef NO_GETENV |
+ if((env=getenv("TJ_OPTIMIZE"))!=NULL && strlen(env)>0 && !strcmp(env, "1")) |
+ cinfo->optimize_coding=TRUE; |
+ if((env=getenv("TJ_ARITHMETIC"))!=NULL && strlen(env)>0 && !strcmp(env, "1")) |
+ cinfo->arith_code=TRUE; |
+ if((env=getenv("TJ_RESTART"))!=NULL && strlen(env)>0) |
+ { |
+ int temp=-1; char tempc=0; |
+ if(sscanf(env, "%d%c", &temp, &tempc)>=1 && temp>=0 && temp<=65535) |
+ { |
+ if(toupper(tempc)=='B') |
+ { |
+ cinfo->restart_interval=temp; |
+ cinfo->restart_in_rows=0; |
+ } |
+ else |
+ cinfo->restart_in_rows=temp; |
+ } |
+ } |
+#endif |
+ |
if(jpegQual>=0) |
{ |
jpeg_set_quality(cinfo, jpegQual, TRUE); |
@@ -197,15 +248,26 @@ static int setCompDefaults(struct jpeg_compress_struct *cinfo, |
} |
if(subsamp==TJSAMP_GRAY) |
jpeg_set_colorspace(cinfo, JCS_GRAYSCALE); |
- else |
- jpeg_set_colorspace(cinfo, JCS_YCbCr); |
+ else if(pixelFormat==TJPF_CMYK) |
+ jpeg_set_colorspace(cinfo, JCS_YCCK); |
+ else jpeg_set_colorspace(cinfo, JCS_YCbCr); |
+ |
+#ifndef NO_GETENV |
+ if((env=getenv("TJ_PROGRESSIVE"))!=NULL && strlen(env)>0 |
+ && !strcmp(env, "1")) |
+ jpeg_simple_progression(cinfo); |
+#endif |
cinfo->comp_info[0].h_samp_factor=tjMCUWidth[subsamp]/8; |
cinfo->comp_info[1].h_samp_factor=1; |
cinfo->comp_info[2].h_samp_factor=1; |
+ if(cinfo->num_components>3) |
+ cinfo->comp_info[3].h_samp_factor=tjMCUWidth[subsamp]/8; |
cinfo->comp_info[0].v_samp_factor=tjMCUHeight[subsamp]/8; |
cinfo->comp_info[1].v_samp_factor=1; |
cinfo->comp_info[2].v_samp_factor=1; |
+ if(cinfo->num_components>3) |
+ cinfo->comp_info[3].v_samp_factor=tjMCUHeight[subsamp]/8; |
return retval; |
} |
@@ -255,6 +317,8 @@ static int setDecompDefaults(struct jpeg_decompress_struct *dinfo, |
case TJPF_ABGR: |
dinfo->out_color_space=JCS_RGB; break; |
#endif |
+ case TJPF_CMYK: |
+ dinfo->out_color_space=JCS_CMYK; break; |
default: |
_throw("Unsupported pixel format"); |
} |
@@ -269,9 +333,20 @@ static int setDecompDefaults(struct jpeg_decompress_struct *dinfo, |
static int getSubsamp(j_decompress_ptr dinfo) |
{ |
int retval=-1, i, k; |
+ |
+ /* The sampling factors actually have no meaning with grayscale JPEG files, |
+ and in fact it's possible to generate grayscale JPEGs with sampling |
+ factors > 1 (even though those sampling factors are ignored by the |
+ decompressor.) Thus, we need to treat grayscale as a special case. */ |
+ if(dinfo->num_components==1 && dinfo->jpeg_color_space==JCS_GRAYSCALE) |
+ return TJSAMP_GRAY; |
+ |
for(i=0; i<NUMSUBOPT; i++) |
{ |
- if(dinfo->num_components==pixelsize[i]) |
+ if(dinfo->num_components==pixelsize[i] |
+ || ((dinfo->jpeg_color_space==JCS_YCCK |
+ || dinfo->jpeg_color_space==JCS_CMYK) |
+ && pixelsize[i]==3 && dinfo->num_components==4)) |
{ |
if(dinfo->comp_info[0].h_samp_factor==tjMCUWidth[i]/8 |
&& dinfo->comp_info[0].v_samp_factor==tjMCUHeight[i]/8) |
@@ -279,8 +354,13 @@ static int getSubsamp(j_decompress_ptr dinfo) |
int match=0; |
for(k=1; k<dinfo->num_components; k++) |
{ |
- if(dinfo->comp_info[k].h_samp_factor==1 |
- && dinfo->comp_info[k].v_samp_factor==1) |
+ int href=1, vref=1; |
+ if(dinfo->jpeg_color_space==JCS_YCCK && k==3) |
+ { |
+ href=tjMCUWidth[i]/8; vref=tjMCUHeight[i]/8; |
+ } |
+ if(dinfo->comp_info[k].h_samp_factor==href |
+ && dinfo->comp_info[k].v_samp_factor==vref) |
match++; |
} |
if(match==dinfo->num_components-1) |
@@ -477,12 +557,15 @@ DLLEXPORT unsigned char *DLLCALL tjAlloc(int bytes) |
static tjhandle _tjInitCompress(tjinstance *this) |
{ |
- unsigned char buffer[1], *buf=buffer; unsigned long size=1; |
+ static unsigned char buffer[1]; |
+ unsigned char *buf=buffer; unsigned long size=1; |
/* This is also straight out of example.c */ |
this->cinfo.err=jpeg_std_error(&this->jerr.pub); |
this->jerr.pub.error_exit=my_error_exit; |
this->jerr.pub.output_message=my_output_message; |
+ this->jerr.emit_message=this->jerr.pub.emit_message; |
+ this->jerr.pub.emit_message=my_emit_message; |
if(setjmp(this->jerr.setjmp_buffer)) |
{ |
@@ -547,22 +630,33 @@ DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height) |
} |
-DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height, |
+DLLEXPORT unsigned long DLLCALL tjBufSizeYUV2(int width, int pad, int height, |
int subsamp) |
{ |
- unsigned long retval=0; |
- int pw, ph, cw, ch; |
- if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT) |
- _throw("tjBufSizeYUV(): Invalid argument"); |
- pw=PAD(width, tjMCUWidth[subsamp]/8); |
- ph=PAD(height, tjMCUHeight[subsamp]/8); |
- cw=pw*8/tjMCUWidth[subsamp]; ch=ph*8/tjMCUHeight[subsamp]; |
- retval=PAD(pw, 4)*ph + (subsamp==TJSAMP_GRAY? 0:PAD(cw, 4)*ch*2); |
+ int retval=0, nc, i; |
+ |
+ if(subsamp<0 || subsamp>=NUMSUBOPT) |
+ _throw("tjBufSizeYUV2(): Invalid argument"); |
+ |
+ nc=(subsamp==TJSAMP_GRAY? 1:3); |
+ for(i=0; i<nc; i++) |
+ { |
+ int pw=tjPlaneWidth(i, width, subsamp); |
+ int stride=PAD(pw, pad); |
+ int ph=tjPlaneHeight(i, height, subsamp); |
+ if(pw<0 || ph<0) return -1; |
+ else retval+=stride*ph; |
+ } |
bailout: |
return retval; |
} |
+DLLEXPORT unsigned long DLLCALL tjBufSizeYUV(int width, int height, |
+ int subsamp) |
+{ |
+ return tjBufSizeYUV2(width, 4, height, subsamp); |
+} |
DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height, |
int subsamp) |
@@ -571,7 +665,72 @@ DLLEXPORT unsigned long DLLCALL TJBUFSIZEYUV(int width, int height, |
} |
-DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, |
+DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp) |
+{ |
+ int pw, nc, retval=0; |
+ |
+ if(width<1 || subsamp<0 || subsamp>=TJ_NUMSAMP) |
+ _throw("tjPlaneWidth(): Invalid argument"); |
+ nc=(subsamp==TJSAMP_GRAY? 1:3); |
+ if(componentID<0 || componentID>=nc) |
+ _throw("tjPlaneWidth(): Invalid argument"); |
+ |
+ pw=PAD(width, tjMCUWidth[subsamp]/8); |
+ if(componentID==0) |
+ retval=pw; |
+ else |
+ retval=pw*8/tjMCUWidth[subsamp]; |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+ |
+DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp) |
+{ |
+ int ph, nc, retval=0; |
+ |
+ if(height<1 || subsamp<0 || subsamp>=TJ_NUMSAMP) |
+ _throw("tjPlaneHeight(): Invalid argument"); |
+ nc=(subsamp==TJSAMP_GRAY? 1:3); |
+ if(componentID<0 || componentID>=nc) |
+ _throw("tjPlaneHeight(): Invalid argument"); |
+ |
+ ph=PAD(height, tjMCUHeight[subsamp]/8); |
+ if(componentID==0) |
+ retval=ph; |
+ else |
+ retval=ph*8/tjMCUHeight[subsamp]; |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+ |
+DLLEXPORT unsigned long DLLCALL tjPlaneSizeYUV(int componentID, int width, |
+ int stride, int height, int subsamp) |
+{ |
+ unsigned long retval=0; |
+ int pw, ph; |
+ |
+ if(width<1 || height<1 || subsamp<0 || subsamp>=NUMSUBOPT) |
+ _throw("tjPlaneSizeYUV(): Invalid argument"); |
+ |
+ pw=tjPlaneWidth(componentID, width, subsamp); |
+ ph=tjPlaneHeight(componentID, height, subsamp); |
+ if(pw<0 || ph<0) return -1; |
+ |
+ if(stride==0) stride=pw; |
+ else stride=abs(stride); |
+ |
+ retval=stride*(ph-1)+pw; |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+ |
+DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, const unsigned char *srcBuf, |
int width, int pitch, int height, int pixelFormat, unsigned char **jpegBuf, |
unsigned long *jpegSize, int jpegSubsamp, int jpegQual, int flags) |
{ |
@@ -580,7 +739,7 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, |
unsigned char *rgbBuf=NULL; |
#endif |
- getinstance(handle) |
+ getcinstance(handle) |
if((this->init&COMPRESS)==0) |
_throw("tjCompress2(): Instance has not been initialized for compression"); |
@@ -599,7 +758,7 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, |
if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; |
#ifndef JCS_EXTENSIONS |
- if(pixelFormat!=TJPF_GRAY) |
+ if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK) |
{ |
rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE); |
if(!rgbBuf) _throw("tjCompress2(): Memory allocation failure"); |
@@ -628,8 +787,9 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, |
_throw("tjCompress2(): Memory allocation failure"); |
for(i=0; i<height; i++) |
{ |
- if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; |
- else row_pointer[i]=&srcBuf[i*pitch]; |
+ if(flags&TJFLAG_BOTTOMUP) |
+ row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch]; |
+ else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch]; |
} |
while(cinfo->next_scanline<cinfo->image_height) |
{ |
@@ -644,6 +804,7 @@ DLLEXPORT int DLLCALL tjCompress2(tjhandle handle, unsigned char *srcBuf, |
if(rgbBuf) free(rgbBuf); |
#endif |
if(row_pointer) free(row_pointer); |
+ if(this->jerr.warning) retval=-1; |
return retval; |
} |
@@ -669,23 +830,23 @@ DLLEXPORT int DLLCALL tjCompress(tjhandle handle, unsigned char *srcBuf, |
} |
-DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
- int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, |
- int subsamp, int flags) |
+DLLEXPORT int DLLCALL tjEncodeYUVPlanes(tjhandle handle, |
+ const unsigned char *srcBuf, int width, int pitch, int height, |
+ int pixelFormat, unsigned char **dstPlanes, int *strides, int subsamp, |
+ int flags) |
{ |
int i, retval=0; JSAMPROW *row_pointer=NULL; |
JSAMPLE *_tmpbuf[MAX_COMPONENTS], *_tmpbuf2[MAX_COMPONENTS]; |
JSAMPROW *tmpbuf[MAX_COMPONENTS], *tmpbuf2[MAX_COMPONENTS]; |
JSAMPROW *outbuf[MAX_COMPONENTS]; |
- int row, pw, ph, cw[MAX_COMPONENTS], ch[MAX_COMPONENTS]; |
- JSAMPLE *ptr=dstBuf; |
- unsigned long yuvsize=0; |
+ int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS]; |
+ JSAMPLE *ptr; |
jpeg_component_info *compptr; |
#ifndef JCS_EXTENSIONS |
unsigned char *rgbBuf=NULL; |
#endif |
- getinstance(handle); |
+ getcinstance(handle); |
for(i=0; i<MAX_COMPONENTS; i++) |
{ |
@@ -694,12 +855,14 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
} |
if((this->init&COMPRESS)==0) |
- _throw("tjEncodeYUV2(): Instance has not been initialized for compression"); |
+ _throw("tjEncodeYUVPlanes(): Instance has not been initialized for compression"); |
if(srcBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 |
- || pixelFormat>=TJ_NUMPF || dstBuf==NULL || subsamp<0 |
+ || pixelFormat>=TJ_NUMPF || !dstPlanes || !dstPlanes[0] || subsamp<0 |
|| subsamp>=NUMSUBOPT) |
- _throw("tjEncodeYUV2(): Invalid argument"); |
+ _throw("tjEncodeYUVPlanes(): Invalid argument"); |
+ if(subsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2])) |
+ _throw("tjEncodeYUVPlanes(): Invalid argument"); |
if(setjmp(this->jerr.setjmp_buffer)) |
{ |
@@ -708,13 +871,16 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
goto bailout; |
} |
+ if(pixelFormat==TJPF_CMYK) |
+ _throw("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels"); |
+ |
if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; |
#ifndef JCS_EXTENSIONS |
- if(pixelFormat!=TJPF_GRAY) |
+ if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK) |
{ |
rgbBuf=(unsigned char *)malloc(width*height*RGB_PIXELSIZE); |
- if(!rgbBuf) _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if(!rgbBuf) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
srcBuf=toRGB(srcBuf, width, pitch, height, pixelFormat, rgbBuf); |
pitch=width*RGB_PIXELSIZE; |
} |
@@ -727,7 +893,6 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
- yuvsize=tjBufSizeYUV(width, height, subsamp); |
if(setCompDefaults(cinfo, pixelFormat, subsamp, -1, flags)==-1) return -1; |
/* Execute only the parts of jpeg_start_compress() that we need. If we |
@@ -735,25 +900,26 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
to write the file headers, which could overflow the output buffer if the |
YUV image were very small. */ |
if(cinfo->global_state!=CSTATE_START) |
- _throw("tjEncodeYUV3(): libjpeg API is in the wrong state"); |
+ _throw("tjEncodeYUVPlanes(): libjpeg API is in the wrong state"); |
(*cinfo->err->reset_error_mgr)((j_common_ptr)cinfo); |
jinit_c_master_control(cinfo, FALSE); |
jinit_color_converter(cinfo); |
jinit_downsampler(cinfo); |
(*cinfo->cconvert->start_pass)(cinfo); |
- pw=PAD(width, cinfo->max_h_samp_factor); |
- ph=PAD(height, cinfo->max_v_samp_factor); |
+ pw0=PAD(width, cinfo->max_h_samp_factor); |
+ ph0=PAD(height, cinfo->max_v_samp_factor); |
- if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph))==NULL) |
- _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL) |
+ _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
for(i=0; i<height; i++) |
{ |
- if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&srcBuf[(height-i-1)*pitch]; |
- else row_pointer[i]=&srcBuf[i*pitch]; |
+ if(flags&TJFLAG_BOTTOMUP) |
+ row_pointer[i]=(JSAMPROW)&srcBuf[(height-i-1)*pitch]; |
+ else row_pointer[i]=(JSAMPROW)&srcBuf[i*pitch]; |
} |
- if(height<ph) |
- for(i=height; i<ph; i++) row_pointer[i]=row_pointer[height-1]; |
+ if(height<ph0) |
+ for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1]; |
for(i=0; i<cinfo->num_components; i++) |
{ |
@@ -761,9 +927,9 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
_tmpbuf[i]=(JSAMPLE *)malloc( |
PAD((compptr->width_in_blocks*cinfo->max_h_samp_factor*DCTSIZE) |
/compptr->h_samp_factor, 16) * cinfo->max_v_samp_factor + 16); |
- if(!_tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if(!_tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*cinfo->max_v_samp_factor); |
- if(!tmpbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if(!tmpbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
for(row=0; row<cinfo->max_v_samp_factor; row++) |
{ |
unsigned char *_tmpbuf_aligned= |
@@ -774,9 +940,9 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
} |
_tmpbuf2[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) |
* compptr->v_samp_factor + 16); |
- if(!_tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if(!_tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
tmpbuf2[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); |
- if(!tmpbuf2[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); |
+ if(!tmpbuf2[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
for(row=0; row<compptr->v_samp_factor; row++) |
{ |
unsigned char *_tmpbuf2_aligned= |
@@ -784,20 +950,19 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
tmpbuf2[i][row]=&_tmpbuf2_aligned[ |
PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; |
} |
- cw[i]=pw*compptr->h_samp_factor/cinfo->max_h_samp_factor; |
- ch[i]=ph*compptr->v_samp_factor/cinfo->max_v_samp_factor; |
- outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]); |
- if(!outbuf[i]) _throw("tjEncodeYUV2(): Memory allocation failure"); |
- for(row=0; row<ch[i]; row++) |
+ pw[i]=pw0*compptr->h_samp_factor/cinfo->max_h_samp_factor; |
+ ph[i]=ph0*compptr->v_samp_factor/cinfo->max_v_samp_factor; |
+ outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]); |
+ if(!outbuf[i]) _throw("tjEncodeYUVPlanes(): Memory allocation failure"); |
+ ptr=dstPlanes[i]; |
+ for(row=0; row<ph[i]; row++) |
{ |
outbuf[i][row]=ptr; |
- ptr+=PAD(cw[i], 4); |
+ ptr+=(strides && strides[i]!=0)? strides[i]:pw[i]; |
} |
} |
- if(yuvsize!=(unsigned long)(ptr-dstBuf)) |
- _throw("tjEncodeYUV2(): Generated image is not the correct size"); |
- for(row=0; row<ph; row+=cinfo->max_v_samp_factor) |
+ for(row=0; row<ph0; row+=cinfo->max_v_samp_factor) |
{ |
(*cinfo->cconvert->color_convert)(cinfo, &row_pointer[row], tmpbuf, 0, |
cinfo->max_v_samp_factor); |
@@ -805,7 +970,7 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
for(i=0, compptr=cinfo->comp_info; i<cinfo->num_components; i++, compptr++) |
jcopy_sample_rows(tmpbuf2[i], 0, outbuf[i], |
row*compptr->v_samp_factor/cinfo->max_v_samp_factor, |
- compptr->v_samp_factor, cw[i]); |
+ compptr->v_samp_factor, pw[i]); |
} |
cinfo->next_scanline+=height; |
jpeg_abort_compress(cinfo); |
@@ -824,9 +989,54 @@ DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
if(_tmpbuf2[i]!=NULL) free(_tmpbuf2[i]); |
if(outbuf[i]!=NULL) free(outbuf[i]); |
} |
+ if(this->jerr.warning) retval=-1; |
return retval; |
} |
+DLLEXPORT int DLLCALL tjEncodeYUV3(tjhandle handle, |
+ const unsigned char *srcBuf, int width, int pitch, int height, |
+ int pixelFormat, unsigned char *dstBuf, int pad, int subsamp, int flags) |
+{ |
+ unsigned char *dstPlanes[3]; |
+ int pw0, ph0, strides[3], retval=-1; |
+ |
+ if(width<=0 || height<=0 || dstBuf==NULL || pad<0 || !isPow2(pad) |
+ || subsamp<0 || subsamp>=NUMSUBOPT) |
+ _throw("tjEncodeYUV3(): Invalid argument"); |
+ |
+ pw0=tjPlaneWidth(0, width, subsamp); |
+ ph0=tjPlaneHeight(0, height, subsamp); |
+ dstPlanes[0]=dstBuf; |
+ strides[0]=PAD(pw0, pad); |
+ if(subsamp==TJSAMP_GRAY) |
+ { |
+ strides[1]=strides[2]=0; |
+ dstPlanes[1]=dstPlanes[2]=NULL; |
+ } |
+ else |
+ { |
+ int pw1=tjPlaneWidth(1, width, subsamp); |
+ int ph1=tjPlaneHeight(1, height, subsamp); |
+ strides[1]=strides[2]=PAD(pw1, pad); |
+ dstPlanes[1]=dstPlanes[0]+strides[0]*ph0; |
+ dstPlanes[2]=dstPlanes[1]+strides[1]*ph1; |
+ } |
+ |
+ return tjEncodeYUVPlanes(handle, srcBuf, width, pitch, height, pixelFormat, |
+ dstPlanes, strides, subsamp, flags); |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+DLLEXPORT int DLLCALL tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, |
+ int width, int pitch, int height, int pixelFormat, unsigned char *dstBuf, |
+ int subsamp, int flags) |
+{ |
+ return tjEncodeYUV3(handle, srcBuf, width, pitch, height, pixelFormat, |
+ dstBuf, 4, subsamp, flags); |
+} |
+ |
DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, |
int width, int pitch, int height, int pixelSize, unsigned char *dstBuf, |
int subsamp, int flags) |
@@ -836,16 +1046,187 @@ DLLEXPORT int DLLCALL tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, |
} |
+DLLEXPORT int DLLCALL tjCompressFromYUVPlanes(tjhandle handle, |
+ const unsigned char **srcPlanes, int width, const int *strides, int height, |
+ int subsamp, unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, |
+ int flags) |
+{ |
+ int i, row, retval=0, alloc=1; JSAMPROW *inbuf[MAX_COMPONENTS]; |
+ int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS], |
+ tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS]; |
+ JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS]; |
+ |
+ getcinstance(handle) |
+ |
+ for(i=0; i<MAX_COMPONENTS; i++) |
+ { |
+ tmpbuf[i]=NULL; inbuf[i]=NULL; |
+ } |
+ |
+ if((this->init&COMPRESS)==0) |
+ _throw("tjCompressFromYUVPlanes(): Instance has not been initialized for compression"); |
+ |
+ if(!srcPlanes || !srcPlanes[0] || width<=0 || height<=0 || subsamp<0 |
+ || subsamp>=NUMSUBOPT || jpegBuf==NULL || jpegSize==NULL || jpegQual<0 |
+ || jpegQual>100) |
+ _throw("tjCompressFromYUVPlanes(): Invalid argument"); |
+ if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2])) |
+ _throw("tjCompressFromYUVPlanes(): Invalid argument"); |
+ |
+ if(setjmp(this->jerr.setjmp_buffer)) |
+ { |
+ /* If we get here, the JPEG code has signaled an error. */ |
+ retval=-1; |
+ goto bailout; |
+ } |
+ |
+ cinfo->image_width=width; |
+ cinfo->image_height=height; |
+ |
+ if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
+ else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
+ else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
+ |
+ if(flags&TJFLAG_NOREALLOC) |
+ { |
+ alloc=0; *jpegSize=tjBufSize(width, height, subsamp); |
+ } |
+ jpeg_mem_dest_tj(cinfo, jpegBuf, jpegSize, alloc); |
+ if(setCompDefaults(cinfo, TJPF_RGB, subsamp, jpegQual, flags)==-1) |
+ return -1; |
+ cinfo->raw_data_in=TRUE; |
+ |
+ jpeg_start_compress(cinfo, TRUE); |
+ for(i=0; i<cinfo->num_components; i++) |
+ { |
+ jpeg_component_info *compptr=&cinfo->comp_info[i]; |
+ int ih; |
+ iw[i]=compptr->width_in_blocks*DCTSIZE; |
+ ih=compptr->height_in_blocks*DCTSIZE; |
+ pw[i]=PAD(cinfo->image_width, cinfo->max_h_samp_factor) |
+ *compptr->h_samp_factor/cinfo->max_h_samp_factor; |
+ ph[i]=PAD(cinfo->image_height, cinfo->max_v_samp_factor) |
+ *compptr->v_samp_factor/cinfo->max_v_samp_factor; |
+ if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1; |
+ th[i]=compptr->v_samp_factor*DCTSIZE; |
+ tmpbufsize+=iw[i]*th[i]; |
+ if((inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL) |
+ _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); |
+ ptr=(JSAMPLE *)srcPlanes[i]; |
+ for(row=0; row<ph[i]; row++) |
+ { |
+ inbuf[i][row]=ptr; |
+ ptr+=(strides && strides[i]!=0)? strides[i]:pw[i]; |
+ } |
+ } |
+ if(usetmpbuf) |
+ { |
+ if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL) |
+ _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); |
+ ptr=_tmpbuf; |
+ for(i=0; i<cinfo->num_components; i++) |
+ { |
+ if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL) |
+ _throw("tjCompressFromYUVPlanes(): Memory allocation failure"); |
+ for(row=0; row<th[i]; row++) |
+ { |
+ tmpbuf[i][row]=ptr; |
+ ptr+=iw[i]; |
+ } |
+ } |
+ } |
+ |
+ for(row=0; row<(int)cinfo->image_height; |
+ row+=cinfo->max_v_samp_factor*DCTSIZE) |
+ { |
+ JSAMPARRAY yuvptr[MAX_COMPONENTS]; |
+ int crow[MAX_COMPONENTS]; |
+ for(i=0; i<cinfo->num_components; i++) |
+ { |
+ jpeg_component_info *compptr=&cinfo->comp_info[i]; |
+ crow[i]=row*compptr->v_samp_factor/cinfo->max_v_samp_factor; |
+ if(usetmpbuf) |
+ { |
+ int j, k; |
+ for(j=0; j<min(th[i], ph[i]-crow[i]); j++) |
+ { |
+ memcpy(tmpbuf[i][j], inbuf[i][crow[i]+j], pw[i]); |
+ /* Duplicate last sample in row to fill out MCU */ |
+ for(k=pw[i]; k<iw[i]; k++) tmpbuf[i][j][k]=tmpbuf[i][j][pw[i]-1]; |
+ } |
+ /* Duplicate last row to fill out MCU */ |
+ for(j=ph[i]-crow[i]; j<th[i]; j++) |
+ memcpy(tmpbuf[i][j], tmpbuf[i][ph[i]-crow[i]-1], iw[i]); |
+ yuvptr[i]=tmpbuf[i]; |
+ } |
+ else |
+ yuvptr[i]=&inbuf[i][crow[i]]; |
+ } |
+ jpeg_write_raw_data(cinfo, yuvptr, cinfo->max_v_samp_factor*DCTSIZE); |
+ } |
+ jpeg_finish_compress(cinfo); |
+ |
+ bailout: |
+ if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); |
+ for(i=0; i<MAX_COMPONENTS; i++) |
+ { |
+ if(tmpbuf[i]) free(tmpbuf[i]); |
+ if(inbuf[i]) free(inbuf[i]); |
+ } |
+ if(_tmpbuf) free(_tmpbuf); |
+ if(this->jerr.warning) retval=-1; |
+ return retval; |
+} |
+ |
+DLLEXPORT int DLLCALL tjCompressFromYUV(tjhandle handle, |
+ const unsigned char *srcBuf, int width, int pad, int height, int subsamp, |
+ unsigned char **jpegBuf, unsigned long *jpegSize, int jpegQual, int flags) |
+{ |
+ const unsigned char *srcPlanes[3]; |
+ int pw0, ph0, strides[3], retval=-1; |
+ |
+ if(srcBuf==NULL || width<=0 || pad<1 || height<=0 || subsamp<0 |
+ || subsamp>=NUMSUBOPT) |
+ _throw("tjCompressFromYUV(): Invalid argument"); |
+ |
+ pw0=tjPlaneWidth(0, width, subsamp); |
+ ph0=tjPlaneHeight(0, height, subsamp); |
+ srcPlanes[0]=srcBuf; |
+ strides[0]=PAD(pw0, pad); |
+ if(subsamp==TJSAMP_GRAY) |
+ { |
+ strides[1]=strides[2]=0; |
+ srcPlanes[1]=srcPlanes[2]=NULL; |
+ } |
+ else |
+ { |
+ int pw1=tjPlaneWidth(1, width, subsamp); |
+ int ph1=tjPlaneHeight(1, height, subsamp); |
+ strides[1]=strides[2]=PAD(pw1, pad); |
+ srcPlanes[1]=srcPlanes[0]+strides[0]*ph0; |
+ srcPlanes[2]=srcPlanes[1]+strides[1]*ph1; |
+ } |
+ |
+ return tjCompressFromYUVPlanes(handle, srcPlanes, width, strides, height, |
+ subsamp, jpegBuf, jpegSize, jpegQual, flags); |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+ |
/* Decompressor */ |
static tjhandle _tjInitDecompress(tjinstance *this) |
{ |
- unsigned char buffer[1]; |
+ static unsigned char buffer[1]; |
/* This is also straight out of example.c */ |
this->dinfo.err=jpeg_std_error(&this->jerr.pub); |
this->jerr.pub.error_exit=my_error_exit; |
this->jerr.pub.output_message=my_output_message; |
+ this->jerr.emit_message=this->jerr.pub.emit_message; |
+ this->jerr.pub.emit_message=my_emit_message; |
if(setjmp(this->jerr.setjmp_buffer)) |
{ |
@@ -875,19 +1256,19 @@ DLLEXPORT tjhandle DLLCALL tjInitDecompress(void) |
} |
-DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, |
- unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, |
- int *jpegSubsamp) |
+DLLEXPORT int DLLCALL tjDecompressHeader3(tjhandle handle, |
+ const unsigned char *jpegBuf, unsigned long jpegSize, int *width, |
+ int *height, int *jpegSubsamp, int *jpegColorspace) |
{ |
int retval=0; |
- getinstance(handle); |
+ getdinstance(handle); |
if((this->init&DECOMPRESS)==0) |
- _throw("tjDecompressHeader2(): Instance has not been initialized for decompression"); |
+ _throw("tjDecompressHeader3(): Instance has not been initialized for decompression"); |
if(jpegBuf==NULL || jpegSize<=0 || width==NULL || height==NULL |
- || jpegSubsamp==NULL) |
- _throw("tjDecompressHeader2(): Invalid argument"); |
+ || jpegSubsamp==NULL || jpegColorspace==NULL) |
+ _throw("tjDecompressHeader3(): Invalid argument"); |
if(setjmp(this->jerr.setjmp_buffer)) |
{ |
@@ -901,18 +1282,39 @@ DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, |
*width=dinfo->image_width; |
*height=dinfo->image_height; |
*jpegSubsamp=getSubsamp(dinfo); |
+ switch(dinfo->jpeg_color_space) |
+ { |
+ case JCS_GRAYSCALE: *jpegColorspace=TJCS_GRAY; break; |
+ case JCS_RGB: *jpegColorspace=TJCS_RGB; break; |
+ case JCS_YCbCr: *jpegColorspace=TJCS_YCbCr; break; |
+ case JCS_CMYK: *jpegColorspace=TJCS_CMYK; break; |
+ case JCS_YCCK: *jpegColorspace=TJCS_YCCK; break; |
+ default: *jpegColorspace=-1; break; |
+ } |
jpeg_abort_decompress(dinfo); |
if(*jpegSubsamp<0) |
- _throw("tjDecompressHeader2(): Could not determine subsampling type for JPEG image"); |
+ _throw("tjDecompressHeader3(): Could not determine subsampling type for JPEG image"); |
+ if(*jpegColorspace<0) |
+ _throw("tjDecompressHeader3(): Could not determine colorspace of JPEG image"); |
if(*width<1 || *height<1) |
- _throw("tjDecompressHeader2(): Invalid data returned in header"); |
+ _throw("tjDecompressHeader3(): Invalid data returned in header"); |
bailout: |
+ if(this->jerr.warning) retval=-1; |
return retval; |
} |
+DLLEXPORT int DLLCALL tjDecompressHeader2(tjhandle handle, |
+ unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height, |
+ int *jpegSubsamp) |
+{ |
+ int jpegColorspace; |
+ return tjDecompressHeader3(handle, jpegBuf, jpegSize, width, height, |
+ jpegSubsamp, &jpegColorspace); |
+} |
+ |
DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle handle, |
unsigned char *jpegBuf, unsigned long jpegSize, int *width, int *height) |
{ |
@@ -936,9 +1338,9 @@ DLLEXPORT tjscalingfactor* DLLCALL tjGetScalingFactors(int *numscalingfactors) |
} |
-DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, |
- unsigned long jpegSize, unsigned char *dstBuf, int width, int pitch, |
- int height, int pixelFormat, int flags) |
+DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, |
+ const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, |
+ int width, int pitch, int height, int pixelFormat, int flags) |
{ |
int i, retval=0; JSAMPROW *row_pointer=NULL; |
int jpegwidth, jpegheight, scaledw, scaledh; |
@@ -947,7 +1349,7 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, |
unsigned char *_dstBuf=NULL; int _pitch=0; |
#endif |
- getinstance(handle); |
+ getdinstance(handle); |
if((this->init&DECOMPRESS)==0) |
_throw("tjDecompress2(): Instance has not been initialized for decompression"); |
@@ -985,7 +1387,7 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, |
if(scaledw<=width && scaledh<=height) |
break; |
} |
- if(scaledw>width || scaledh>height) |
+ if(i>=NUMSF) |
_throw("tjDecompress2(): Could not scale down to desired image dimensions"); |
width=scaledw; height=scaledh; |
dinfo->scale_num=sf[i].num; |
@@ -995,7 +1397,7 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, |
if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; |
#ifndef JCS_EXTENSIONS |
- if(pixelFormat!=TJPF_GRAY && |
+ if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK && |
(RGB_RED!=tjRedOffset[pixelFormat] || |
RGB_GREEN!=tjGreenOffset[pixelFormat] || |
RGB_BLUE!=tjBlueOffset[pixelFormat] || |
@@ -1034,6 +1436,7 @@ DLLEXPORT int DLLCALL tjDecompress2(tjhandle handle, unsigned char *jpegBuf, |
if(rgbBuf) free(rgbBuf); |
#endif |
if(row_pointer) free(row_pointer); |
+ if(this->jerr.warning) retval=-1; |
return retval; |
} |
@@ -1049,16 +1452,270 @@ DLLEXPORT int DLLCALL tjDecompress(tjhandle handle, unsigned char *jpegBuf, |
} |
-DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
- unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, |
+static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo, |
+ int pixelFormat, int subsamp, int flags) |
+{ |
+ int i; |
+ |
+ dinfo->scale_num=dinfo->scale_denom=1; |
+ |
+ if(subsamp==TJSAMP_GRAY) |
+ { |
+ dinfo->num_components=dinfo->comps_in_scan=1; |
+ dinfo->jpeg_color_space=JCS_GRAYSCALE; |
+ } |
+ else |
+ { |
+ dinfo->num_components=dinfo->comps_in_scan=3; |
+ dinfo->jpeg_color_space=JCS_YCbCr; |
+ } |
+ |
+ dinfo->comp_info=(jpeg_component_info *) |
+ (*dinfo->mem->alloc_small)((j_common_ptr)dinfo, JPOOL_IMAGE, |
+ dinfo->num_components*sizeof(jpeg_component_info)); |
+ |
+ for(i=0; i<dinfo->num_components; i++) |
+ { |
+ jpeg_component_info *compptr=&dinfo->comp_info[i]; |
+ compptr->h_samp_factor=(i==0)? tjMCUWidth[subsamp]/8:1; |
+ compptr->v_samp_factor=(i==0)? tjMCUHeight[subsamp]/8:1; |
+ compptr->component_index=i; |
+ compptr->component_id=i+1; |
+ compptr->quant_tbl_no=compptr->dc_tbl_no=compptr->ac_tbl_no= |
+ (i==0)? 0:1; |
+ dinfo->cur_comp_info[i]=compptr; |
+ } |
+ dinfo->data_precision=8; |
+ for(i=0; i<2; i++) |
+ { |
+ if(dinfo->quant_tbl_ptrs[i]==NULL) |
+ dinfo->quant_tbl_ptrs[i]=jpeg_alloc_quant_table((j_common_ptr)dinfo); |
+ } |
+ |
+ return 0; |
+} |
+ |
+ |
+int my_read_markers(j_decompress_ptr dinfo) |
+{ |
+ return JPEG_REACHED_SOS; |
+} |
+ |
+void my_reset_marker_reader(j_decompress_ptr dinfo) |
+{ |
+} |
+ |
+DLLEXPORT int DLLCALL tjDecodeYUVPlanes(tjhandle handle, |
+ const unsigned char **srcPlanes, const int *strides, int subsamp, |
+ unsigned char *dstBuf, int width, int pitch, int height, int pixelFormat, |
int flags) |
{ |
- int i, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS]; |
- int cw[MAX_COMPONENTS], ch[MAX_COMPONENTS], iw[MAX_COMPONENTS], |
+ int i, retval=0; JSAMPROW *row_pointer=NULL; |
+ JSAMPLE *_tmpbuf[MAX_COMPONENTS]; |
+ JSAMPROW *tmpbuf[MAX_COMPONENTS], *inbuf[MAX_COMPONENTS]; |
+ int row, pw0, ph0, pw[MAX_COMPONENTS], ph[MAX_COMPONENTS]; |
+ JSAMPLE *ptr; |
+ jpeg_component_info *compptr; |
+ #ifndef JCS_EXTENSIONS |
+ unsigned char *rgbBuf=NULL; |
+ unsigned char *_dstBuf=NULL; int _pitch=0; |
+ #endif |
+ int (*old_read_markers)(j_decompress_ptr); |
+ void (*old_reset_marker_reader)(j_decompress_ptr); |
+ |
+ getdinstance(handle); |
+ |
+ for(i=0; i<MAX_COMPONENTS; i++) |
+ { |
+ tmpbuf[i]=NULL; _tmpbuf[i]=NULL; inbuf[i]=NULL; |
+ } |
+ |
+ if((this->init&DECOMPRESS)==0) |
+ _throw("tjDecodeYUVPlanes(): Instance has not been initialized for decompression"); |
+ |
+ if(!srcPlanes || !srcPlanes[0] || subsamp<0 || subsamp>=NUMSUBOPT |
+ || dstBuf==NULL || width<=0 || pitch<0 || height<=0 || pixelFormat<0 |
+ || pixelFormat>=TJ_NUMPF) |
+ _throw("tjDecodeYUVPlanes(): Invalid argument"); |
+ if(subsamp!=TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2])) |
+ _throw("tjDecodeYUVPlanes(): Invalid argument"); |
+ |
+ if(setjmp(this->jerr.setjmp_buffer)) |
+ { |
+ /* If we get here, the JPEG code has signaled an error. */ |
+ retval=-1; |
+ goto bailout; |
+ } |
+ |
+ if(pixelFormat==TJPF_CMYK) |
+ _throw("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels."); |
+ |
+ if(pitch==0) pitch=width*tjPixelSize[pixelFormat]; |
+ dinfo->image_width=width; |
+ dinfo->image_height=height; |
+ |
+ if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
+ else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
+ else if(flags&TJFLAG_FORCESSE2) putenv("JSIMD_FORCESSE2=1"); |
+ |
+ if(setDecodeDefaults(dinfo, pixelFormat, subsamp, flags)==-1) |
+ { |
+ retval=-1; goto bailout; |
+ } |
+ old_read_markers=dinfo->marker->read_markers; |
+ dinfo->marker->read_markers=my_read_markers; |
+ old_reset_marker_reader=dinfo->marker->reset_marker_reader; |
+ dinfo->marker->reset_marker_reader=my_reset_marker_reader; |
+ jpeg_read_header(dinfo, TRUE); |
+ dinfo->marker->read_markers=old_read_markers; |
+ dinfo->marker->reset_marker_reader=old_reset_marker_reader; |
+ |
+ if(setDecompDefaults(dinfo, pixelFormat, flags)==-1) |
+ { |
+ retval=-1; goto bailout; |
+ } |
+ dinfo->do_fancy_upsampling=FALSE; |
+ dinfo->Se=DCTSIZE2-1; |
+ jinit_master_decompress(dinfo); |
+ (*dinfo->upsample->start_pass)(dinfo); |
+ |
+ pw0=PAD(width, dinfo->max_h_samp_factor); |
+ ph0=PAD(height, dinfo->max_v_samp_factor); |
+ |
+ if(pitch==0) pitch=dinfo->output_width*tjPixelSize[pixelFormat]; |
+ |
+ #ifndef JCS_EXTENSIONS |
+ if(pixelFormat!=TJPF_GRAY && pixelFormat!=TJPF_CMYK && |
+ (RGB_RED!=tjRedOffset[pixelFormat] || |
+ RGB_GREEN!=tjGreenOffset[pixelFormat] || |
+ RGB_BLUE!=tjBlueOffset[pixelFormat] || |
+ RGB_PIXELSIZE!=tjPixelSize[pixelFormat])) |
+ { |
+ rgbBuf=(unsigned char *)malloc(width*height*3); |
+ if(!rgbBuf) _throw("tjDecodeYUVPlanes(): Memory allocation failure"); |
+ _pitch=pitch; pitch=width*3; |
+ _dstBuf=dstBuf; dstBuf=rgbBuf; |
+ } |
+ #endif |
+ |
+ if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph0))==NULL) |
+ _throw("tjDecodeYUVPlanes(): Memory allocation failure"); |
+ for(i=0; i<height; i++) |
+ { |
+ if(flags&TJFLAG_BOTTOMUP) row_pointer[i]=&dstBuf[(height-i-1)*pitch]; |
+ else row_pointer[i]=&dstBuf[i*pitch]; |
+ } |
+ if(height<ph0) |
+ for(i=height; i<ph0; i++) row_pointer[i]=row_pointer[height-1]; |
+ |
+ for(i=0; i<dinfo->num_components; i++) |
+ { |
+ compptr=&dinfo->comp_info[i]; |
+ _tmpbuf[i]=(JSAMPLE *)malloc(PAD(compptr->width_in_blocks*DCTSIZE, 16) |
+ * compptr->v_samp_factor + 16); |
+ if(!_tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure"); |
+ tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*compptr->v_samp_factor); |
+ if(!tmpbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure"); |
+ for(row=0; row<compptr->v_samp_factor; row++) |
+ { |
+ unsigned char *_tmpbuf_aligned= |
+ (unsigned char *)PAD((size_t)_tmpbuf[i], 16); |
+ tmpbuf[i][row]=&_tmpbuf_aligned[ |
+ PAD(compptr->width_in_blocks*DCTSIZE, 16) * row]; |
+ } |
+ pw[i]=pw0*compptr->h_samp_factor/dinfo->max_h_samp_factor; |
+ ph[i]=ph0*compptr->v_samp_factor/dinfo->max_v_samp_factor; |
+ inbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]); |
+ if(!inbuf[i]) _throw("tjDecodeYUVPlanes(): Memory allocation failure"); |
+ ptr=(JSAMPLE *)srcPlanes[i]; |
+ for(row=0; row<ph[i]; row++) |
+ { |
+ inbuf[i][row]=ptr; |
+ ptr+=(strides && strides[i]!=0)? strides[i]:pw[i]; |
+ } |
+ } |
+ |
+ for(row=0; row<ph0; row+=dinfo->max_v_samp_factor) |
+ { |
+ JDIMENSION inrow=0, outrow=0; |
+ for(i=0, compptr=dinfo->comp_info; i<dinfo->num_components; i++, compptr++) |
+ jcopy_sample_rows(inbuf[i], |
+ row*compptr->v_samp_factor/dinfo->max_v_samp_factor, tmpbuf[i], 0, |
+ compptr->v_samp_factor, pw[i]); |
+ (dinfo->upsample->upsample)(dinfo, tmpbuf, &inrow, |
+ dinfo->max_v_samp_factor, &row_pointer[row], &outrow, |
+ dinfo->max_v_samp_factor); |
+ } |
+ jpeg_abort_decompress(dinfo); |
+ |
+ #ifndef JCS_EXTENSIONS |
+ fromRGB(rgbBuf, _dstBuf, width, _pitch, height, pixelFormat); |
+ #endif |
+ |
+ bailout: |
+ if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); |
+ #ifndef JCS_EXTENSIONS |
+ if(rgbBuf) free(rgbBuf); |
+ #endif |
+ if(row_pointer) free(row_pointer); |
+ for(i=0; i<MAX_COMPONENTS; i++) |
+ { |
+ if(tmpbuf[i]!=NULL) free(tmpbuf[i]); |
+ if(_tmpbuf[i]!=NULL) free(_tmpbuf[i]); |
+ if(inbuf[i]!=NULL) free(inbuf[i]); |
+ } |
+ if(this->jerr.warning) retval=-1; |
+ return retval; |
+} |
+ |
+DLLEXPORT int DLLCALL tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf, |
+ int pad, int subsamp, unsigned char *dstBuf, int width, int pitch, |
+ int height, int pixelFormat, int flags) |
+{ |
+ const unsigned char *srcPlanes[3]; |
+ int pw0, ph0, strides[3], retval=-1; |
+ |
+ if(srcBuf==NULL || pad<0 || !isPow2(pad) || subsamp<0 || subsamp>=NUMSUBOPT |
+ || width<=0 || height<=0) |
+ _throw("tjDecodeYUV(): Invalid argument"); |
+ |
+ pw0=tjPlaneWidth(0, width, subsamp); |
+ ph0=tjPlaneHeight(0, height, subsamp); |
+ srcPlanes[0]=srcBuf; |
+ strides[0]=PAD(pw0, pad); |
+ if(subsamp==TJSAMP_GRAY) |
+ { |
+ strides[1]=strides[2]=0; |
+ srcPlanes[1]=srcPlanes[2]=NULL; |
+ } |
+ else |
+ { |
+ int pw1=tjPlaneWidth(1, width, subsamp); |
+ int ph1=tjPlaneHeight(1, height, subsamp); |
+ strides[1]=strides[2]=PAD(pw1, pad); |
+ srcPlanes[1]=srcPlanes[0]+strides[0]*ph0; |
+ srcPlanes[2]=srcPlanes[1]+strides[1]*ph1; |
+ } |
+ |
+ return tjDecodeYUVPlanes(handle, srcPlanes, strides, subsamp, dstBuf, width, |
+ pitch, height, pixelFormat, flags); |
+ |
+ bailout: |
+ return retval; |
+} |
+ |
+DLLEXPORT int DLLCALL tjDecompressToYUVPlanes(tjhandle handle, |
+ const unsigned char *jpegBuf, unsigned long jpegSize, |
+ unsigned char **dstPlanes, int width, int *strides, int height, int flags) |
+{ |
+ int i, sfi, row, retval=0; JSAMPROW *outbuf[MAX_COMPONENTS]; |
+ int jpegwidth, jpegheight, jpegSubsamp, scaledw, scaledh; |
+ int pw[MAX_COMPONENTS], ph[MAX_COMPONENTS], iw[MAX_COMPONENTS], |
tmpbufsize=0, usetmpbuf=0, th[MAX_COMPONENTS]; |
- JSAMPLE *_tmpbuf=NULL, *ptr=dstBuf; JSAMPROW *tmpbuf[MAX_COMPONENTS]; |
+ JSAMPLE *_tmpbuf=NULL, *ptr; JSAMPROW *tmpbuf[MAX_COMPONENTS]; |
+ int dctsize; |
- getinstance(handle); |
+ getdinstance(handle); |
for(i=0; i<MAX_COMPONENTS; i++) |
{ |
@@ -1066,10 +1723,11 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
} |
if((this->init&DECOMPRESS)==0) |
- _throw("tjDecompressToYUV(): Instance has not been initialized for decompression"); |
+ _throw("tjDecompressToYUVPlanes(): Instance has not been initialized for decompression"); |
- if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL) |
- _throw("tjDecompressToYUV(): Invalid argument"); |
+ if(jpegBuf==NULL || jpegSize<=0 || !dstPlanes || !dstPlanes[0] || width<0 |
+ || height<0) |
+ _throw("tjDecompressToYUVPlanes(): Invalid argument"); |
if(flags&TJFLAG_FORCEMMX) putenv("JSIMD_FORCEMMX=1"); |
else if(flags&TJFLAG_FORCESSE) putenv("JSIMD_FORCESSE=1"); |
@@ -1082,39 +1740,73 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
goto bailout; |
} |
- jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); |
- jpeg_read_header(dinfo, TRUE); |
+ if(!this->headerRead) |
+ { |
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); |
+ jpeg_read_header(dinfo, TRUE); |
+ } |
+ this->headerRead=0; |
+ jpegSubsamp=getSubsamp(dinfo); |
+ if(jpegSubsamp<0) |
+ _throw("tjDecompressToYUVPlanes(): Could not determine subsampling type for JPEG image"); |
+ |
+ if(jpegSubsamp!=TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2])) |
+ _throw("tjDecompressToYUVPlanes(): Invalid argument"); |
+ |
+ jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; |
+ if(width==0) width=jpegwidth; |
+ if(height==0) height=jpegheight; |
+ for(i=0; i<NUMSF; i++) |
+ { |
+ scaledw=TJSCALED(jpegwidth, sf[i]); |
+ scaledh=TJSCALED(jpegheight, sf[i]); |
+ if(scaledw<=width && scaledh<=height) |
+ break; |
+ } |
+ if(i>=NUMSF) |
+ _throw("tjDecompressToYUVPlanes(): Could not scale down to desired image dimensions"); |
+ if(dinfo->num_components>3) |
+ _throw("tjDecompressToYUVPlanes(): JPEG image must have 3 or fewer components"); |
+ |
+ width=scaledw; height=scaledh; |
+ dinfo->scale_num=sf[i].num; |
+ dinfo->scale_denom=sf[i].denom; |
+ sfi=i; |
+ jpeg_calc_output_dimensions(dinfo); |
+ |
+ dctsize=DCTSIZE*sf[sfi].num/sf[sfi].denom; |
for(i=0; i<dinfo->num_components; i++) |
{ |
jpeg_component_info *compptr=&dinfo->comp_info[i]; |
int ih; |
- iw[i]=compptr->width_in_blocks*DCTSIZE; |
- ih=compptr->height_in_blocks*DCTSIZE; |
- cw[i]=PAD(dinfo->image_width, dinfo->max_h_samp_factor) |
+ iw[i]=compptr->width_in_blocks*dctsize; |
+ ih=compptr->height_in_blocks*dctsize; |
+ pw[i]=PAD(dinfo->output_width, dinfo->max_h_samp_factor) |
*compptr->h_samp_factor/dinfo->max_h_samp_factor; |
- ch[i]=PAD(dinfo->image_height, dinfo->max_v_samp_factor) |
+ ph[i]=PAD(dinfo->output_height, dinfo->max_v_samp_factor) |
*compptr->v_samp_factor/dinfo->max_v_samp_factor; |
- if(iw[i]!=cw[i] || ih!=ch[i]) usetmpbuf=1; |
- th[i]=compptr->v_samp_factor*DCTSIZE; |
+ if(iw[i]!=pw[i] || ih!=ph[i]) usetmpbuf=1; |
+ th[i]=compptr->v_samp_factor*dctsize; |
tmpbufsize+=iw[i]*th[i]; |
- if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ch[i]))==NULL) |
- _throw("tjDecompressToYUV(): Memory allocation failure"); |
- for(row=0; row<ch[i]; row++) |
+ if((outbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*ph[i]))==NULL) |
+ _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); |
+ ptr=dstPlanes[i]; |
+ for(row=0; row<ph[i]; row++) |
{ |
outbuf[i][row]=ptr; |
- ptr+=PAD(cw[i], 4); |
+ ptr+=(strides && strides[i]!=0)? strides[i]:pw[i]; |
} |
} |
if(usetmpbuf) |
{ |
if((_tmpbuf=(JSAMPLE *)malloc(sizeof(JSAMPLE)*tmpbufsize))==NULL) |
- _throw("tjDecompressToYUV(): Memory allocation failure"); |
+ _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); |
ptr=_tmpbuf; |
for(i=0; i<dinfo->num_components; i++) |
{ |
if((tmpbuf[i]=(JSAMPROW *)malloc(sizeof(JSAMPROW)*th[i]))==NULL) |
- _throw("tjDecompressToYUV(): Memory allocation failure"); |
+ _throw("tjDecompressToYUVPlanes(): Memory allocation failure"); |
for(row=0; row<th[i]; row++) |
{ |
tmpbuf[i][row]=ptr; |
@@ -1129,26 +1821,45 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
jpeg_start_decompress(dinfo); |
for(row=0; row<(int)dinfo->output_height; |
- row+=dinfo->max_v_samp_factor*DCTSIZE) |
+ row+=dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size) |
{ |
JSAMPARRAY yuvptr[MAX_COMPONENTS]; |
int crow[MAX_COMPONENTS]; |
for(i=0; i<dinfo->num_components; i++) |
{ |
jpeg_component_info *compptr=&dinfo->comp_info[i]; |
+ if(jpegSubsamp==TJ_420) |
+ { |
+ /* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try |
+ to be clever and use the IDCT to perform upsampling on the U and V |
+ planes. For instance, if the output image is to be scaled by 1/2 |
+ relative to the JPEG image, then the scaling factor and upsampling |
+ effectively cancel each other, so a normal 8x8 IDCT can be used. |
+ However, this is not desirable when using the decompress-to-YUV |
+ functionality in TurboJPEG, since we want to output the U and V |
+ planes in their subsampled form. Thus, we have to override some |
+ internal libjpeg parameters to force it to use the "scaled" IDCT |
+ functions on the U and V planes. */ |
+ compptr->_DCT_scaled_size=dctsize; |
+ compptr->MCU_sample_width=tjMCUWidth[jpegSubsamp]* |
+ sf[sfi].num/sf[sfi].denom* |
+ compptr->v_samp_factor/dinfo->max_v_samp_factor; |
+ dinfo->idct->inverse_DCT[i] = dinfo->idct->inverse_DCT[0]; |
+ } |
crow[i]=row*compptr->v_samp_factor/dinfo->max_v_samp_factor; |
if(usetmpbuf) yuvptr[i]=tmpbuf[i]; |
else yuvptr[i]=&outbuf[i][crow[i]]; |
} |
- jpeg_read_raw_data(dinfo, yuvptr, dinfo->max_v_samp_factor*DCTSIZE); |
+ jpeg_read_raw_data(dinfo, yuvptr, |
+ dinfo->max_v_samp_factor*dinfo->_min_DCT_scaled_size); |
if(usetmpbuf) |
{ |
int j; |
for(i=0; i<dinfo->num_components; i++) |
{ |
- for(j=0; j<min(th[i], ch[i]-crow[i]); j++) |
+ for(j=0; j<min(th[i], ph[i]-crow[i]); j++) |
{ |
- memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], cw[i]); |
+ memcpy(outbuf[i][crow[i]+j], tmpbuf[i][j], pw[i]); |
} |
} |
} |
@@ -1163,7 +1874,76 @@ DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
if(outbuf[i]) free(outbuf[i]); |
} |
if(_tmpbuf) free(_tmpbuf); |
+ if(this->jerr.warning) retval=-1; |
+ return retval; |
+} |
+ |
+DLLEXPORT int DLLCALL tjDecompressToYUV2(tjhandle handle, |
+ const unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, |
+ int width, int pad, int height, int flags) |
+{ |
+ unsigned char *dstPlanes[3]; |
+ int pw0, ph0, strides[3], retval=-1, jpegSubsamp=-1; |
+ int i, jpegwidth, jpegheight, scaledw, scaledh; |
+ |
+ getdinstance(handle); |
+ |
+ if(jpegBuf==NULL || jpegSize<=0 || dstBuf==NULL || width<0 || pad<1 |
+ || !isPow2(pad) || height<0) |
+ _throw("tjDecompressToYUV2(): Invalid argument"); |
+ |
+ jpeg_mem_src_tj(dinfo, jpegBuf, jpegSize); |
+ jpeg_read_header(dinfo, TRUE); |
+ jpegSubsamp=getSubsamp(dinfo); |
+ if(jpegSubsamp<0) |
+ _throw("tjDecompressToYUV2(): Could not determine subsampling type for JPEG image"); |
+ |
+ jpegwidth=dinfo->image_width; jpegheight=dinfo->image_height; |
+ if(width==0) width=jpegwidth; |
+ if(height==0) height=jpegheight; |
+ |
+ for(i=0; i<NUMSF; i++) |
+ { |
+ scaledw=TJSCALED(jpegwidth, sf[i]); |
+ scaledh=TJSCALED(jpegheight, sf[i]); |
+ if(scaledw<=width && scaledh<=height) |
+ break; |
+ } |
+ if(i>=NUMSF) |
+ _throw("tjDecompressToYUV2(): Could not scale down to desired image dimensions"); |
+ |
+ pw0=tjPlaneWidth(0, width, jpegSubsamp); |
+ ph0=tjPlaneHeight(0, height, jpegSubsamp); |
+ dstPlanes[0]=dstBuf; |
+ strides[0]=PAD(pw0, pad); |
+ if(jpegSubsamp==TJSAMP_GRAY) |
+ { |
+ strides[1]=strides[2]=0; |
+ dstPlanes[1]=dstPlanes[2]=NULL; |
+ } |
+ else |
+ { |
+ int pw1=tjPlaneWidth(1, width, jpegSubsamp); |
+ int ph1=tjPlaneHeight(1, height, jpegSubsamp); |
+ strides[1]=strides[2]=PAD(pw1, pad); |
+ dstPlanes[1]=dstPlanes[0]+strides[0]*ph0; |
+ dstPlanes[2]=dstPlanes[1]+strides[1]*ph1; |
+ } |
+ |
+ this->headerRead=1; |
+ return tjDecompressToYUVPlanes(handle, jpegBuf, jpegSize, dstPlanes, width, |
+ strides, height, flags); |
+ |
+ bailout: |
return retval; |
+ |
+} |
+ |
+DLLEXPORT int DLLCALL tjDecompressToYUV(tjhandle handle, |
+ unsigned char *jpegBuf, unsigned long jpegSize, unsigned char *dstBuf, |
+ int flags) |
+{ |
+ return tjDecompressToYUV2(handle, jpegBuf, jpegSize, dstBuf, 0, 4, 0, flags); |
} |
@@ -1186,9 +1966,9 @@ DLLEXPORT tjhandle DLLCALL tjInitTransform(void) |
} |
-DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf, |
- unsigned long jpegSize, int n, unsigned char **dstBufs, |
- unsigned long *dstSizes, tjtransform *t, int flags) |
+DLLEXPORT int DLLCALL tjTransform(tjhandle handle, |
+ const unsigned char *jpegBuf, unsigned long jpegSize, int n, |
+ unsigned char **dstBufs, unsigned long *dstSizes, tjtransform *t, int flags) |
{ |
jpeg_transform_info *xinfo=NULL; |
jvirt_barray_ptr *srccoefs, *dstcoefs; |
@@ -1336,5 +2116,6 @@ DLLEXPORT int DLLCALL tjTransform(tjhandle handle, unsigned char *jpegBuf, |
if(cinfo->global_state>CSTATE_START) jpeg_abort_compress(cinfo); |
if(dinfo->global_state>DSTATE_START) jpeg_abort_decompress(dinfo); |
if(xinfo) free(xinfo); |
+ if(this->jerr.warning) retval=-1; |
return retval; |
} |