/* Copyright (C)2004 Landmark Graphics Corporation * Copyright (C)2005 Sun Microsystems, Inc. * Copyright (C)2010, 2012 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 #include #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif #include "./tjutil.h" #include "./bmp.h" #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; } #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; jSIZE_MAX/3 || (tempbuf=(unsigned char *)calloc(*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.bfOffBitsBMPPIXELFORMATS-1 || srcpitch<0) _throw("bad argument to savebmp()"); if(srcpitch==0) srcpitch=w*ps[f]; if((temp=strrchr(filename, '.'))!=NULL) { if(!strcasecmp(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; }