Home | History | Annotate | Download | only in test
      1 /* Copyright (C)2004 Landmark Graphics Corporation
      2  * Copyright (C)2005 Sun Microsystems, Inc.
      3  * Copyright (C)2010, 2012 D. R. Commander
      4  *
      5  * This library is free software and may be redistributed and/or modified under
      6  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
      7  * any later version.  The full license is in the LICENSE.txt file included
      8  * with this distribution.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * wxWindows Library License for more details.
     14 */
     15 
     16 #include <fcntl.h>
     17 #include <sys/types.h>
     18 #include <sys/stat.h>
     19 #include <errno.h>
     20 #include <stdlib.h>
     21 #include <stdio.h>
     22 #include <string.h>
     23 #ifdef _WIN32
     24  #include <io.h>
     25 #else
     26  #include <unistd.h>
     27 #endif
     28 #include "./tjutil.h"
     29 #include "./bmp.h"
     30 
     31 #define LOG_TAG "bmp.c"
     32 #include <cutils/log.h>
     33 
     34 #define byteswap(i) ( \
     35 	(((i) & 0xff000000) >> 24) | \
     36 	(((i) & 0x00ff0000) >>  8) | \
     37 	(((i) & 0x0000ff00) <<  8) | \
     38 	(((i) & 0x000000ff) << 24) )
     39 
     40 #define byteswap16(i) ( \
     41 	(((i) & 0xff00) >> 8) | \
     42 	(((i) & 0x00ff) << 8) )
     43 
     44 static __inline int littleendian(void)
     45 {
     46 	unsigned int value=1;
     47 	unsigned char *ptr=(unsigned char *)(&value);
     48 	if(ptr[0]==1 && ptr[3]==0) return 1;
     49 	else return 0;
     50 }
     51 
     52 #ifndef BI_BITFIELDS
     53 #define BI_BITFIELDS 3L
     54 #endif
     55 #ifndef BI_RGB
     56 #define BI_RGB 0L
     57 #endif
     58 
     59 #define BMPHDRSIZE 54
     60 typedef struct _bmphdr
     61 {
     62 	unsigned short bfType;
     63 	unsigned int bfSize;
     64 	unsigned short bfReserved1, bfReserved2;
     65 	unsigned int bfOffBits;
     66 
     67 	unsigned int biSize;
     68 	int biWidth, biHeight;
     69 	unsigned short biPlanes, biBitCount;
     70 	unsigned int biCompression, biSizeImage;
     71 	int biXPelsPerMeter, biYPelsPerMeter;
     72 	unsigned int biClrUsed, biClrImportant;
     73 } bmphdr;
     74 
     75 static const char *__bmperr="No error";
     76 
     77 static const int ps[BMPPIXELFORMATS]={3, 4, 3, 4, 4, 4};
     78 static const int roffset[BMPPIXELFORMATS]={0, 0, 2, 2, 3, 1};
     79 static const int goffset[BMPPIXELFORMATS]={1, 1, 1, 1, 2, 2};
     80 static const int boffset[BMPPIXELFORMATS]={2, 2, 0, 0, 1, 3};
     81 
     82 #define _throw(m) {__bmperr=m;  retcode=-1;  goto finally;}
     83 #define _unix(f) {if((f)==-1) _throw(strerror(errno));}
     84 #define _catch(f) {if((f)==-1) {retcode=-1;  goto finally;}}
     85 
     86 #define readme(fd, addr, size) \
     87 	if((bytesread=read(fd, addr, (size)))==-1) _throw(strerror(errno)); \
     88 	if(bytesread!=(size)) _throw("Read error");
     89 
     90 void pixelconvert(unsigned char *srcbuf, enum BMPPIXELFORMAT srcformat,
     91 	int srcpitch, unsigned char *dstbuf, enum BMPPIXELFORMAT dstformat, int dstpitch,
     92 	int w, int h, int flip)
     93 {
     94 	unsigned char *srcptr, *srcptr0, *dstptr, *dstptr0;
     95 	int i, j;
     96 
     97 	srcptr=flip? &srcbuf[srcpitch*(h-1)]:srcbuf;
     98 	for(j=0, dstptr=dstbuf; j<h; j++,
     99 		srcptr+=flip? -srcpitch:srcpitch, dstptr+=dstpitch)
    100 	{
    101 		for(i=0, srcptr0=srcptr, dstptr0=dstptr; i<w; i++,
    102 			srcptr0+=ps[srcformat], dstptr0+=ps[dstformat])
    103 		{
    104 			dstptr0[roffset[dstformat]]=srcptr0[roffset[srcformat]];
    105 			dstptr0[goffset[dstformat]]=srcptr0[goffset[srcformat]];
    106 			dstptr0[boffset[dstformat]]=srcptr0[boffset[srcformat]];
    107 		}
    108 	}
    109 }
    110 
    111 int loadppm(int *fd, unsigned char **buf, int *w, int *h,
    112 	enum BMPPIXELFORMAT f, int align, int dstbottomup, int ascii)
    113 {
    114 	FILE *fs=NULL;  int retcode=0, scalefactor, dstpitch;
    115 	unsigned char *tempbuf=NULL;  char temps[255], temps2[255];
    116 	int numread=0, totalread=0, pixel[3], i, j;
    117 
    118 	if((fs=fdopen(*fd, "r"))==NULL) _throw(strerror(errno));
    119 
    120 	do
    121 	{
    122 		if(!fgets(temps, 255, fs)) _throw("Read error");
    123 		if(strlen(temps)==0 || temps[0]=='\n') continue;
    124 		if(sscanf(temps, "%s", temps2)==1 && temps2[1]=='#') continue;
    125 		switch(totalread)
    126 		{
    127 			case 0:
    128 				if((numread=sscanf(temps, "%d %d %d", w, h, &scalefactor))==EOF)
    129 					_throw("Read error");
    130 				break;
    131 			case 1:
    132 				if((numread=sscanf(temps, "%d %d", h, &scalefactor))==EOF)
    133 					_throw("Read error");
    134 				break;
    135 			case 2:
    136 				if((numread=sscanf(temps, "%d", &scalefactor))==EOF)
    137 					_throw("Read error");
    138 				break;
    139 		}
    140 		totalread+=numread;
    141 	} while(totalread<3);
    142 	if((*w)<1 || (*h)<1 || scalefactor<1) _throw("Corrupt PPM header");
    143 
    144 	dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
    145 	if((*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
    146 		_throw("Memory allocation error");
    147 	if(ascii)
    148 	{
    149 		for(j=0; j<*h; j++)
    150 		{
    151 			for(i=0; i<*w; i++)
    152 			{
    153 				if(fscanf(fs, "%d%d%d", &pixel[0], &pixel[1], &pixel[2])!=3)
    154 					_throw("Read error");
    155 				(*buf)[j*dstpitch+i*ps[f]+roffset[f]]=(unsigned char)(pixel[0]*255/scalefactor);
    156 				(*buf)[j*dstpitch+i*ps[f]+goffset[f]]=(unsigned char)(pixel[1]*255/scalefactor);
    157 				(*buf)[j*dstpitch+i*ps[f]+boffset[f]]=(unsigned char)(pixel[2]*255/scalefactor);
    158 			}
    159 		}
    160 	}
    161 	else
    162 	{
    163 		if(scalefactor!=255)
    164 			_throw("Binary PPMs must have 8-bit components");
    165 		if((tempbuf=(unsigned char *)malloc((*w)*(*h)*3))==NULL)
    166 			_throw("Memory allocation error");
    167 		if(fread(tempbuf, (*w)*(*h)*3, 1, fs)!=1) _throw("Read error");
    168 		pixelconvert(tempbuf, BMP_RGB, (*w)*3, *buf, f, dstpitch, *w, *h, dstbottomup);
    169 	}
    170 
    171 	finally:
    172 	if(fs) {fclose(fs);  *fd=-1;}
    173 	if(tempbuf) free(tempbuf);
    174 	return retcode;
    175 }
    176 
    177 
    178 int loadbmp(char *filename, unsigned char **buf, int *w, int *h,
    179 	enum BMPPIXELFORMAT f, int align, int dstbottomup)
    180 {
    181 	int fd=-1, bytesread, srcpitch, srcbottomup=1, srcps, dstpitch,
    182 		retcode=0;
    183 	unsigned char *tempbuf=NULL;
    184 	bmphdr bh;  int flags=O_RDONLY;
    185 
    186 	dstbottomup=dstbottomup? 1:0;
    187 	#ifdef _WIN32
    188 	flags|=O_BINARY;
    189 	#endif
    190 	if(!filename || !buf || !w || !h || f<0 || f>BMPPIXELFORMATS-1 || align<1)
    191 		_throw("invalid argument to loadbmp()");
    192 	if((align&(align-1))!=0)
    193 		_throw("Alignment must be a power of 2");
    194 	_unix(fd=open(filename, flags));
    195 
    196 	readme(fd, &bh.bfType, sizeof(unsigned short));
    197 	if(!littleendian())	bh.bfType=byteswap16(bh.bfType);
    198 
    199 	if(bh.bfType==0x3650)
    200 	{
    201 		_catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 0));
    202 		goto finally;
    203 	}
    204 	if(bh.bfType==0x3350)
    205 	{
    206 		_catch(loadppm(&fd, buf, w, h, f, align, dstbottomup, 1));
    207 		goto finally;
    208 	}
    209 
    210 	readme(fd, &bh.bfSize, sizeof(unsigned int));
    211 	readme(fd, &bh.bfReserved1, sizeof(unsigned short));
    212 	readme(fd, &bh.bfReserved2, sizeof(unsigned short));
    213 	readme(fd, &bh.bfOffBits, sizeof(unsigned int));
    214 	readme(fd, &bh.biSize, sizeof(unsigned int));
    215 	readme(fd, &bh.biWidth, sizeof(int));
    216 	readme(fd, &bh.biHeight, sizeof(int));
    217 	readme(fd, &bh.biPlanes, sizeof(unsigned short));
    218 	readme(fd, &bh.biBitCount, sizeof(unsigned short));
    219 	readme(fd, &bh.biCompression, sizeof(unsigned int));
    220 	readme(fd, &bh.biSizeImage, sizeof(unsigned int));
    221 	readme(fd, &bh.biXPelsPerMeter, sizeof(int));
    222 	readme(fd, &bh.biYPelsPerMeter, sizeof(int));
    223 	readme(fd, &bh.biClrUsed, sizeof(unsigned int));
    224 	readme(fd, &bh.biClrImportant, sizeof(unsigned int));
    225 
    226 	if(!littleendian())
    227 	{
    228 		bh.bfSize=byteswap(bh.bfSize);
    229 		bh.bfOffBits=byteswap(bh.bfOffBits);
    230 		bh.biSize=byteswap(bh.biSize);
    231 		bh.biWidth=byteswap(bh.biWidth);
    232 		bh.biHeight=byteswap(bh.biHeight);
    233 		bh.biPlanes=byteswap16(bh.biPlanes);
    234 		bh.biBitCount=byteswap16(bh.biBitCount);
    235 		bh.biCompression=byteswap(bh.biCompression);
    236 		bh.biSizeImage=byteswap(bh.biSizeImage);
    237 		bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
    238 		bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
    239 		bh.biClrUsed=byteswap(bh.biClrUsed);
    240 		bh.biClrImportant=byteswap(bh.biClrImportant);
    241 	}
    242 
    243 	if(bh.bfType!=0x4d42 || bh.bfOffBits<BMPHDRSIZE
    244 	|| bh.biWidth<1 || bh.biHeight==0)
    245 		_throw("Corrupt bitmap header");
    246 	if((bh.biBitCount!=24 && bh.biBitCount!=32) || bh.biCompression!=BI_RGB)
    247 		_throw("Only uncompessed RGB bitmaps are supported");
    248 
    249 	*w=bh.biWidth;  *h=bh.biHeight;  srcps=bh.biBitCount/8;
    250 	if(*h<0) {*h=-(*h);  srcbottomup=0;}
    251 	srcpitch=(((*w)*srcps)+3)&(~3);
    252 	dstpitch=(((*w)*ps[f])+(align-1))&(~(align-1));
    253 
    254 	if(srcpitch*(*h)+bh.bfOffBits!=bh.bfSize) _throw("Corrupt bitmap header");
    255 	if((tempbuf=(unsigned char *)malloc(srcpitch*(*h)))==NULL
    256 	|| (*buf=(unsigned char *)malloc(dstpitch*(*h)))==NULL)
    257 		_throw("Memory allocation error");
    258 	if(lseek(fd, (long)bh.bfOffBits, SEEK_SET)!=(long)bh.bfOffBits)
    259 		_throw(strerror(errno));
    260 	_unix(bytesread=read(fd, tempbuf, srcpitch*(*h)));
    261 	if(bytesread!=srcpitch*(*h)) _throw("Read error");
    262 
    263 	pixelconvert(tempbuf, BMP_BGR, srcpitch, *buf, f, dstpitch, *w, *h,
    264 		srcbottomup!=dstbottomup);
    265 
    266 	finally:
    267 	if(tempbuf) free(tempbuf);
    268 	if(fd!=-1) close(fd);
    269 	return retcode;
    270 }
    271 
    272 #define writeme(fd, addr, size) \
    273 	if((byteswritten=write(fd, addr, (size)))==-1) _throw(strerror(errno)); \
    274 	if(byteswritten!=(size)) _throw("Write error");
    275 
    276 int saveppm(char *filename, unsigned char *buf, int w, int h,
    277 	enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
    278 {
    279 	FILE *fs=NULL;  int retcode=0;
    280 	unsigned char *tempbuf=NULL;
    281 
    282 	if((fs=fopen(filename, "wb"))==NULL) _throw(strerror(errno));
    283 	if(fprintf(fs, "P6\n")<1) _throw("Write error");
    284 	if(fprintf(fs, "%d %d\n", w, h)<1) _throw("Write error");
    285 	if(fprintf(fs, "255\n")<1) _throw("Write error");
    286 
    287 	if((tempbuf=(unsigned char *)malloc(w*h*3))==NULL)
    288 		_throw("Memory allocation error");
    289 
    290 	pixelconvert(buf, f, srcpitch, tempbuf, BMP_RGB, w*3, w, h,
    291 		srcbottomup);
    292 
    293 	if((fwrite(tempbuf, w*h*3, 1, fs))!=1) _throw("Write error");
    294 
    295 	finally:
    296 	if(tempbuf) free(tempbuf);
    297 	if(fs) fclose(fs);
    298 	return retcode;
    299 }
    300 
    301 int savebmp(char *filename, unsigned char *buf, int w, int h,
    302 	enum BMPPIXELFORMAT f, int srcpitch, int srcbottomup)
    303 {
    304 	int fd=-1, byteswritten, dstpitch, retcode=0;
    305 	int flags=O_RDWR|O_CREAT|O_TRUNC;
    306 	unsigned char *tempbuf=NULL;  char *temp;
    307 	bmphdr bh;  int mode;
    308 
    309 	#ifdef _WIN32
    310 	flags|=O_BINARY;  mode=_S_IREAD|_S_IWRITE;
    311 	#else
    312 	mode=S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
    313 	#endif
    314 	if(!filename || !buf || w<1 || h<1 || f<0 || f>BMPPIXELFORMATS-1 || srcpitch<0)
    315 		_throw("bad argument to savebmp()");
    316 
    317 	if(srcpitch==0) srcpitch=w*ps[f];
    318 
    319 	if((temp=strrchr(filename, '.'))!=NULL)
    320 	{
    321 		if(!strcasecmp(temp, ".ppm"))
    322 			return saveppm(filename, buf, w, h, f, srcpitch, srcbottomup);
    323 	}
    324 
    325 	_unix(fd=open(filename, flags, mode));
    326 	dstpitch=((w*3)+3)&(~3);
    327 
    328 	bh.bfType=0x4d42;
    329 	bh.bfSize=BMPHDRSIZE+srcpitch*h;
    330 	bh.bfReserved1=0;  bh.bfReserved2=0;
    331 	bh.bfOffBits=BMPHDRSIZE;
    332 	bh.biSize=40;
    333 	bh.biWidth=w;  bh.biHeight=h;
    334 	bh.biPlanes=1;  bh.biBitCount=32;
    335 	bh.biCompression=BI_RGB;  bh.biSizeImage=0;
    336 	bh.biXPelsPerMeter=w;  bh.biYPelsPerMeter=h;
    337 	bh.biClrUsed=0;  bh.biClrImportant=0;
    338 
    339 	if(!littleendian())
    340 	{
    341 		bh.bfType=byteswap16(bh.bfType);
    342 		bh.bfSize=byteswap(bh.bfSize);
    343 		bh.bfOffBits=byteswap(bh.bfOffBits);
    344 		bh.biSize=byteswap(bh.biSize);
    345 		bh.biWidth=byteswap(bh.biWidth);
    346 		bh.biHeight=byteswap(bh.biHeight);
    347 		bh.biPlanes=byteswap16(bh.biPlanes);
    348 		bh.biBitCount=byteswap16(bh.biBitCount);
    349 		bh.biCompression=byteswap(bh.biCompression);
    350 		bh.biSizeImage=byteswap(bh.biSizeImage);
    351 		bh.biXPelsPerMeter=byteswap(bh.biXPelsPerMeter);
    352 		bh.biYPelsPerMeter=byteswap(bh.biYPelsPerMeter);
    353 		bh.biClrUsed=byteswap(bh.biClrUsed);
    354 		bh.biClrImportant=byteswap(bh.biClrImportant);
    355 	}
    356 
    357 	writeme(fd, &bh.bfType, sizeof(unsigned short));
    358 	writeme(fd, &bh.bfSize, sizeof(unsigned int));
    359 	writeme(fd, &bh.bfReserved1, sizeof(unsigned short));
    360 	writeme(fd, &bh.bfReserved2, sizeof(unsigned short));
    361 	writeme(fd, &bh.bfOffBits, sizeof(unsigned int));
    362 	writeme(fd, &bh.biSize, sizeof(unsigned int));
    363 	writeme(fd, &bh.biWidth, sizeof(int));
    364 	writeme(fd, &bh.biHeight, sizeof(int));
    365 	writeme(fd, &bh.biPlanes, sizeof(unsigned short));
    366 	writeme(fd, &bh.biBitCount, sizeof(unsigned short));
    367 	writeme(fd, &bh.biCompression, sizeof(unsigned int));
    368 	writeme(fd, &bh.biSizeImage, sizeof(unsigned int));
    369 	writeme(fd, &bh.biXPelsPerMeter, sizeof(int));
    370 	writeme(fd, &bh.biYPelsPerMeter, sizeof(int));
    371 	writeme(fd, &bh.biClrUsed, sizeof(unsigned int));
    372 	writeme(fd, &bh.biClrImportant, sizeof(unsigned int));
    373 
    374 #if 0
    375 	if((tempbuf=(unsigned char *)malloc(dstpitch*h))==NULL)
    376 		_throw("Memory allocation error");
    377 
    378 	pixelconvert(buf, f, srcpitch, tempbuf, BMP_BGR, dstpitch, w, h,
    379 		!srcbottomup);
    380 
    381 	if((byteswritten=write(fd, tempbuf, dstpitch*h))!=dstpitch*h)
    382 		_throw(strerror(errno));
    383 #else
    384         ALOGI("writting bitmap data (%u bytes), srcpitch = %d, h = %d", srcpitch*h, srcpitch, h);
    385 	if((byteswritten=write(fd, buf, srcpitch*h))!=srcpitch*h)
    386 		_throw(strerror(errno));
    387 #endif
    388 
    389 	finally:
    390 	if(tempbuf) free(tempbuf);
    391 	if(fd!=-1) close(fd);
    392 	return retcode;
    393 }
    394 
    395 const char *bmpgeterr(void)
    396 {
    397 	return __bmperr;
    398 }
    399