Blender  V2.59
bmp.c
Go to the documentation of this file.
00001 /*
00002  * $Id: bmp.c 35336 2011-03-03 17:58:06Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include "BLI_blenlib.h"
00036 
00037 #include "imbuf.h"
00038 
00039 #include "IMB_imbuf_types.h"
00040 #include "IMB_imbuf.h"
00041 #include "IMB_allocimbuf.h"
00042 #include "IMB_filetype.h"
00043 
00044 /* some code copied from article on microsoft.com, copied
00045   here for enhanced BMP support in the future
00046   http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
00047 */
00048 
00049 typedef struct BMPINFOHEADER{
00050         unsigned int    biSize;
00051         unsigned int    biWidth;
00052         unsigned int    biHeight;
00053         unsigned short  biPlanes;
00054         unsigned short  biBitCount;
00055         unsigned int    biCompression;
00056         unsigned int    biSizeImage;
00057         unsigned int    biXPelsPerMeter;
00058         unsigned int    biYPelsPerMeter;
00059         unsigned int    biClrUsed;
00060         unsigned int    biClrImportant;
00061 } BMPINFOHEADER;
00062 
00063 typedef struct BMPHEADER {
00064         unsigned short biType;
00065         unsigned int biSize;
00066         unsigned short biRes1;
00067         unsigned short biRes2;
00068         unsigned int biOffBits;
00069 } BMPHEADER;
00070 
00071 #define BMP_FILEHEADER_SIZE 14
00072 
00073 static int checkbmp(unsigned char *mem)
00074 {
00075         int ret_val = 0;
00076         BMPINFOHEADER bmi;
00077         unsigned int u;
00078 
00079         if (mem) {
00080                 if ((mem[0] == 'B') && (mem[1] == 'M')) {
00081                         /* skip fileheader */
00082                         mem += BMP_FILEHEADER_SIZE;
00083                 } else {
00084                 }
00085 
00086                 /* for systems where an int needs to be 4 bytes aligned */
00087                 memcpy(&bmi, mem, sizeof(bmi));
00088 
00089                 u = LITTLE_LONG(bmi.biSize);
00090                 /* we only support uncompressed 24 or 32 bits images for now */
00091                 if (u >= sizeof(BMPINFOHEADER)) {
00092                         if ((bmi.biCompression == 0) && (bmi.biClrUsed == 0)) {
00093                                 u = LITTLE_SHORT(bmi.biBitCount);
00094                                 if (u >= 16) {
00095                                         ret_val = 1;
00096                                 }
00097                         }
00098                 }
00099         }
00100 
00101         return(ret_val);
00102 }
00103 
00104 int imb_is_a_bmp(unsigned char *buf) {
00105         
00106         return checkbmp(buf);
00107 }
00108 
00109 struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags)
00110 {
00111         struct ImBuf *ibuf = NULL;
00112         BMPINFOHEADER bmi;
00113         int x, y, depth, skip, i;
00114         unsigned char *bmp, *rect;
00115         unsigned short col;
00116         
00117         (void)size; /* unused */
00118 
00119         if (checkbmp(mem) == 0) return(NULL);
00120 
00121         if ((mem[0] == 'B') && (mem[1] == 'M')) {
00122                 /* skip fileheader */
00123                 mem += BMP_FILEHEADER_SIZE;
00124         }
00125 
00126         /* for systems where an int needs to be 4 bytes aligned */
00127         memcpy(&bmi, mem, sizeof(bmi));
00128 
00129         skip = LITTLE_LONG(bmi.biSize);
00130         x = LITTLE_LONG(bmi.biWidth);
00131         y = LITTLE_LONG(bmi.biHeight);
00132         depth = LITTLE_SHORT(bmi.biBitCount);
00133 
00134         /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, 
00135                 depth, bmi.biBitCount); */
00136         /* printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, 
00137                 depth, bmi.biBitCount); */
00138         if (flags & IB_test) {
00139                 ibuf = IMB_allocImBuf(x, y, depth, 0);
00140         } else {
00141                 ibuf = IMB_allocImBuf(x, y, depth, IB_rect);
00142                 bmp = mem + skip;
00143                 rect = (unsigned char *) ibuf->rect;
00144 
00145                 if (depth == 16) {
00146                         for (i = x * y; i > 0; i--) {
00147                                 col = bmp[0] + (bmp[1] << 8);
00148                                 rect[0] = ((col >> 10) & 0x1f) << 3;
00149                                 rect[1] = ((col >>  5) & 0x1f) << 3;
00150                                 rect[2] = ((col >>  0) & 0x1f) << 3;
00151                                 
00152                                 rect[3] = 255;
00153                                 rect += 4; bmp += 2;
00154                         }
00155 
00156                 } else if (depth == 24) {
00157                         for (i = y; i > 0; i--) {
00158                                 int j;
00159                                 for (j = x ; j > 0; j--) {
00160                                         rect[0] = bmp[2];
00161                                         rect[1] = bmp[1];
00162                                         rect[2] = bmp[0];
00163                                         
00164                                         rect[3] = 255;
00165                                         rect += 4; bmp += 3;
00166                                 }
00167                                 /* for 24-bit images, rows are padded to multiples of 4 */
00168                                 bmp += x % 4;   
00169                         }
00170                 } else if (depth == 32) {
00171                         for (i = x * y; i > 0; i--) {
00172                                 rect[0] = bmp[2];
00173                                 rect[1] = bmp[1];
00174                                 rect[2] = bmp[0];
00175                                 rect[3] = bmp[3];
00176                                 rect += 4; bmp += 4;
00177                         }
00178                 }
00179         }
00180 
00181         if (ibuf) {
00182                 ibuf->ftype = BMP;
00183                 ibuf->profile = IB_PROFILE_SRGB;
00184         }
00185         
00186         return(ibuf);
00187 }
00188 
00189 /* Couple of helper functions for writing our data */
00190 static int putIntLSB(unsigned int ui,FILE *ofile) { 
00191         putc((ui>>0)&0xFF,ofile); 
00192         putc((ui>>8)&0xFF,ofile); 
00193         putc((ui>>16)&0xFF,ofile); 
00194         return putc((ui>>24)&0xFF,ofile); 
00195 }
00196 
00197 static int putShortLSB(unsigned short us,FILE *ofile) { 
00198         putc((us>>0)&0xFF,ofile); 
00199         return putc((us>>8)&0xFF,ofile); 
00200 } 
00201 
00202 /* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
00203 int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags) {
00204 
00205         BMPINFOHEADER infoheader;
00206         int bytesize, extrabytes, x, y, t, ptr;
00207         uchar *data;
00208         FILE *ofile;
00209         
00210         (void)flags; /* unused */
00211 
00212         extrabytes = (4 - ibuf->x*3 % 4) % 4;
00213         bytesize = (ibuf->x * 3 + extrabytes) * ibuf->y;
00214 
00215         data = (uchar *) ibuf->rect;
00216         ofile = fopen(name,"wb");
00217                 if (!ofile) return 0;
00218 
00219         putShortLSB(19778,ofile); /* "BM" */
00220         putIntLSB(0,ofile); /* This can be 0 for BI_RGB bitmaps */
00221         putShortLSB(0,ofile); /* Res1 */
00222         putShortLSB(0,ofile); /* Res2 */
00223         putIntLSB(BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile); 
00224 
00225         putIntLSB(sizeof(infoheader),ofile);
00226         putIntLSB(ibuf->x,ofile);
00227         putIntLSB(ibuf->y,ofile);
00228         putShortLSB(1,ofile);
00229         putShortLSB(24,ofile);
00230         putIntLSB(0,ofile);
00231         putIntLSB(bytesize + BMP_FILEHEADER_SIZE + sizeof(infoheader),ofile);
00232         putIntLSB(0,ofile);
00233         putIntLSB(0,ofile);
00234         putIntLSB(0,ofile);
00235         putIntLSB(0,ofile);
00236 
00237         /* Need to write out padded image data in bgr format */
00238         for (y=0;y<ibuf->y;y++) {
00239                 for (x=0;x<ibuf->x;x++) {
00240                         ptr=(x + y * ibuf->x) * 4;
00241                         if (putc(data[ptr+2],ofile) == EOF) return 0;
00242                         if (putc(data[ptr+1],ofile) == EOF) return 0;
00243                         if (putc(data[ptr],ofile) == EOF) return 0;
00244                 }
00245                 /* add padding here */
00246                 for (t=0;t<extrabytes;t++) if (putc(0,ofile) == EOF) return 0;
00247         }
00248         if (ofile) {
00249                 fflush(ofile);
00250                 fclose(ofile);
00251         }
00252         return 1;
00253 }