]> source.dussan.org Git - tigervnc.git/commitdiff
Include low-level unit tests borrowed from VirtualGL
authorDRC <dcommander@users.sourceforge.net>
Fri, 3 Apr 2009 12:04:24 +0000 (12:04 +0000)
committerDRC <dcommander@users.sourceforge.net>
Fri, 3 Apr 2009 12:04:24 +0000 (12:04 +0000)
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3745 3789f03b-4d11-0410-bbf8-ca57d06f2519

common/jpeg/Makefile.am
common/jpeg/bmp.c [new file with mode: 0644]
common/jpeg/bmp.h [new file with mode: 0644]
common/jpeg/jpegut.c [new file with mode: 0644]
common/jpeg/jpgtest.cxx [new file with mode: 0644]
common/jpeg/rrtimer.h [new file with mode: 0644]
common/jpeg/rrutil.h [new file with mode: 0644]
common/jpeg/turbojpeg.h [new file with mode: 0644]
common/jpeg/turbojpegl.c [new file with mode: 0644]

index 1d868b7b3ce1e13402ff26c4dc29737df63d76f8..93120789bd991c79affa97d5f4a42c55f832b369 100644 (file)
@@ -1,7 +1,7 @@
 noinst_LTLIBRARIES = libjpeg.la
 
 HDRS = jchuff.h jdct.h jdhuff.h jerror.h jinclude.h jmemsys.h jmorecfg.h \
-       jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h
+       jpegint.h jpeglib.h jversion.h jsimd.h jsimddct.h turbojpeg.h
 
 libjpeg_la_SOURCES = $(HDRS) jcapimin.c jcapistd.c jccoefct.c jccolor.c \
        jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c \
@@ -20,3 +20,14 @@ libjpeg_la_LIBADD = simd/libsimd.la
 
 endif
 
+TSTHDRS = turbojpeg.h rrutil.h rrtimer.h
+
+bin_PROGRAMS = jpgtest jpegut
+
+jpgtest_SOURCES = $(TSTHDRS) jpgtest.cxx bmp.c turbojpegl.c
+
+jpgtest_LDADD = $(top_srcdir)/libjpeg.la
+
+jpegut_SOURCES = $(TSTHDRS) jpegut.c bmp.c turbojpegl.c
+
+jpegut_LDADD = $(top_srcdir)/libjpeg.la
diff --git a/common/jpeg/bmp.c b/common/jpeg/bmp.c
new file mode 100644 (file)
index 0000000..3ccc877
--- /dev/null
@@ -0,0 +1,370 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+*/
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _WIN32
+ #include <io.h>
+#else
+ #include <unistd.h>
+#endif
+#include "./rrutil.h"
+#include "./bmp.h"
+
+#ifndef BI_BITFIELDS
+#define BI_BITFIELDS 3L
+#endif
+#ifndef BI_RGB
+#define BI_RGB 0L
+#endif
+
+#define BMPHDRSIZE 54
+typedef struct _bmphdr
+{
+       unsigned short bfType;
+       unsigned int bfSize;
+       unsigned short bfReserved1, bfReserved2;
+       unsigned int bfOffBits;
+
+       unsigned int biSize;
+       int biWidth, biHeight;
+       unsigned short biPlanes, biBitCount;
+       unsigned int biCompression, biSizeImage;
+       int biXPelsPerMeter, biYPelsPerMeter;
+       unsigned int biClrUsed, biClrImportant;
+} bmphdr;
+
+static const char *__bmperr="No error";
+
+static const int ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
+static const int roffset[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
+static const int goffset[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
+static const int boffset[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
+
+#define _throw(m) {__bmperr=m;  retcode=-1;  goto finally;}
+#define _unix(f) {if((f)==-1) _throw(strerror(errno));}
+#define _catch(f) {if((f)==-1) {retcode=-1;  goto finally;}}
+
+#define readme(fd, addr, size) \
+       if((bytesread=read(fd, addr, (size)))==-1) _throw(strerror(errno)); \
+       if(bytesread!=(size)) _throw("Read error");
+
+void pixelconvert(unsigned char *srcbuf, enum BMPPIXELFORMAT srcformat,
+       int srcpitch, unsigned char *dstbuf, enum BMPPIXELFORMAT dstformat, int dstpitch,
+       int w, int h, int flip)
+{
+       unsigned char *srcptr, *srcptr0, *dstptr, *dstptr0;
+       int i, j;
+
+       srcptr=flip? &srcbuf[srcpitch*(h-1)]:srcbuf;
+       for(j=0, dstptr=dstbuf; j<h; j++,
+               srcptr+=flip? -srcpitch:srcpitch, dstptr+=dstpitch)
+       {
+               for(i=0, srcptr0=srcptr, dstptr0=dstptr; i<w; i++,
+                       srcptr0+=ps[srcformat], dstptr0+=ps[dstformat])
+               {
+                       dstptr0[roffset[dstformat]]=srcptr0[roffset[srcformat]];
+                       dstptr0[goffset[dstformat]]=srcptr0[goffset[srcformat]];
+                       dstptr0[boffset[dstformat]]=srcptr0[boffset[srcformat]];
+               }
+       }
+}
+
+int loadppm(int *fd, unsigned char **buf, int *w, int *h,
+       enum BMPPIXELFORMAT f, int align, int dstbottomup, int ascii)
+{
+       FILE *fs=NULL;  int retcode=0, scalefactor, dstpitch;
+       unsigned char *tempbuf=NULL;  char temps[255], temps2[255];
+       int numread=0, totalread=0, pixel[3], i, j;
+
+       if((fs=fdopen(*fd, "r"))==NULL) _throw(strerror(errno));
+
+       do
+       {
+               if(!fgets(temps, 255, fs)) _throw("Read error");
+               if(strlen(temps)==0 || temps[0]=='\n') continue;
+               if(sscanf(temps, "%s", temps2)==1 && temps2[1]=='#') continue;
+               switch(totalread)
+               {
+                       case 0:
+                               if((numread=sscanf(temps, "%d %d %d", w, h, &scalefactor))==EOF)
+                                       _throw("Read error");
+                               break;
+                       case 1:
+                               if((numread=sscanf(temps, "%d %d", h, &scalefactor))==EOF)
+                                       _throw("Read error");
+                               break;
+                       case 2:
+                               if((numread=sscanf(temps, "%d", &scalefactor))==EOF)
+                                       _throw("Read error");
+                               break;
+               }
+               totalread+=numread;
+       } while(totalread<3);
+       if((*w)<1 || (*h)<1 || scalefactor<1) _throw("Corrupt PPM header");
+
+       dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
+       if((*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
+               _throw("Memory allocation error");
+       if(ascii)
+       {
+               for(j=0; j<*h; j++)
+               {
+                       for(i=0; i<*w; i++)
+                       {
+                               if(fscanf(fs, "%d%d%d", &pixel[0], &pixel[1], &pixel[2])!=3)
+                                       _throw("Read error");
+                               (*buf)[j*dstpitch+i*ps[f]+roffset[f]]=(unsigned char)(pixel[0]*255/scalefactor);
+                               (*buf)[j*dstpitch+i*ps[f]+goffset[f]]=(unsigned char)(pixel[1]*255/scalefactor);
+                               (*buf)[j*dstpitch+i*ps[f]+boffset[f]]=(unsigned char)(pixel[2]*255/scalefactor);
+                       }
+               }
+       }
+       else
+       {
+               if(scalefactor!=255)
+                       _throw("Binary PPMs must have 8-bit components");
+               if((tempbuf=(unsigned char *)malloc((*w)*(*h)*3))==NULL)
+                       _throw("Memory allocation error");
+               if(fread(tempbuf, (*w)*(*h)*3, 1, fs)!=1) _throw("Read error");
+               pixelconvert(tempbuf, BMP_RGB, (*w)*3, *buf, f, dstpitch, *w, *h, dstbottomup);
+       }
+
+       finally:
+       if(fs) {fclose(fs);  *fd=-1;}
+       if(tempbuf) free(tempbuf);
+       return retcode;
+}
+
+
+int loadbmp(char *filename, unsigned char **buf, int *w, int *h, 
+       enum BMPPIXELFORMAT f, int align, int dstbottomup)
+{
+       int fd=-1, bytesread, srcpitch, srcbottomup=1, srcps, dstpitch,
+               retcode=0;
+       unsigned char *tempbuf=NULL;
+       bmphdr bh;  int flags=O_RDONLY;
+
+       dstbottomup=dstbottomup? 1:0;
+       #ifdef _WIN32
+       flags|=O_BINARY;
+       #endif
+       if(!filename || !buf || !w || !h || f<0 || f>BMPPIXELFORMATS-1 || align<1)
+               _throw("invalid argument to loadbmp()");
+       if((align&(align-1))!=0)
+               _throw("Alignment must be a power of 2");
+       _unix(fd=open(filename, flags));
+
+       readme(fd, &bh.bfType, sizeof(unsigned short));
+       if(!littleendian())     bh.bfType=byteswap16(bh.bfType);
+
+       if(bh.bfType==0x3650)
+       {
+               _catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 0));
+               goto finally;
+       }
+       if(bh.bfType==0x3350)
+       {
+               _catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 1));
+               goto finally;
+       }
+
+       readme(fd, &bh.bfSize, sizeof(unsigned int));
+       readme(fd, &bh.bfReserved1, sizeof(unsigned short));
+       readme(fd, &bh.bfReserved2, sizeof(unsigned short));
+       readme(fd, &bh.bfOffBits, sizeof(unsigned int));
+       readme(fd, &bh.biSize, sizeof(unsigned int));
+       readme(fd, &bh.biWidth, sizeof(int));
+       readme(fd, &bh.biHeight, sizeof(int));
+       readme(fd, &bh.biPlanes, sizeof(unsigned short));
+       readme(fd, &bh.biBitCount, sizeof(unsigned short));
+       readme(fd, &bh.biCompression, sizeof(unsigned int));
+       readme(fd, &bh.biSizeImage, sizeof(unsigned int));
+       readme(fd, &bh.biXPelsPerMeter, sizeof(int));
+       readme(fd, &bh.biYPelsPerMeter, sizeof(int));
+       readme(fd, &bh.biClrUsed, sizeof(unsigned int));
+       readme(fd, &bh.biClrImportant, sizeof(unsigned int));
+
+       if(!littleendian())
+       {
+               bh.bfSize=byteswap(bh.bfSize);
+               bh.bfOffBits=byteswap(bh.bfOffBits);
+               bh.biSize=byteswap(bh.biSize);
+               bh.biWidth=byteswap(bh.biWidth);
+               bh.biHeight=byteswap(bh.biHeight);
+               bh.biPlanes=byteswap16(bh.biPlanes);
+               bh.biBitCount=byteswap16(bh.biBitCount);
+               bh.biCompression=byteswap(bh.biCompression);
+               bh.biSizeImage=byteswap(bh.biSizeImage);
+               bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
+               bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
+               bh.biClrUsed=byteswap(bh.biClrUsed);
+               bh.biClrImportant=byteswap(bh.biClrImportant);
+       }
+
+       if(bh.bfType!=0x4d42 || bh.bfOffBits<BMPHDRSIZE
+       || bh.biWidth<1 || bh.biHeight==0)
+               _throw("Corrupt bitmap header");
+       if((bh.biBitCount!=24 && bh.biBitCount!=32) || bh.biCompression!=BI_RGB)
+               _throw("Only uncompessed RGB bitmaps are supported");
+
+       *w=bh.biWidth;  *h=bh.biHeight;  srcps=bh.biBitCount/8;
+       if(*h<0) {*h=-(*h);  srcbottomup=0;}
+       srcpitch=(((*w)*srcps)+3)&(~3);
+       dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
+
+       if(srcpitch*(*h)+bh.bfOffBits!=bh.bfSize) _throw("Corrupt bitmap header");
+       if((tempbuf=(unsigned char *)malloc(srcpitch*(*h)))==NULL
+       || (*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
+               _throw("Memory allocation error");
+       if(lseek(fd, (long)bh.bfOffBits, SEEK_SET)!=(long)bh.bfOffBits)
+               _throw(strerror(errno));
+       _unix(bytesread=read(fd, tempbuf, srcpitch*(*h)));
+       if(bytesread!=srcpitch*(*h)) _throw("Read error");
+
+       pixelconvert(tempbuf, BMP_BGR, srcpitch, *buf, f, dstpitch, *w, *h, 
+               srcbottomup!=dstbottomup);
+
+       finally:
+       if(tempbuf) free(tempbuf);
+       if(fd!=-1) close(fd);
+       return retcode;
+}
+
+#define writeme(fd, addr, size) \
+       if((byteswritten=write(fd, addr, (size)))==-1) _throw(strerror(errno)); \
+       if(byteswritten!=(size)) _throw("Write error");
+
+int saveppm(char *filename, unsigned char *buf, int w, int h,
+       enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
+{
+       FILE *fs=NULL;  int retcode=0;
+       unsigned char *tempbuf=NULL;
+
+       if((fs=fopen(filename, "wb"))==NULL) _throw(strerror(errno));
+       if(fprintf(fs, "P6\n")<1) _throw("Write error");
+       if(fprintf(fs, "%d %d\n", w, h)<1) _throw("Write error");
+       if(fprintf(fs, "255\n")<1) _throw("Write error");
+
+       if((tempbuf=(unsigned char *)malloc(w*h*3))==NULL)
+               _throw("Memory allocation error");
+
+       pixelconvert(buf, f, srcpitch, tempbuf, BMP_RGB, w*3, w, h, 
+               srcbottomup);
+
+       if((fwrite(tempbuf, w*h*3, 1, fs))!=1) _throw("Write error");
+
+       finally:
+       if(tempbuf) free(tempbuf);
+       if(fs) fclose(fs);
+       return retcode;
+}
+
+int savebmp(char *filename, unsigned char *buf, int w, int h,
+       enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
+{
+       int fd=-1, byteswritten, dstpitch, retcode=0;
+       int flags=O_RDWR|O_CREAT|O_TRUNC;
+       unsigned char *tempbuf=NULL;  char *temp;
+       bmphdr bh;  int mode;
+
+       #ifdef _WIN32
+       flags|=O_BINARY;  mode=_S_IREAD|_S_IWRITE;
+       #else
+       mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+       #endif
+       if(!filename || !buf || w<1 || h<1 || f<0 || f>BMPPIXELFORMATS-1 || srcpitch<0)
+               _throw("bad argument to savebmp()");
+
+       if(srcpitch==0) srcpitch=w*ps[f];
+
+       if((temp=strrchr(filename, '.'))!=NULL)
+       {
+               if(!stricmp(temp, ".ppm"))
+                       return saveppm(filename, buf, w, h, f, srcpitch, srcbottomup);
+       }
+
+       _unix(fd=open(filename, flags, mode));
+       dstpitch=((w*3)+3)&(~3);
+
+       bh.bfType=0x4d42;
+       bh.bfSize=BMPHDRSIZE+dstpitch*h;
+       bh.bfReserved1=0;  bh.bfReserved2=0;
+       bh.bfOffBits=BMPHDRSIZE;
+       bh.biSize=40;
+       bh.biWidth=w;  bh.biHeight=h;
+       bh.biPlanes=0;  bh.biBitCount=24;
+       bh.biCompression=BI_RGB;  bh.biSizeImage=0;
+       bh.biXPelsPerMeter=0;  bh.biYPelsPerMeter=0;
+       bh.biClrUsed=0;  bh.biClrImportant=0;
+
+       if(!littleendian())
+       {
+               bh.bfType=byteswap16(bh.bfType);
+               bh.bfSize=byteswap(bh.bfSize);
+               bh.bfOffBits=byteswap(bh.bfOffBits);
+               bh.biSize=byteswap(bh.biSize);
+               bh.biWidth=byteswap(bh.biWidth);
+               bh.biHeight=byteswap(bh.biHeight);
+               bh.biPlanes=byteswap16(bh.biPlanes);
+               bh.biBitCount=byteswap16(bh.biBitCount);
+               bh.biCompression=byteswap(bh.biCompression);
+               bh.biSizeImage=byteswap(bh.biSizeImage);
+               bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
+               bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
+               bh.biClrUsed=byteswap(bh.biClrUsed);
+               bh.biClrImportant=byteswap(bh.biClrImportant);
+       }
+
+       writeme(fd, &bh.bfType, sizeof(unsigned short));
+       writeme(fd, &bh.bfSize, sizeof(unsigned int));
+       writeme(fd, &bh.bfReserved1, sizeof(unsigned short));
+       writeme(fd, &bh.bfReserved2, sizeof(unsigned short));
+       writeme(fd, &bh.bfOffBits, sizeof(unsigned int));
+       writeme(fd, &bh.biSize, sizeof(unsigned int));
+       writeme(fd, &bh.biWidth, sizeof(int));
+       writeme(fd, &bh.biHeight, sizeof(int));
+       writeme(fd, &bh.biPlanes, sizeof(unsigned short));
+       writeme(fd, &bh.biBitCount, sizeof(unsigned short));
+       writeme(fd, &bh.biCompression, sizeof(unsigned int));
+       writeme(fd, &bh.biSizeImage, sizeof(unsigned int));
+       writeme(fd, &bh.biXPelsPerMeter, sizeof(int));
+       writeme(fd, &bh.biYPelsPerMeter, sizeof(int));
+       writeme(fd, &bh.biClrUsed, sizeof(unsigned int));
+       writeme(fd, &bh.biClrImportant, sizeof(unsigned int));
+
+       if((tempbuf=(unsigned char *)malloc(dstpitch*h))==NULL)
+               _throw("Memory allocation error");
+
+       pixelconvert(buf, f, srcpitch, tempbuf, BMP_BGR, dstpitch, w, h, 
+               !srcbottomup);
+
+       if((byteswritten=write(fd, tempbuf, dstpitch*h))!=dstpitch*h)
+               _throw(strerror(errno));
+
+       finally:
+       if(tempbuf) free(tempbuf);
+       if(fd!=-1) close(fd);
+       return retcode;
+}
+
+const char *bmpgeterr(void)
+{
+       return __bmperr;
+}
diff --git a/common/jpeg/bmp.h b/common/jpeg/bmp.h
new file mode 100644 (file)
index 0000000..437d327
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+*/
+
+// This provides rudimentary facilities for loading and saving true color
+// BMP and PPM files
+
+#ifndef __BMP_H__
+#define __BMP_H__
+
+#define BMPPIXELFORMATS 6
+enum BMPPIXELFORMAT {BMP_RGB=0, BMP_RGBA, BMP_BGR, BMP_BGRA, BMP_ABGR, BMP_ARGB};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// This will load a Windows bitmap from a file and return a buffer with the
+// specified pixel format, scanline alignment, and orientation.  The width and
+// height are returned in w and h.
+
+int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
+       enum BMPPIXELFORMAT f, int align, int dstbottomup);
+
+// This will save a buffer with the specified pixel format, pitch, orientation,
+// width, and height as a 24-bit Windows bitmap or PPM (the filename determines
+// which format to use)
+
+int savebmp(char *filename, unsigned char *buf, int w, int h,
+       enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup);
+
+const char *bmpgeterr(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/jpeg/jpegut.c b/common/jpeg/jpegut.c
new file mode 100644 (file)
index 0000000..777cd3d
--- /dev/null
@@ -0,0 +1,384 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ * Copyright (C)2009 D. R. Commander
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "./rrtimer.h"
+#include "./turbojpeg.h"
+
+#define _catch(f) {if((f)==-1) {printf("TJPEG: %s\n", tjGetErrorStr());  goto finally;}}
+
+const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:1:1", "GRAY"};
+const char *_subnames[NUMSUBOPT]={"444", "422", "411", "GRAY"};
+
+int pixels[9][3]=
+{
+       {0, 255, 0},
+       {255, 0, 255},
+       {255, 255, 0},
+       {0, 0, 255},
+       {0, 255, 255},
+       {255, 0, 0},
+       {255, 255, 255},
+       {0, 0, 0},
+       {255, 0, 0}
+};
+
+void initbuf(unsigned char *buf, int w, int h, int ps, int flags)
+{
+       int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
+               _i, j;
+       if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
+       memset(buf, 0, w*h*ps);
+       for(_i=0; _i<16; _i++)
+       {
+               if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+               for(j=0; j<w; j++)
+               {
+                       buf[(w*i+j)*ps+roffset]=255;
+                       if(((_i/8)+(j/8))%2==0)
+                       {
+                               buf[(w*i+j)*ps+goffset]=255;
+                               buf[(w*i+j)*ps+boffset]=255;
+                       }
+               }
+       }
+       for(_i=16; _i<h; _i++)
+       {
+               if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+               for(j=0; j<w; j++)
+               {
+                       if(((_i/8)+(j/8))%2!=0)
+                       {
+                               buf[(w*i+j)*ps+roffset]=255;
+                               buf[(w*i+j)*ps+goffset]=255;
+                       }
+               }
+       }
+}
+
+int dumpbuf(unsigned char *buf, int w, int h, int ps, int flags)
+{
+       int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
+               j;
+       for(i=0; i<h; i++)
+       {
+               for(j=0; j<w; j++)
+               {
+                       printf("%.3d/%.3d/%.3d ", buf[(w*i+j)*ps+roffset],
+                               buf[(w*i+j)*ps+roffset], buf[(w*i+j)*ps+roffset]);
+               }
+               printf("\n");
+       }
+}
+
+int checkbuf(unsigned char *buf, int w, int h, int ps, int subsamp, int flags)
+{
+       int roffset=(flags&TJ_BGR)?2:0, goffset=1, boffset=(flags&TJ_BGR)?0:2, i,
+               _i, j;
+       if(flags&TJ_ALPHAFIRST) {roffset++;  goffset++;  boffset++;}
+       if(subsamp==TJ_GRAYSCALE)
+       {
+               for(_i=0; _i<16; _i++)
+               {
+                       if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+                       for(j=0; j<w; j++)
+                       {
+                               unsigned char r=buf[(w*i+j)*ps+roffset],
+                                       g=buf[(w*i+j)*ps+goffset],
+                                       b=buf[(w*i+j)*ps+boffset];
+                               if(((_i/8)+(j/8))%2==0)
+                               {
+                                       if(r<253 || g<253 || b<253) return 0;
+                               }
+                               else
+                               {
+                                       if(r<74 || r>78 || g<74 || g>78 || b<74 || b>78) return 0;
+                               }
+                       }
+               }
+               for(_i=16; _i<h; _i++)
+               {
+                       if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+                       for(j=0; j<w; j++)
+                       {
+                               unsigned char r=buf[(w*i+j)*ps+roffset],
+                                       g=buf[(w*i+j)*ps+goffset],
+                                       b=buf[(w*i+j)*ps+boffset];
+                               if(((_i/8)+(j/8))%2==0)
+                               {
+                                       if(r>2 || g>2 || b>2) return 0;
+                               }
+                               else
+                               {
+                                       if(r<224 || r>228 || g<224 || g>228 || b<224 || b>228) return 0;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               for(_i=0; _i<16; _i++)
+               {
+                       if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+                       for(j=0; j<w; j++)
+                       {
+                               if(buf[(w*i+j)*ps+roffset]<253) return 0;
+                               if(((_i/8)+(j/8))%2==0)
+                               {
+                                       if(buf[(w*i+j)*ps+goffset]<253) return 0;
+                                       if(buf[(w*i+j)*ps+boffset]<253) return 0;
+                               }
+                               else
+                               {
+                                       if(buf[(w*i+j)*ps+goffset]>2) return 0;
+                                       if(buf[(w*i+j)*ps+boffset]>2) return 0;
+                               }
+                       }
+               }
+               for(_i=16; _i<h; _i++)
+               {
+                       if(flags&TJ_BOTTOMUP) i=h-_i-1;  else i=_i;
+                       for(j=0; j<w; j++)
+                       {
+                               if(buf[(w*i+j)*ps+boffset]>2) return 0;
+                               if(((_i/8)+(j/8))%2==0)
+                               {
+                                       if(buf[(w*i+j)*ps+roffset]>2) return 0;
+                                       if(buf[(w*i+j)*ps+goffset]>2) return 0;
+                               }
+                               else
+                               {
+                                       if(buf[(w*i+j)*ps+roffset]<253) return 0;
+                                       if(buf[(w*i+j)*ps+goffset]<253) return 0;
+                               }
+                       }
+               }
+       }
+       return 1;
+}
+
+void writejpeg(unsigned char *jpegbuf, unsigned long jpgbufsize, char *filename)
+{
+       FILE *outfile=NULL;
+       if((outfile=fopen(filename, "wb"))==NULL)
+       {
+               printf("ERROR: Could not open %s for writing.\n", filename);
+               goto finally;
+       }
+       if(fwrite(jpegbuf, jpgbufsize, 1, outfile)!=1)
+       {
+               printf("ERROR: Could not write to %s.\n", filename);
+               goto finally;
+       }
+
+       finally:
+       if(outfile) fclose(outfile);
+}
+
+void gentestjpeg(tjhandle hnd, unsigned char *jpegbuf, unsigned long *size,
+       int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
+{
+       char tempstr[1024];  unsigned char *bmpbuf=NULL;
+       const char *pixformat;  double t;
+
+       if(flags&TJ_BGR)
+       {
+               if(ps==3) pixformat="BGR";
+               else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
+       }
+       else
+       {
+               if(ps==3) pixformat="RGB";
+               else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
+       }
+       printf("%s %s -> %s Q%d ... ", pixformat,
+               (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ", _subnamel[subsamp], qual);
+
+       if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
+       {
+               printf("ERROR: Could not allocate buffer\n");  goto finally;
+       }
+       initbuf(bmpbuf, w, h, ps, flags);
+       memset(jpegbuf, 0, TJBUFSIZE(w, h));
+
+       t=rrtime();
+       _catch(tjCompress(hnd, bmpbuf, w, 0, h, ps, jpegbuf, size, subsamp, qual, flags));
+       t=rrtime()-t;
+
+       sprintf(tempstr, "%s_enc_%s_%s_%sQ%d.jpg", basefilename, pixformat,
+               (flags&TJ_BOTTOMUP)? "BU":"TD", _subnames[subsamp], qual);
+       writejpeg(jpegbuf, *size, tempstr);
+       printf("Done.  %f ms\n  Result in %s\n", t*1000., tempstr);
+
+       finally:
+       if(bmpbuf) free(bmpbuf);
+}
+
+void gentestbmp(tjhandle hnd, unsigned char *jpegbuf, unsigned long jpegsize,
+       int w, int h, int ps, char *basefilename, int subsamp, int qual, int flags)
+{
+       unsigned char *bmpbuf=NULL;
+       const char *pixformat;  int _w=0, _h=0;  double t;
+
+       if(flags&TJ_BGR)
+       {
+               if(ps==3) pixformat="BGR";
+               else {if(flags&TJ_ALPHAFIRST) pixformat="ABGR";  else pixformat="BGRA";}
+       }
+       else
+       {
+               if(ps==3) pixformat="RGB";
+               else {if(flags&TJ_ALPHAFIRST) pixformat="ARGB";  else pixformat="RGBA";}
+       }
+       printf("JPEG -> %s %s ... ", pixformat, (flags&TJ_BOTTOMUP)?"Bottom-Up":"Top-Down ");
+
+       _catch(tjDecompressHeader(hnd, jpegbuf, jpegsize, &_w, &_h));
+       if(_w!=w || _h!=h)
+       {
+               printf("Incorrect JPEG header\n");  goto finally;
+       }
+
+       if((bmpbuf=(unsigned char *)malloc(w*h*ps+1))==NULL)
+       {
+               printf("ERROR: Could not allocate buffer\n");  goto finally;
+       }
+       memset(bmpbuf, 0, w*ps*h);
+
+       t=rrtime();
+       _catch(tjDecompress(hnd, jpegbuf, jpegsize, bmpbuf, w, w*ps, h, ps, flags));
+       t=rrtime()-t;
+
+       if(checkbuf(bmpbuf, w, h, ps, subsamp, flags)) printf("Passed.");
+       else {printf("FAILED!");  dumpbuf(bmpbuf, w, h, ps, flags);}
+
+       printf("  %f ms\n\n", t*1000.);
+
+       finally:
+       if(bmpbuf) free(bmpbuf);
+}
+
+void dotest(int w, int h, int ps, int subsamp, char *basefilename)
+{
+       tjhandle hnd=NULL, dhnd=NULL;  unsigned char *jpegbuf=NULL;
+       unsigned long size;
+
+       if((jpegbuf=(unsigned char *)malloc(TJBUFSIZE(w, h))) == NULL)
+       {
+               puts("ERROR: Could not allocate buffer.");  goto finally;
+       }
+
+       if((hnd=tjInitCompress())==NULL)
+               {printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());  goto finally;}
+       if((dhnd=tjInitDecompress())==NULL)
+               {printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr());  goto finally;}
+
+       gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, 0);
+       gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, 0);
+
+       gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
+       gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR);
+
+       gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
+       gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BOTTOMUP);
+
+       gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
+       gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_BGR|TJ_BOTTOMUP);
+
+       if(ps==4)
+       {
+               gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
+               gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST);
+
+               gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
+               gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR);
+
+               gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
+               gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BOTTOMUP);
+
+               gentestjpeg(hnd, jpegbuf, &size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
+               gentestbmp(dhnd, jpegbuf, size, w, h, ps, basefilename, subsamp, 100, TJ_ALPHAFIRST|TJ_BGR|TJ_BOTTOMUP);
+       }
+
+       finally:
+       if(hnd) tjDestroy(hnd);
+       if(dhnd) tjDestroy(dhnd);
+
+       if(jpegbuf) free(jpegbuf);
+}
+
+#define MAXLENGTH 2048
+
+void dotest1(void)
+{
+       int i, j, i2;  unsigned char *bmpbuf=NULL, *jpgbuf=NULL;
+       tjhandle hnd=NULL;  unsigned long size;
+       if((hnd=tjInitCompress())==NULL)
+               {printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());  goto finally;}
+       printf("Buffer size regression test\n");
+       for(j=1; j<48; j++)
+       {
+               for(i=1; i<(j==1?MAXLENGTH:48); i++)
+               {
+                       if(i%100==0) printf("%.4d x %.4d\b\b\b\b\b\b\b\b\b\b\b", i, j);
+                       if((bmpbuf=(unsigned char *)malloc(i*j*4))==NULL
+                       || (jpgbuf=(unsigned char *)malloc(TJBUFSIZE(i, j)))==NULL)
+                       {
+                               printf("Memory allocation failure\n");  goto finally;
+                       }
+                       memset(bmpbuf, 0, i*j*4);
+                       for(i2=0; i2<i*j; i2++)
+                       {
+                               bmpbuf[i2*4]=pixels[i2%9][2];
+                               bmpbuf[i2*4+1]=pixels[i2%9][1];
+                               bmpbuf[i2*2+2]=pixels[i2%9][0];
+                       }
+                       _catch(tjCompress(hnd, bmpbuf, i, i*4, j, 4,
+                               jpgbuf, &size, TJ_444, 100, TJ_BGR));
+                       free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
+
+                       if((bmpbuf=(unsigned char *)malloc(j*i*4))==NULL
+                       || (jpgbuf=(unsigned char *)malloc(TJBUFSIZE(j, i)))==NULL)
+                       {
+                               printf("Memory allocation failure\n");  goto finally;
+                       }
+                       for(i2=0; i2<j*i*4; i2++)
+                       {
+                               if(i2%2==0) bmpbuf[i2]=0xFF;
+                               else bmpbuf[i2]=0;
+                       }
+                       _catch(tjCompress(hnd, bmpbuf, j, j*4, i, 4,
+                               jpgbuf, &size, TJ_444, 100, TJ_BGR));
+                       free(bmpbuf);  bmpbuf=NULL;  free(jpgbuf);  jpgbuf=NULL;
+               }
+       }
+       printf("Done.      \n");
+
+       finally:
+       if(bmpbuf) free(bmpbuf);  if(jpgbuf) free(jpgbuf);
+       if(hnd) tjDestroy(hnd);
+}
+
+int main(int argc, char *argv[])
+{
+       dotest(35, 41, 3, TJ_444, "test");
+       dotest(35, 41, 4, TJ_444, "test");
+       dotest(35, 41, 3, TJ_GRAYSCALE, "test");
+       dotest(35, 41, 4, TJ_GRAYSCALE, "test");
+       dotest1();
+
+       return 0;
+}
diff --git a/common/jpeg/jpgtest.cxx b/common/jpeg/jpgtest.cxx
new file mode 100644 (file)
index 0000000..d0baea5
--- /dev/null
@@ -0,0 +1,382 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005, 2006 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "./bmp.h"
+#include "./rrutil.h"
+#include "./rrtimer.h"
+#include "./turbojpeg.h"
+
+#define _catch(f) {if((f)==-1) {printf("Error in %s:\n%s\n", #f, tjGetErrorStr());  goto bailout;}}
+
+int forcemmx=0, forcesse=0, forcesse2=0, forcesse3=0;
+const int _ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
+const int _flags[BMPPIXELFORMATS]={0, 0, TJ_BGR, TJ_BGR,
+       TJ_BGR|TJ_ALPHAFIRST, TJ_ALPHAFIRST};
+const int _rindex[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
+const int _gindex[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
+const int _bindex[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
+const char *_pfname[]={"RGB", "RGBA", "BGR", "BGRA", "ABGR", "ARGB"};
+const char *_subnamel[NUMSUBOPT]={"4:4:4", "4:2:2", "4:1:1", "GRAY"};
+const char *_subnames[NUMSUBOPT]={"444", "422", "411", "GRAY"};
+
+void printsigfig(double val, int figs)
+{
+       char format[80];
+       double _l=log10(val);  int l;
+       if(_l<0.)
+       {
+               l=(int)fabs(_l);
+               sprintf(format, "%%%d.%df", figs+l+2, figs+l);
+       }
+       else
+       {
+               l=(int)_l+1;
+               if(figs<=l) sprintf(format, "%%.0f");
+               else sprintf(format, "%%%d.%df", figs+1, figs-l);
+       }       
+       printf(format, val);
+}
+
+void dotest(unsigned char *srcbuf, int w, int h, BMPPIXELFORMAT pf, int bu,
+       int jpegsub, int qual, char *filename, int dotile, int useppm, int quiet)
+{
+       char tempstr[1024];
+       FILE *outfile;  tjhandle hnd;
+       unsigned char **jpegbuf=NULL, *rgbbuf=NULL;
+       rrtimer timer; double elapsed;
+       int jpgbufsize=0, i, j, tilesizex, tilesizey, numtilesx, numtilesy, ITER;
+       unsigned long *comptilesize=NULL;
+       int flags=(forcemmx?TJ_FORCEMMX:0)|(forcesse?TJ_FORCESSE:0)
+               |(forcesse2?TJ_FORCESSE2:0)|(forcesse3?TJ_FORCESSE3:0);
+       int ps=_ps[pf];
+       int pitch=w*ps;
+
+       flags |= _flags[pf];
+       if(bu) flags |= TJ_BOTTOMUP;
+
+       if((rgbbuf=(unsigned char *)malloc(pitch*h)) == NULL)
+       {
+               puts("ERROR: Could not allocate image buffer.");
+               exit(1);
+       }
+
+       if(!quiet) printf("\n>>>>>  %s (%s) <--> JPEG %s Q%d  <<<<<\n", _pfname[pf],
+               bu?"Bottom-up":"Top-down", _subnamel[jpegsub], qual);
+       if(dotile) {tilesizex=tilesizey=4;}  else {tilesizex=w;  tilesizey=h;}
+
+       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)
+               {
+                       puts("ERROR: Could not allocate image buffers.");
+                       goto bailout;
+               }
+               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)
+                       {
+                               puts("ERROR: Could not allocate image buffers.");
+                               goto bailout;
+                       }
+               }
+
+               // Compression test
+               if(quiet) printf("%s\t%s\t%s\t%d\t",  _pfname[pf], bu?"BU":"TD",
+                       _subnamel[jpegsub], qual);
+               for(i=0; i<h; i++) memcpy(&rgbbuf[pitch*i], &srcbuf[w*ps*i], w*ps);
+               if((hnd=tjInitCompress())==NULL)
+               {
+                       printf("Error in tjInitCompress():\n%s\n", tjGetErrorStr());
+                       goto bailout;
+               }
+               _catch(tjCompress(hnd, rgbbuf, tilesizex, pitch, tilesizey, ps,
+                       jpegbuf[0], &comptilesize[0], jpegsub, qual, flags));
+               ITER=0;
+               timer.start();
+               do
+               {
+                       jpgbufsize=0;  int 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);
+                                       _catch(tjCompress(hnd, &rgbbuf[pitch*i+j*ps], tempw, pitch,
+                                               temph, ps, jpegbuf[tilen], &comptilesize[tilen], jpegsub, qual,
+                                               flags));
+                                       jpgbufsize+=comptilesize[tilen];
+                                       tilen++;
+                               }
+                       }
+                       ITER++;
+               } while((elapsed=timer.elapsed())<5.);
+               _catch(tjDestroy(hnd));
+               if(quiet)
+               {
+                       if(tilesizex==w && tilesizey==h) printf("Full     \t");
+                       else printf("%-4d %-4d\t", tilesizex, tilesizey);
+                       printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
+                       printf("\t");
+                       printsigfig((double)(w*h*ps)/(double)jpgbufsize, 4);
+                       printf("\t");
+               }
+               else
+               {
+                       if(tilesizex==w && tilesizey==h) printf("\nFull image\n");
+                       else printf("\nTile size: %d x %d\n", tilesizex, tilesizey);
+                       printf("C--> Frame rate:           %f fps\n", (double)ITER/elapsed);
+                       printf("     Output image size:    %d 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.*(double)ITER/elapsed);
+                       printf("     Output bit stream:    %f Megabits/sec\n",
+                               (double)jpgbufsize*8./1000000.*(double)ITER/elapsed);
+               }
+               if(tilesizex==w && tilesizey==h)
+               {
+                       sprintf(tempstr, "%s_%sQ%d.jpg", filename, _subnames[jpegsub], qual);
+                       if((outfile=fopen(tempstr, "wb"))==NULL)
+                       {
+                               puts("ERROR: Could not open reference image");
+                               exit(1);
+                       }
+                       if(fwrite(jpegbuf[0], jpgbufsize, 1, outfile)!=1)
+                       {
+                               puts("ERROR: Could not write reference image");
+                               exit(1);
+                       }
+                       fclose(outfile);
+                       if(!quiet) printf("Reference image written to %s\n", tempstr);
+               }
+
+               // Decompression test
+               memset(rgbbuf, 127, pitch*h);  // Grey image means decompressor did nothing
+               if((hnd=tjInitDecompress())==NULL)
+               {
+                       printf("Error in tjInitDecompress():\n%s\n", tjGetErrorStr());
+                       goto bailout;
+               }
+               _catch(tjDecompress(hnd, jpegbuf[0], jpgbufsize, rgbbuf, tilesizex, pitch,
+                       tilesizey, ps, flags));
+               ITER=0;
+               timer.start();
+               do
+               {
+                       int 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);
+                                       _catch(tjDecompress(hnd, jpegbuf[tilen], comptilesize[tilen],
+                                               &rgbbuf[pitch*i+ps*j], tempw, pitch, temph, ps, flags));
+                                       tilen++;
+                               }
+                       }
+                       ITER++;
+               }       while((elapsed=timer.elapsed())<5.);
+               _catch(tjDestroy(hnd));
+               if(quiet)
+               {
+                       printsigfig((double)(w*h)/1000000.*(double)ITER/elapsed, 4);
+                       printf("\n");
+               }
+               else
+               {
+                       printf("D--> Frame rate:           %f fps\n", (double)ITER/elapsed);
+                       printf("     Dest. throughput:     %f Megapixels/sec\n",
+                               (double)(w*h)/1000000.*(double)ITER/elapsed);
+               }
+               if(tilesizex==w && tilesizey==h)
+                       sprintf(tempstr, "%s_%sQ%d_full.%s", filename, _subnames[jpegsub], qual,
+                               useppm?"ppm":"bmp");
+               else sprintf(tempstr, "%s_%sQ%d_%dx%d.%s", filename, _subnames[jpegsub],
+                       qual, tilesizex, tilesizey, useppm?"ppm":"bmp");
+               if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
+               {
+                       printf("ERROR saving bitmap: %s\n", bmpgeterr());
+                       goto bailout;
+               }
+               sprintf(strrchr(tempstr, '.'), "-err.%s", useppm?"ppm":"bmp");
+               if(!quiet)
+                       printf("Computing compression error and saving to %s.\n", tempstr);
+               if(jpegsub==TJ_GRAYSCALE)
+               {
+                       for(j=0; j<h; j++)
+                       {
+                               for(i=0; i<w*ps; i+=ps)
+                               {
+                                       int y=(int)((double)srcbuf[w*ps*j+i+_rindex[pf]]*0.299
+                                               + (double)srcbuf[w*ps*j+i+_gindex[pf]]*0.587
+                                               + (double)srcbuf[w*ps*j+i+_bindex[pf]]*0.114 + 0.5);
+                                       if(y>255) y=255;  if(y<0) y=0;
+                                       rgbbuf[pitch*j+i+_rindex[pf]]=abs(rgbbuf[pitch*j+i+_rindex[pf]]-y);
+                                       rgbbuf[pitch*j+i+_gindex[pf]]=abs(rgbbuf[pitch*j+i+_gindex[pf]]-y);
+                                       rgbbuf[pitch*j+i+_bindex[pf]]=abs(rgbbuf[pitch*j+i+_bindex[pf]]-y);
+                               }
+                       }
+               }               
+               else
+               {
+                       for(j=0; j<h; j++) for(i=0; i<w*ps; i++)
+                               rgbbuf[pitch*j+i]=abs(rgbbuf[pitch*j+i]-srcbuf[w*ps*j+i]);
+               }
+               if(savebmp(tempstr, rgbbuf, w, h, pf, pitch, bu)==-1)
+               {
+                       printf("ERROR saving bitmap: %s\n", bmpgeterr());
+                       goto bailout;
+               }
+
+               // Cleanup
+               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;}
+       } while(tilesizex<w || tilesizey<h);
+
+       if(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
+       return;
+
+       bailout:
+       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(rgbbuf) {free(rgbbuf);  rgbbuf=NULL;}
+       return;
+}
+
+
+int main(int argc, char *argv[])
+{
+       unsigned char *bmpbuf=NULL;  int w, h, i, useppm=0;
+       int qual, dotile=0, quiet=0, hiqual=-1;  char *temp;
+       BMPPIXELFORMAT pf=BMP_BGR;
+       int bu=0;
+
+       printf("\n");
+
+       if(argc<3)
+       {
+               printf("USAGE: %s <Inputfile (BMP|PPM)> <%% Quality>\n\n", argv[0]);
+               printf("       [-tile]\n");
+               printf("       Test performance of the codec when the image is encoded\n");
+               printf("       as separate tiles of varying sizes.\n\n");
+               printf("       [-forcemmx] [-forcesse] [-forcesse2] [-forcesse3]\n");
+               printf("       Force MMX, SSE, or SSE2 code paths in Intel codec\n\n");
+               printf("       [-rgb | -bgr | -rgba | -bgra | -abgr | -argb]\n");
+               printf("       Test the specified color conversion path in the codec (default: BGR)\n\n");
+               printf("       [-quiet]\n");
+               printf("       Output in tabular rather than verbose format\n\n");
+               printf("       NOTE: If the quality is specified as a range, i.e. 90-100, a separate\n");
+               printf("       test will be performed for all quality values in the range.\n");
+               exit(1);
+       }
+       if((qual=atoi(argv[2]))<1 || qual>100)
+       {
+               puts("ERROR: Quality must be between 1 and 100.");
+               exit(1);
+       }
+       if((temp=strchr(argv[2], '-'))!=NULL && strlen(temp)>1
+               && sscanf(&temp[1], "%d", &hiqual)==1 && hiqual>qual && hiqual>=1
+               && hiqual<=100) {}
+       else hiqual=qual;
+
+       if(argc>3)
+       {
+               for(i=3; i<argc; i++)
+               {
+                       if(!stricmp(argv[i], "-tile")) dotile=1;
+                       if(!stricmp(argv[i], "-forcesse3"))
+                       {
+                               printf("Using SSE3 code in Intel compressor\n");
+                               forcesse3=1;
+                       }
+                       if(!stricmp(argv[i], "-forcesse2"))
+                       {
+                               printf("Using SSE2 code in Intel compressor\n");
+                               forcesse2=1;
+                       }
+                       if(!stricmp(argv[i], "-forcesse"))
+                       {
+                               printf("Using SSE code in Intel compressor\n");
+                               forcesse=1;
+                       }
+                       if(!stricmp(argv[i], "-forcemmx"))
+                       {
+                               printf("Using MMX code in Intel compressor\n");
+                               forcemmx=1;
+                       }
+                       if(!stricmp(argv[i], "-rgb")) pf=BMP_RGB;
+                       if(!stricmp(argv[i], "-rgba")) pf=BMP_RGBA;
+                       if(!stricmp(argv[i], "-bgr")) pf=BMP_BGR;
+                       if(!stricmp(argv[i], "-bgra")) pf=BMP_BGRA;
+                       if(!stricmp(argv[i], "-abgr")) pf=BMP_ABGR;
+                       if(!stricmp(argv[i], "-argb")) pf=BMP_ARGB;
+                       if(!stricmp(argv[i], "-bottomup")) bu=1;
+                       if(!stricmp(argv[i], "-quiet")) quiet=1;
+               }
+       }
+
+       if(loadbmp(argv[1], &bmpbuf, &w, &h, pf, 1, bu)==-1)
+       {
+               printf("ERROR loading bitmap: %s\n", bmpgeterr());  exit(1);
+       }
+
+       temp=strrchr(argv[1], '.');
+       if(temp!=NULL)
+       {
+               if(!stricmp(temp, ".ppm")) useppm=1;
+               *temp='\0';
+       }
+
+       if(quiet)
+       {
+               printf("All performance values in Mpixels/sec\n\n");
+               printf("Bitmap\tBitmap\tJPEG\tJPEG\tTile Size\tCompr\tCompr\tDecomp\n");
+               printf("Format\tOrder\tFormat\tQual\t X    Y  \tPerf \tRatio\tPerf\n\n");
+       }
+
+       for(i=hiqual; i>=qual; i--)
+               dotest(bmpbuf, w, h, pf, bu, TJ_GRAYSCALE, i, argv[1], dotile, useppm, quiet);
+       if(quiet) printf("\n");
+       for(i=hiqual; i>=qual; i--)
+               dotest(bmpbuf, w, h, pf, bu, TJ_411, i, argv[1], dotile, useppm, quiet);
+       if(quiet) printf("\n");
+       for(i=hiqual; i>=qual; i--)
+               dotest(bmpbuf, w, h, pf, bu, TJ_422, i, argv[1], dotile, useppm, quiet);
+       if(quiet) printf("\n");
+       for(i=hiqual; i>=qual; i--)
+               dotest(bmpbuf, w, h, pf, bu, TJ_444, i, argv[1], dotile, useppm, quiet);
+
+       if(bmpbuf) free(bmpbuf);
+       return 0;
+}
diff --git a/common/jpeg/rrtimer.h b/common/jpeg/rrtimer.h
new file mode 100644 (file)
index 0000000..4db5e37
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#ifndef __RRTIMER_H__
+#define __RRTIMER_H__
+
+#ifdef __cplusplus
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+class rrtimer
+{
+       public:
+
+               rrtimer(void) : t1(0.0)
+               {
+                       #ifdef _WIN32
+                       highres=false;  tick=0.001;
+                       LARGE_INTEGER Frequency;
+                       if(QueryPerformanceFrequency(&Frequency)!=0)
+                       {
+                               tick=(double)1.0/(double)(Frequency.QuadPart);
+                               highres=true;
+                       }
+                       #endif
+               }
+
+               void start(void)
+               {
+                       t1=time();
+               }
+
+               double time(void)
+               {
+                       #ifdef _WIN32
+                       if(highres)
+                       {
+                               LARGE_INTEGER Time;
+                               QueryPerformanceCounter(&Time);
+                               return((double)(Time.QuadPart)*tick);
+                       }
+                       else
+                               return((double)GetTickCount()*tick);
+                       #else
+                       struct timeval __tv;
+                       gettimeofday(&__tv, (struct timezone *)NULL);
+                       return((double)(__tv.tv_sec)+(double)(__tv.tv_usec)*0.000001);
+                       #endif
+               }
+
+               double elapsed(void)
+               {
+                       return time()-t1;
+               }
+
+       private:
+
+               #ifdef _WIN32
+               bool highres;  double tick;
+               #endif
+               double t1;
+};
+
+#endif  // __cplusplus
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+__inline double rrtime(void)
+{
+       LARGE_INTEGER Frequency, Time;
+       if(QueryPerformanceFrequency(&Frequency)!=0)
+       {
+               QueryPerformanceCounter(&Time);
+               return (double)Time.QuadPart/(double)Frequency.QuadPart;
+       }
+       else return (double)GetTickCount()*0.001;
+}
+
+#else
+
+#include <sys/time.h>
+
+#ifdef sun
+#define __inline inline
+#endif
+
+static __inline double rrtime(void)
+{
+       struct timeval __tv;
+       gettimeofday(&__tv, (struct timezone *)NULL);
+       return((double)__tv.tv_sec+(double)__tv.tv_usec*0.000001);
+}
+
+#endif
+
+#endif
+
diff --git a/common/jpeg/rrutil.h b/common/jpeg/rrutil.h
new file mode 100644 (file)
index 0000000..4918120
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#ifndef __RRUTIL_H__
+#define __RRUTIL_H__
+
+#ifdef _WIN32
+       #include <windows.h>
+       #define sleep(t) Sleep((t)*1000)
+       #define usleep(t) Sleep((t)/1000)
+#else
+       #include <unistd.h>
+       #define stricmp strcasecmp
+       #define strnicmp strncasecmp
+#endif
+
+#ifndef min
+ #define min(a,b) ((a)<(b)?(a):(b))
+#endif
+
+#ifndef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#define pow2(i) (1<<(i))
+#define isPow2(x) (((x)&(x-1))==0)
+
+#ifdef sgi
+#define _SC_NPROCESSORS_CONF _SC_NPROC_CONF
+#endif
+
+#ifdef sun
+#define __inline inline
+#endif
+
+static __inline int numprocs(void)
+{
+       #ifdef _WIN32
+       DWORD ProcAff, SysAff, i;  int count=0;
+       if(!GetProcessAffinityMask(GetCurrentProcess(), &ProcAff, &SysAff)) return(1);
+       for(i=0; i<32; i++) if(ProcAff&(1<<i)) count++;
+       return(count);
+       #elif defined (__APPLE__)
+       return(1);
+       #else
+       long count=1;
+       if((count=sysconf(_SC_NPROCESSORS_CONF))!=-1) return((int)count);
+       else return(1);
+       #endif
+}
+
+#define byteswap(i) ( \
+       (((i) & 0xff000000) >> 24) | \
+       (((i) & 0x00ff0000) >>  8) | \
+       (((i) & 0x0000ff00) <<  8) | \
+       (((i) & 0x000000ff) << 24) )
+
+#define byteswap16(i) ( \
+       (((i) & 0xff00) >> 8) | \
+       (((i) & 0x00ff) << 8) )
+
+static __inline int littleendian(void)
+{
+       unsigned int value=1;
+       unsigned char *ptr=(unsigned char *)(&value);
+       if(ptr[0]==1 && ptr[3]==0) return 1;
+       else return 0;
+}
+
+#endif
diff --git a/common/jpeg/turbojpeg.h b/common/jpeg/turbojpeg.h
new file mode 100644 (file)
index 0000000..90f1278
--- /dev/null
@@ -0,0 +1,229 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005, 2006 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+#if (defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__)) && defined(_WIN32) && defined(DLLDEFINE)
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT
+#endif
+
+#define DLLCALL
+
+/* Subsampling */
+#define NUMSUBOPT 4
+
+enum {TJ_444=0, TJ_422, TJ_411, TJ_GRAYSCALE};
+
+/* Flags */
+#define TJ_BGR       1
+#define TJ_BOTTOMUP  2
+#define TJ_FORCEMMX  8   /* Force IPP to use MMX code even if SSE available */
+#define TJ_FORCESSE  16  /* Force IPP to use SSE1 code even if SSE2 available */
+#define TJ_FORCESSE2 32  /* Force IPP to use SSE2 code (useful if auto-detect is not working properly) */
+#define TJ_ALPHAFIRST 64 /* BGR buffer is ABGR and RGB buffer is ARGB */
+#define TJ_FORCESSE3 128 /* Force IPP to use SSE3 code (useful if auto-detect is not working properly) */
+
+typedef void* tjhandle;
+
+#define TJPAD(p) (((p)+3)&(~3))
+#ifndef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* API follows */
+
+
+/*
+  tjhandle tjInitCompress(void)
+
+  Creates a new JPEG compressor 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
+  compress an image, because this will cause performance to suffer.
+
+  RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitCompress(void);
+
+
+/*
+  int tjCompress(tjhandle j,
+     unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+     unsigned char *dstbuf, unsigned long *size,
+     int jpegsubsamp, int jpegqual, int flags)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitCompress()
+  [INPUT] srcbuf = pointer to user-allocated image buffer containing pixels in
+     RGB(A) or BGR(A) form
+  [INPUT] width =  width (in pixels) of the source image
+  [INPUT] pitch = bytes per line of the source image (width*pixelsize if the
+     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+     is padded to the nearest 32-bit boundary, such as is the case for Windows
+     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
+     as long as the pitch is greater than 0.)
+  [INPUT] height = height (in pixels) of the source image
+  [INPUT] pixelsize = size (in bytes) of each pixel in the source image
+     RGBA and BGRA: 4, RGB and BGR: 3
+  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+     the JPEG image.  Use the macro TJBUFSIZE(width, height) to determine
+     the appropriate size for this buffer based on the image width and height.
+  [OUTPUT] size = pointer to unsigned long which receives the size (in bytes)
+     of the compressed image
+  [INPUT] jpegsubsamp = Specifies either 4:1:1, 4:2:2, or 4:4:4 subsampling.
+     When the image is converted from the RGB to YCbCr colorspace as part of the
+     JPEG compression process, every other Cb and Cr (chrominance) pixel can be
+     discarded to produce a smaller image with little perceptible loss of
+     image clarity (the human eye is more sensitive to small changes in
+     brightness than small changes in color.)
+
+     TJ_411: 4:1:1 subsampling.  Discards every other Cb, Cr pixel in both
+        horizontal and vertical directions.
+     TJ_422: 4:2:2 subsampling.  Discards every other Cb, Cr pixel only in
+        the horizontal direction.
+     TJ_444: no subsampling.
+     TJ_GRAYSCALE: Generate grayscale JPEG image
+
+  [INPUT] jpegqual = JPEG quality (an integer between 0 and 100 inclusive.)
+  [INPUT] flags = the bitwise OR of one or more of the following
+
+     TJ_BGR: The components of each pixel in the source image are stored in
+        B,G,R order, not R,G,B
+     TJ_BOTTOMUP: The source image is stored in bottom-up (Windows) order,
+        not top-down
+     TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+     TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+     TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+     TJ_FORCESSE3: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE3 code (bypass CPU auto-detection)
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjCompress(tjhandle j,
+       unsigned char *srcbuf, int width, int pitch, int height, int pixelsize,
+       unsigned char *dstbuf, unsigned long *size,
+       int jpegsubsamp, int jpegqual, int flags);
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height);
+
+/*
+  tjhandle tjInitDecompress(void)
+
+  Creates a new JPEG decompressor 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
+  decompress an image, because this will cause performance to suffer.
+
+  RETURNS: NULL on error
+*/
+DLLEXPORT tjhandle DLLCALL tjInitDecompress(void);
+
+
+/*
+  int tjDecompressHeader(tjhandle j,
+     unsigned char *srcbuf, unsigned long size,
+     int *width, int *height)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitDecompress()
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+     to decompress
+  [INPUT] size = size of the JPEG image buffer (in bytes)
+  [OUTPUT] width = width (in pixels) of the JPEG image
+  [OUTPUT] height = height (in pixels) of the JPEG image
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle j,
+       unsigned char *srcbuf, unsigned long size,
+       int *width, int *height);
+
+
+/*
+  int tjDecompress(tjhandle j,
+     unsigned char *srcbuf, unsigned long size,
+     unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+     int flags)
+
+  [INPUT] j = instance handle previously returned from a call to
+     tjInitDecompress()
+  [INPUT] srcbuf = pointer to a user-allocated buffer containing the JPEG image
+     to decompress
+  [INPUT] size = size of the JPEG image buffer (in bytes)
+  [INPUT] dstbuf = pointer to user-allocated image buffer which will receive
+     the bitmap image.  This buffer should normally be pitch*height
+     bytes in size, although this pointer may also be used to decompress into
+     a specific region of a larger buffer.
+  [INPUT] width =  width (in pixels) of the destination image
+  [INPUT] pitch = bytes per line of the destination image (width*pixelsize if the
+     bitmap is unpadded, else TJPAD(width*pixelsize) if each line of the bitmap
+     is padded to the nearest 32-bit boundary, such as is the case for Windows
+     bitmaps.  You can also be clever and use this parameter to skip lines, etc.,
+     as long as the pitch is greater than 0.)
+  [INPUT] height = height (in pixels) of the destination image
+  [INPUT] pixelsize = size (in bytes) of each pixel in the destination image
+     RGBA/RGBx and BGRA/BGRx: 4, RGB and BGR: 3
+  [INPUT] flags = the bitwise OR of one or more of the following
+
+     TJ_BGR: The components of each pixel in the destination image should be
+        written in B,G,R order, not R,G,B
+     TJ_BOTTOMUP: The destination image should be stored in bottom-up
+        (Windows) order, not top-down
+     TJ_FORCEMMX: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use MMX code (bypass CPU auto-detection)
+     TJ_FORCESSE: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE code (bypass CPU auto-detection)
+     TJ_FORCESSE2: Valid only for the Intel Performance Primitives implementation
+        of this codec-- force IPP to use SSE2 code (bypass CPU auto-detection)
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDecompress(tjhandle j,
+       unsigned char *srcbuf, unsigned long size,
+       unsigned char *dstbuf, int width, int pitch, int height, int pixelsize,
+       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()
+
+  RETURNS: 0 on success, -1 on error
+*/
+DLLEXPORT int DLLCALL tjDestroy(tjhandle h);
+
+
+/*
+  char *tjGetErrorStr(void)
+  
+  Returns a descriptive error message explaining why the last command failed
+*/
+DLLEXPORT char* DLLCALL tjGetErrorStr(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/common/jpeg/turbojpegl.c b/common/jpeg/turbojpegl.c
new file mode 100644 (file)
index 0000000..3f03aed
--- /dev/null
@@ -0,0 +1,352 @@
+/* Copyright (C)2004 Landmark Graphics Corporation
+ * Copyright (C)2005 Sun Microsystems, Inc.
+ *
+ * This library is free software and may be redistributed and/or modified under
+ * the terms of the wxWindows Library License, Version 3.1 or (at your option)
+ * any later version.  The full license is in the LICENSE.txt file included
+ * with this distribution.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * wxWindows Library License for more details.
+ */
+
+// This implements a JPEG compressor/decompressor using the libjpeg API
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#include <setjmp.h>
+#include "./turbojpeg.h"
+
+
+// Error handling
+
+static char lasterror[JMSG_LENGTH_MAX]="No error";
+
+typedef struct _error_mgr
+{
+       struct jpeg_error_mgr pub;
+       jmp_buf jb;
+} error_mgr;
+
+static void my_error_exit(j_common_ptr cinfo)
+{
+       error_mgr *myerr = (error_mgr *)cinfo->err;
+       (*cinfo->err->output_message)(cinfo);
+       longjmp(myerr->jb, 1);
+}
+
+static void my_output_message(j_common_ptr cinfo)
+{
+       (*cinfo->err->format_message)(cinfo, lasterror);
+}
+
+
+// Global structures, macros, etc.
+
+typedef struct _jpgstruct
+{
+       struct jpeg_compress_struct cinfo;
+       struct jpeg_decompress_struct dinfo;
+       struct jpeg_destination_mgr jdms;
+       struct jpeg_source_mgr jsms;
+       error_mgr jerr;
+       int initc, initd;
+} jpgstruct;
+
+static const int hsampfactor[NUMSUBOPT]={1, 2, 2, 1};
+static const int vsampfactor[NUMSUBOPT]={1, 1, 2, 1};
+
+#define _throw(c) {sprintf(lasterror, "%s", c);  return -1;}
+#define _catch(f) {if((f)==-1) return -1;}
+#define checkhandle(h) jpgstruct *j=(jpgstruct *)h; \
+       if(!j) _throw("Invalid handle");
+
+
+// CO
+
+static boolean empty_output_buffer(struct jpeg_compress_struct *cinfo)
+{
+       ERREXIT(cinfo, JERR_BUFFER_SIZE);
+       return TRUE;
+}
+
+static void destination_noop(struct jpeg_compress_struct *cinfo)
+{
+}
+
+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));
+       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;
+
+       if(setjmp(j->jerr.jb))
+       { // this will execute if LIBJPEG has an error
+               if(j) free(j);  return NULL;
+  }
+
+       jpeg_create_compress(&j->cinfo);
+       j->cinfo.dest=&j->jdms;
+       j->jdms.init_destination=destination_noop;
+       j->jdms.empty_output_buffer=empty_output_buffer;
+       j->jdms.term_destination=destination_noop;
+
+       j->initc=1;
+       return (tjhandle)j;
+}
+
+DLLEXPORT unsigned long DLLCALL TJBUFSIZE(int width, int height)
+{
+       // This allows enough room in case the image doesn't compress
+       return ((width+15)&(~15)) * ((height+15)&(~15)) * 6 + 2048;
+}
+
+DLLEXPORT int DLLCALL tjCompress(tjhandle h,
+       unsigned char *srcbuf, int width, int pitch, int height, int ps,
+       unsigned char *dstbuf, unsigned long *size,
+       int jpegsub, int qual, int flags)
+{
+       int i;  JSAMPROW *row_pointer=NULL;
+
+       checkhandle(h);
+
+       if(srcbuf==NULL || width<=0 || pitch<0 || height<=0
+               || dstbuf==NULL || size==NULL
+               || jpegsub<0 || jpegsub>=NUMSUBOPT || qual<0 || qual>100)
+               _throw("Invalid argument in tjCompress()");
+       if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
+       if(!j->initc) _throw("Instance has not been initialized for compression");
+
+       if(pitch==0) pitch=width*ps;
+
+       j->cinfo.image_width = width;
+       j->cinfo.image_height = height;
+       j->cinfo.input_components = ps;
+
+       #if JCS_EXTENSIONS==1
+       j->cinfo.in_color_space = JCS_EXT_RGB;
+       if(ps==3 && (flags&TJ_BGR))
+               j->cinfo.in_color_space = JCS_EXT_BGR;
+       else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
+               j->cinfo.in_color_space = JCS_EXT_RGBX;
+       else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
+               j->cinfo.in_color_space = JCS_EXT_BGRX;
+       else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
+               j->cinfo.in_color_space = JCS_EXT_XBGR;
+       else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
+               j->cinfo.in_color_space = JCS_EXT_XRGB;
+       #else
+       #error "TurboJPEG requires JPEG colorspace extensions"
+       #endif
+
+       if(setjmp(j->jerr.jb))
+       {  // this will execute if LIBJPEG has an error
+               if(row_pointer) free(row_pointer);
+               return -1;
+  }
+
+       jpeg_set_defaults(&j->cinfo);
+
+       jpeg_set_quality(&j->cinfo, qual, TRUE);
+       if(jpegsub==TJ_GRAYSCALE)
+               jpeg_set_colorspace(&j->cinfo, JCS_GRAYSCALE);
+       else
+               jpeg_set_colorspace(&j->cinfo, JCS_YCbCr);
+       j->cinfo.dct_method = JDCT_FASTEST;
+
+       j->cinfo.comp_info[0].h_samp_factor=hsampfactor[jpegsub];
+       j->cinfo.comp_info[1].h_samp_factor=1;
+       j->cinfo.comp_info[2].h_samp_factor=1;
+       j->cinfo.comp_info[0].v_samp_factor=vsampfactor[jpegsub];
+       j->cinfo.comp_info[1].v_samp_factor=1;
+       j->cinfo.comp_info[2].v_samp_factor=1;
+
+       j->jdms.next_output_byte = dstbuf;
+       j->jdms.free_in_buffer = TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height);
+
+       if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
+               _throw("Memory allocation failed in tjInitCompress()");
+       for(i=0; i<height; i++)
+       {
+               if(flags&TJ_BOTTOMUP) row_pointer[i]= &srcbuf[(height-i-1)*pitch];
+               else row_pointer[i]= &srcbuf[i*pitch];
+       }
+       jpeg_start_compress(&j->cinfo, TRUE);
+       while(j->cinfo.next_scanline<j->cinfo.image_height)
+       {
+               jpeg_write_scanlines(&j->cinfo, &row_pointer[j->cinfo.next_scanline],
+                       j->cinfo.image_height-j->cinfo.next_scanline);
+       }
+       jpeg_finish_compress(&j->cinfo);
+       *size=TJBUFSIZE(j->cinfo.image_width, j->cinfo.image_height)-(j->jdms.free_in_buffer);
+
+       if(row_pointer) free(row_pointer);
+       return 0;
+}
+
+
+// DEC
+
+static boolean fill_input_buffer (struct jpeg_decompress_struct *dinfo)
+{
+       ERREXIT(dinfo, JERR_BUFFER_SIZE);
+       return TRUE;
+}
+
+static void skip_input_data (struct jpeg_decompress_struct *dinfo, long num_bytes)
+{
+       dinfo->src->next_input_byte += (size_t) num_bytes;
+       dinfo->src->bytes_in_buffer -= (size_t) num_bytes;
+}
+
+static void source_noop (struct jpeg_decompress_struct *dinfo)
+{
+}
+
+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));
+       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;
+
+       if(setjmp(j->jerr.jb))
+       { // this will execute if LIBJPEG has an error
+               free(j);  return NULL;
+  }
+
+       jpeg_create_decompress(&j->dinfo);
+       j->dinfo.src=&j->jsms;
+       j->jsms.init_source=source_noop;
+       j->jsms.fill_input_buffer = fill_input_buffer;
+       j->jsms.skip_input_data = skip_input_data;
+       j->jsms.resync_to_restart = jpeg_resync_to_restart;
+       j->jsms.term_source = source_noop;
+
+       j->initd=1;
+       return (tjhandle)j;
+}
+
+
+DLLEXPORT int DLLCALL tjDecompressHeader(tjhandle h,
+       unsigned char *srcbuf, unsigned long size,
+       int *width, int *height)
+{
+       checkhandle(h);
+
+       if(srcbuf==NULL || size<=0 || width==NULL || height==NULL)
+               _throw("Invalid argument in tjDecompressHeader()");
+       if(!j->initd) _throw("Instance has not been initialized for decompression");
+
+       if(setjmp(j->jerr.jb))
+       {  // this will execute if LIBJPEG has an error
+               return -1;
+       }
+
+       j->jsms.bytes_in_buffer = size;
+       j->jsms.next_input_byte = srcbuf;
+
+       jpeg_read_header(&j->dinfo, TRUE);
+
+       *width=j->dinfo.image_width;  *height=j->dinfo.image_height;
+
+       jpeg_abort_decompress(&j->dinfo);
+
+       if(*width<1 || *height<1) _throw("Invalid data returned in header");
+       return 0;
+}
+
+
+DLLEXPORT int DLLCALL tjDecompress(tjhandle h,
+       unsigned char *srcbuf, unsigned long size,
+       unsigned char *dstbuf, int width, int pitch, int height, int ps,
+       int flags)
+{
+       int i;  JSAMPROW *row_pointer=NULL;
+
+       checkhandle(h);
+
+       if(srcbuf==NULL || size<=0
+               || dstbuf==NULL || width<=0 || pitch<0 || height<=0)
+               _throw("Invalid argument in tjDecompress()");
+       if(ps!=3 && ps!=4) _throw("This compressor can only take 24-bit or 32-bit RGB input");
+       if(!j->initd) _throw("Instance has not been initialized for decompression");
+
+       if(pitch==0) pitch=width*ps;
+
+       if(setjmp(j->jerr.jb))
+       {  // this will execute if LIBJPEG has an error
+               if(row_pointer) free(row_pointer);
+               return -1;
+  }
+
+       j->jsms.bytes_in_buffer = size;
+       j->jsms.next_input_byte = srcbuf;
+
+       jpeg_read_header(&j->dinfo, TRUE);
+
+       if((row_pointer=(JSAMPROW *)malloc(sizeof(JSAMPROW)*height))==NULL)
+               _throw("Memory allocation failed in tjInitDecompress()");
+       for(i=0; i<height; i++)
+       {
+               if(flags&TJ_BOTTOMUP) row_pointer[i]= &dstbuf[(height-i-1)*pitch];
+               else row_pointer[i]= &dstbuf[i*pitch];
+       }
+
+       #if JCS_EXTENSIONS==1
+       j->dinfo.out_color_space = JCS_EXT_RGB;
+       if(ps==3 && (flags&TJ_BGR))
+               j->dinfo.out_color_space = JCS_EXT_BGR;
+       else if(ps==4 && !(flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
+               j->dinfo.out_color_space = JCS_EXT_RGBX;
+       else if(ps==4 && (flags&TJ_BGR) && !(flags&TJ_ALPHAFIRST))
+               j->dinfo.out_color_space = JCS_EXT_BGRX;
+       else if(ps==4 && (flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
+               j->dinfo.out_color_space = JCS_EXT_XBGR;
+       else if(ps==4 && !(flags&TJ_BGR) && (flags&TJ_ALPHAFIRST))
+               j->dinfo.out_color_space = JCS_EXT_XRGB;
+       #else
+       #error "TurboJPEG requires JPEG colorspace extensions"
+       #endif
+
+       jpeg_start_decompress(&j->dinfo);
+       while(j->dinfo.output_scanline<j->dinfo.output_height)
+       {
+               jpeg_read_scanlines(&j->dinfo, &row_pointer[j->dinfo.output_scanline],
+                       j->dinfo.output_height-j->dinfo.output_scanline);
+       }
+       jpeg_finish_decompress(&j->dinfo);
+
+       if(row_pointer) free(row_pointer);
+       return 0;
+}
+
+
+// General
+
+DLLEXPORT char* DLLCALL tjGetErrorStr(void)
+{
+       return lasterror;
+}
+
+DLLEXPORT int DLLCALL tjDestroy(tjhandle h)
+{
+       checkhandle(h);
+       if(setjmp(j->jerr.jb)) return -1;
+       if(j->initc) jpeg_destroy_compress(&j->cinfo);
+       if(j->initd) jpeg_destroy_decompress(&j->dinfo);
+       free(j);
+       return 0;
+}