1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup imbuf
22  */
23 
24 #include <math.h>
25 
26 #include "BLI_fileops.h"
27 #include "BLI_utildefines.h"
28 
29 #include "imbuf.h"
30 
31 #include "IMB_filetype.h"
32 #include "IMB_imbuf.h"
33 #include "IMB_imbuf_types.h"
34 
35 #include "IMB_colormanagement.h"
36 #include "IMB_colormanagement_intern.h"
37 
38 /* Some code copied from article on microsoft.com,
39  * copied here for enhanced BMP support in the future:
40  * http://www.microsoft.com/msj/defaultframe.asp?page=/msj/0197/mfcp1/mfcp1.htm&nav=/msj/0197/newnav.htm
41  */
42 
43 typedef struct BMPINFOHEADER {
44   uint biSize;
45   uint biWidth;
46   uint biHeight;
47   ushort biPlanes;
48   ushort biBitCount;
49   uint biCompression;
50   uint biSizeImage;
51   uint biXPelsPerMeter;
52   uint biYPelsPerMeter;
53   uint biClrUsed;
54   uint biClrImportant;
55 } BMPINFOHEADER;
56 
57 #if 0
58 typedef struct BMPHEADER {
59   ushort biType;
60   uint biSize;
61   ushort biRes1;
62   ushort biRes2;
63   uint biOffBits;
64 } BMPHEADER;
65 #endif
66 
67 #define BMP_FILEHEADER_SIZE 14
68 
69 #define CHECK_HEADER_FIELD(_mem, _field) ((_mem[0] == _field[0]) && (_mem[1] == _field[1]))
70 #define CHECK_HEADER_FIELD_BMP(_mem) \
71   (CHECK_HEADER_FIELD(_mem, "BM") || CHECK_HEADER_FIELD(_mem, "BA") || \
72    CHECK_HEADER_FIELD(_mem, "CI") || CHECK_HEADER_FIELD(_mem, "CP") || \
73    CHECK_HEADER_FIELD(_mem, "IC") || CHECK_HEADER_FIELD(_mem, "PT"))
74 
checkbmp(const uchar * mem)75 static int checkbmp(const uchar *mem)
76 {
77 
78   int ret_val = 0;
79   BMPINFOHEADER bmi;
80   uint u;
81 
82   if (mem) {
83     if (CHECK_HEADER_FIELD_BMP(mem)) {
84       /* skip fileheader */
85       mem += BMP_FILEHEADER_SIZE;
86     }
87     else {
88       return 0;
89     }
90 
91     /* for systems where an int needs to be 4 bytes aligned */
92     memcpy(&bmi, mem, sizeof(bmi));
93 
94     u = LITTLE_LONG(bmi.biSize);
95     /* we only support uncompressed images for now. */
96     if (u >= sizeof(BMPINFOHEADER)) {
97       if (bmi.biCompression == 0) {
98         u = LITTLE_SHORT(bmi.biBitCount);
99         if (u > 0 && u <= 32) {
100           ret_val = 1;
101         }
102       }
103     }
104   }
105 
106   return ret_val;
107 }
108 
imb_is_a_bmp(const uchar * buf)109 int imb_is_a_bmp(const uchar *buf)
110 {
111   return checkbmp(buf);
112 }
113 
imb_bmp_decode(const uchar * mem,size_t size,int flags,char colorspace[IM_MAX_SPACE])114 ImBuf *imb_bmp_decode(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
115 {
116   ImBuf *ibuf = NULL;
117   BMPINFOHEADER bmi;
118   int x, y, depth, ibuf_depth, skip;
119   const uchar *bmp;
120   uchar *rect;
121   ushort col;
122   double xppm, yppm;
123   bool top_to_bottom = false;
124 
125   (void)size; /* unused */
126 
127   if (checkbmp(mem) == 0) {
128     return NULL;
129   }
130 
131   colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
132 
133   bmp = mem + LITTLE_LONG(*(int *)(mem + 10));
134 
135   if (CHECK_HEADER_FIELD_BMP(mem)) {
136     /* skip fileheader */
137     mem += BMP_FILEHEADER_SIZE;
138   }
139   else {
140     return NULL;
141   }
142 
143   /* for systems where an int needs to be 4 bytes aligned */
144   memcpy(&bmi, mem, sizeof(bmi));
145 
146   skip = LITTLE_LONG(bmi.biSize);
147   x = LITTLE_LONG(bmi.biWidth);
148   y = LITTLE_LONG(bmi.biHeight);
149   depth = LITTLE_SHORT(bmi.biBitCount);
150   xppm = LITTLE_LONG(bmi.biXPelsPerMeter);
151   yppm = LITTLE_LONG(bmi.biYPelsPerMeter);
152 
153   if (depth <= 8) {
154     ibuf_depth = 24;
155   }
156   else {
157     ibuf_depth = depth;
158   }
159 
160   if (y < 0) {
161     /* Negative height means bitmap is stored top-to-bottom... */
162     y = -y;
163     top_to_bottom = true;
164   }
165 
166 #if 0
167   printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, depth, bmi.biBitCount);
168 #endif
169 
170   if (flags & IB_test) {
171     ibuf = IMB_allocImBuf(x, y, ibuf_depth, 0);
172   }
173   else {
174     ibuf = IMB_allocImBuf(x, y, ibuf_depth, IB_rect);
175     if (!ibuf) {
176       return NULL;
177     }
178 
179     rect = (uchar *)ibuf->rect;
180 
181     if (depth <= 8) {
182       const int rowsize = (depth * x + 31) / 32 * 4;
183       const char(*palette)[4] = (void *)(mem + skip);
184       const int startmask = ((1 << depth) - 1) << 8;
185       for (size_t i = y; i > 0; i--) {
186         int index;
187         int bitoffs = 8;
188         int bitmask = startmask;
189         int nbytes = 0;
190         const char *pcol;
191         if (top_to_bottom) {
192           rect = (uchar *)&ibuf->rect[(i - 1) * x];
193         }
194         for (size_t j = x; j > 0; j--) {
195           bitoffs -= depth;
196           bitmask >>= depth;
197           index = (bmp[0] & bitmask) >> bitoffs;
198           pcol = palette[index];
199           /* intentionally BGR -> RGB */
200           rect[0] = pcol[2];
201           rect[1] = pcol[1];
202           rect[2] = pcol[0];
203 
204           rect[3] = 255;
205           rect += 4;
206           if (bitoffs == 0) {
207             /* Advance to the next byte */
208             bitoffs = 8;
209             bitmask = startmask;
210             nbytes += 1;
211             bmp += 1;
212           }
213         }
214         /* Advance to the next row */
215         bmp += (rowsize - nbytes);
216       }
217     }
218     else if (depth == 16) {
219       for (size_t i = y; i > 0; i--) {
220         if (top_to_bottom) {
221           rect = (uchar *)&ibuf->rect[(i - 1) * x];
222         }
223         for (size_t j = x; j > 0; j--) {
224           col = bmp[0] + (bmp[1] << 8);
225           rect[0] = ((col >> 10) & 0x1f) << 3;
226           rect[1] = ((col >> 5) & 0x1f) << 3;
227           rect[2] = ((col >> 0) & 0x1f) << 3;
228 
229           rect[3] = 255;
230           rect += 4;
231           bmp += 2;
232         }
233       }
234     }
235     else if (depth == 24) {
236       const int x_pad = x % 4;
237       for (size_t i = y; i > 0; i--) {
238         if (top_to_bottom) {
239           rect = (uchar *)&ibuf->rect[(i - 1) * x];
240         }
241         for (size_t j = x; j > 0; j--) {
242           rect[0] = bmp[2];
243           rect[1] = bmp[1];
244           rect[2] = bmp[0];
245 
246           rect[3] = 255;
247           rect += 4;
248           bmp += 3;
249         }
250         /* for 24-bit images, rows are padded to multiples of 4 */
251         bmp += x_pad;
252       }
253     }
254     else if (depth == 32) {
255       for (size_t i = y; i > 0; i--) {
256         if (top_to_bottom) {
257           rect = (uchar *)&ibuf->rect[(i - 1) * x];
258         }
259         for (size_t j = x; j > 0; j--) {
260           rect[0] = bmp[2];
261           rect[1] = bmp[1];
262           rect[2] = bmp[0];
263           rect[3] = bmp[3];
264           rect += 4;
265           bmp += 4;
266         }
267       }
268     }
269   }
270 
271   if (ibuf) {
272     ibuf->ppm[0] = xppm;
273     ibuf->ppm[1] = yppm;
274     ibuf->ftype = IMB_FTYPE_BMP;
275   }
276 
277   return ibuf;
278 }
279 
280 #undef CHECK_HEADER_FIELD_BMP
281 #undef CHECK_HEADER_FIELD
282 
283 /* Couple of helper functions for writing our data */
putIntLSB(uint ui,FILE * ofile)284 static int putIntLSB(uint ui, FILE *ofile)
285 {
286   putc((ui >> 0) & 0xFF, ofile);
287   putc((ui >> 8) & 0xFF, ofile);
288   putc((ui >> 16) & 0xFF, ofile);
289   return putc((ui >> 24) & 0xFF, ofile);
290 }
291 
putShortLSB(ushort us,FILE * ofile)292 static int putShortLSB(ushort us, FILE *ofile)
293 {
294   putc((us >> 0) & 0xFF, ofile);
295   return putc((us >> 8) & 0xFF, ofile);
296 }
297 
298 /* Found write info at http://users.ece.gatech.edu/~slabaugh/personal/c/bitmapUnix.c */
imb_savebmp(ImBuf * ibuf,const char * filepath,int UNUSED (flags))299 int imb_savebmp(ImBuf *ibuf, const char *filepath, int UNUSED(flags))
300 {
301   BMPINFOHEADER infoheader;
302 
303   const size_t bytes_per_pixel = (ibuf->planes + 7) >> 3;
304   BLI_assert(bytes_per_pixel == 1 || bytes_per_pixel == 3);
305 
306   const size_t pad_bytes_per_scanline = (4 - ibuf->x * bytes_per_pixel % 4) % 4;
307   const size_t bytesize = (ibuf->x * bytes_per_pixel + pad_bytes_per_scanline) * ibuf->y;
308 
309   const uchar *data = (const uchar *)ibuf->rect;
310   FILE *ofile = BLI_fopen(filepath, "wb");
311   if (ofile == NULL) {
312     return 0;
313   }
314 
315   const bool is_grayscale = bytes_per_pixel == 1;
316   const size_t palette_size = is_grayscale ? 255 * 4 : 0; /* RGBA32 */
317   const size_t pixel_array_start = BMP_FILEHEADER_SIZE + sizeof(infoheader) + palette_size;
318 
319   putShortLSB(19778, ofile);                      /* "BM" */
320   putIntLSB(bytesize + pixel_array_start, ofile); /* Total file size */
321   putShortLSB(0, ofile);                          /* Res1 */
322   putShortLSB(0, ofile);                          /* Res2 */
323   putIntLSB(pixel_array_start, ofile);            /* offset to start of pixel array */
324 
325   putIntLSB(sizeof(infoheader), ofile);
326   putIntLSB(ibuf->x, ofile);
327   putIntLSB(ibuf->y, ofile);
328   putShortLSB(1, ofile);
329   putShortLSB(is_grayscale ? 8 : 24, ofile);
330   putIntLSB(0, ofile);
331   putIntLSB(bytesize, ofile);
332   putIntLSB(round(ibuf->ppm[0]), ofile);
333   putIntLSB(round(ibuf->ppm[1]), ofile);
334   putIntLSB(0, ofile);
335   putIntLSB(0, ofile);
336 
337   /* color palette table, which is just every grayscale color, full alpha */
338   if (is_grayscale) {
339     for (char i = 0; i < 255; i++) {
340       putc(i, ofile);
341       putc(i, ofile);
342       putc(i, ofile);
343       putc(0xFF, ofile);
344     }
345   }
346 
347   if (is_grayscale) {
348     for (size_t y = 0; y < ibuf->y; y++) {
349       for (size_t x = 0; x < ibuf->x; x++) {
350         const size_t ptr = (x + y * ibuf->x) * 4;
351         if (putc(data[ptr], ofile) == EOF) {
352           return 0;
353         }
354       }
355       /* Add padding here. */
356       for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
357         if (putc(0, ofile) == EOF) {
358           return 0;
359         }
360       }
361     }
362   }
363   else {
364     /* Need to write out padded image data in BGR format. */
365     for (size_t y = 0; y < ibuf->y; y++) {
366       for (size_t x = 0; x < ibuf->x; x++) {
367         const size_t ptr = (x + y * ibuf->x) * 4;
368         if (putc(data[ptr + 2], ofile) == EOF) {
369           return 0;
370         }
371         if (putc(data[ptr + 1], ofile) == EOF) {
372           return 0;
373         }
374         if (putc(data[ptr], ofile) == EOF) {
375           return 0;
376         }
377       }
378       /* Add padding here. */
379       for (size_t t = 0; t < pad_bytes_per_scanline; t++) {
380         if (putc(0, ofile) == EOF) {
381           return 0;
382         }
383       }
384     }
385   }
386   if (ofile) {
387     fflush(ofile);
388     fclose(ofile);
389   }
390   return 1;
391 }
392