1 
2 
3 #include <stdio.h>
4 #include <string.h>
5 #include <stdlib.h>
6 #include <math.h>
7 
8 #include "../compatibility/tnz4.h"
9 #include "../compatibility/inforegion.h"
10 #include "filebmp.h"
11 /*
12 typedef unsigned long  ULONG;
13 typedef unsigned short USHORT;
14 typedef unsigned char  UCHAR;
15 typedef unsigned int   UINT;
16 typedef void IMAGERGB;
17 typedef struct {USHORT m,b,g,r;} SPIXEL;
18 #define CASE break; case
19 #define __OR      ; case
20 #define DEFAULT break; default
21 #define TRUE 1
22 #define FALSE 0
23 #define NIL (void*)0
24 */
25 
26 typedef enum {
27   BMP_NONE,
28   BMP_BW,
29   BMP_GREY16,
30   BMP_GREY16C,
31   BMP_GREY256,
32   BMP_GREY256C,
33   BMP_CMAPPED16,
34   BMP_CMAPPED16C,
35   BMP_CMAPPED256,
36   BMP_CMAPPED256C,
37   BMP_RGB
38 
39 } BMP_SUBTYPE;
40 
41 /*
42 typedef struct bmpimage {
43         int xsize,ysize;
44         LPIXEL *buffer;
45   BMP_SUBTYPE type;
46         } IMAGE;
47 */
48 
49 #define UNUSED_REDUCE_COLORS
50 
51 /*---------------------------------------------------------------------------*/
52 /*-- Defines ----------------------------------------------------------------*/
53 
54 #define BMP_BI_RGB 0
55 #define BMP_BI_RLE8 1
56 #define BMP_BI_RLE4 2
57 
58 #define BMP_WIN_OS2_OLD 12
59 #define BMP_WIN_NEW 40
60 #define BMP_OS2_NEW 64
61 
62 #define BMP_READ_INFO 1
63 #define BMP_READ_IMAGE 2
64 
65 #define BMP_FERROR(fp) (ferror(fp) || feof(fp))
66 
67 #define BMP_RMAP(x) (x & 0xe0) | ((x & 0xe0) >> 3) | ((x & 0xc0) >> 6)
68 #define BMP_GMAP(x) ((x & 0x1c) << 3) | (x & 0x1c) | ((x & 0x18) >> 3)
69 #define BMP_BMAP(x)                                                            \
70   ((x & 0x03) << 6) | ((x & 0x03) << 4) | ((x & 0x03) << 2) | (x & 0x03)
71 
72 #define BMP_RMAP16(x)                                                          \
73   ((x & 0xc0) << 0) | ((x & 0xc0) >> 2) | ((x & 0xc0) >> 4) | ((x & 0xc0) >> 6)
74 #define BMP_GMAP16(x)                                                          \
75   ((x & 0x60) << 1) | ((x & 0x60) >> 1) | ((x & 0x60) >> 3) | ((x & 0x60) >> 5)
76 #define BMP_BMAP16(x)                                                          \
77   ((x & 0x30) << 2) | ((x & 0x30) << 0) | ((x & 0x30) >> 2) | ((x & 0x30) >> 4)
78 
79 #define BMP_CUT(a, b, c)                                                       \
80   {                                                                            \
81     if (a < b)                                                                 \
82       a = b;                                                                   \
83     else if (a > c)                                                            \
84       a = c;                                                                   \
85   }
86 
87 #define BMP_REDUCE_COLORS(r, g, b)                                             \
88   ((r & 0xe0) | ((g & 0xe0) >> 3) | ((b & 0xc0) >> 6))
89 
90 #define BMP_ADD_ERROR(pix, weight)                                             \
91   {                                                                            \
92     tmp = (pix).r + ((r1 * weight) >> 4);                                      \
93     BMP_CUT(tmp, 0, 255);                                                      \
94     (pix).r = tmp;                                                             \
95     tmp     = (pix).g + ((g1 * weight) >> 4);                                  \
96     BMP_CUT(tmp, 0, 255);                                                      \
97     (pix).g = tmp;                                                             \
98     tmp     = (pix).b + ((b1 * weight) >> 4);                                  \
99     BMP_CUT(tmp, 0, 255);                                                      \
100     (pix).b = tmp;                                                             \
101   }
102 
103 #define BMP_ADD_ERROR_BW(pix, error)                                           \
104   {                                                                            \
105     tmp = (pix).r + (error);                                                   \
106     BMP_CUT(tmp, 0, 255);                                                      \
107     (pix).r = tmp;                                                             \
108     tmp     = (pix).g + (error);                                               \
109     BMP_CUT(tmp, 0, 255);                                                      \
110     (pix).g = tmp;                                                             \
111     tmp     = (pix).b + (error);                                               \
112     BMP_CUT(tmp, 0, 255);                                                      \
113     (pix).b = tmp;                                                             \
114   }
115 
116 /*---------------------------------------------------------------------------*/
117 /*-- Structures and Enums ---------------------------------------------------*/
118 
119 typedef struct {
120   UINT bfSize;
121   UINT bfOffBits;
122   UINT biSize;
123   UINT biWidth;
124   UINT biHeight;
125   UINT biPlanes;
126   UINT biBitCount;
127   UINT biCompression;
128   UINT biSizeImage;
129   UINT biXPelsPerMeter;
130   UINT biYPelsPerMeter;
131   UINT biClrUsed;
132   UINT biClrImportant;
133   UINT biFilesize;
134   UINT biPad;
135 
136 } BMP_HEADER;
137 
138 /*---------------------------------------------------------------------------*/
139 /*-- Prototypes -------------------------------------------------------------*/
140 
141 int load_bmp_header(FILE *fp, BMP_HEADER **pHd);
142 int write_bmp_header(FILE *fp, BMP_HEADER *hd);
143 void release_bmp_header(BMP_HEADER *hd);
144 
145 int write_bmp_palette(FILE *fp, int nc, UCHAR *b, UCHAR *g, UCHAR *r);
146 
147 int make_bmp_palette(int colors, int grey, UCHAR *r, UCHAR *g, UCHAR *b);
148 
149 BMP_SUBTYPE bmp_get_colorstyle(IMAGE *img);
150 
151 int error_checking_bmp(BMP_HEADER *hd);
152 
153 int read_bmp_line(FILE *fp, void *line, UINT w, UINT h, UCHAR **map,
154                   BMP_SUBTYPE type);
155 
156 int write_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR *map,
157                    BMP_SUBTYPE type);
158 
159 int skip_bmp_lines(FILE *fp, UINT w, UINT rows, int whence, BMP_SUBTYPE type);
160 
161 /*---------------------------------------------------------------------------*/
162 /*-- Local Prototypes -------------------------------------------------------*/
163 
164 static UINT getshort(FILE *fp);
165 static UINT getint(FILE *fp);
166 static void putshort(FILE *fp, int value);
167 static void putint(FILE *fp, int value);
168 
169 static int img_read_bmp_generic(const MYSTRING fname, int type, IMAGE **);
170 #ifndef UNUSED_REDUCE_COLORS
171 static UCHAR *reduce_colors(UCHAR *buffin, int xsize, int ysize, UCHAR *rmap,
172                             UCHAR *gmap, UCHAR *bmap, int nc);
173 
174 #endif
175 
176 static int loadBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT h, UCHAR *r, UCHAR *g,
177                     UCHAR *b);
178 static int loadBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r,
179                     UCHAR *g, UCHAR *b);
180 static int loadBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r,
181                     UCHAR *g, UCHAR *b);
182 static int loadBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT h);
183 
184 static int writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map);
185 static int writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map);
186 static int writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map);
187 static int writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map);
188 static int writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *map);
189 static int writeBMP24(FILE *fp, UCHAR *pic24, UINT w, UINT h, UCHAR *map);
190 
191 static int load_lineBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map);
192 static int load_lineBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map);
193 static int load_lineBMPC4(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map);
194 static int load_lineBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map);
195 static int load_lineBMPC8(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map);
196 static int load_lineBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT padb);
197 
198 static int line_writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
199                           UCHAR *pc2nc);
200 static int line_writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
201                           UCHAR *pc2nc);
202 static int line_writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT row,
203                            UCHAR *pc2nc);
204 static int line_writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
205                           UCHAR *pc2nc);
206 static int line_writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT row,
207                            UCHAR *pc2nc);
208 static int line_writeBMP24(FILE *fp, LPIXEL *pp, UINT w, UINT padb);
209 
210 static int skip_rowsBMP1(FILE *fp, UINT w, UINT pad, UINT rows, int whence);
211 static int skip_rowsBMP4(FILE *fp, UINT w, UINT pad, UINT rows, int whence);
212 static int skip_rowsBMPC4(FILE *fp, UINT rows);
213 static int skip_rowsBMP8(FILE *fp, UINT w, UINT pad, UINT rows, int whence);
214 static int skip_rowsBMPC8(FILE *fp, UINT rows);
215 static int skip_rowsBMP24(FILE *fp, UINT w, UINT pad, UINT rows, int whence);
216 
217 #define BMP_DEBUG 0
218 #define __BMP_WRITE_LINE_BY_LINE
219 #define __BMP_READ_LINE_BY_LINE
220 
221 /*---------------------------------------------------------------------------*/
read_bmp_line(FILE * fp,void * line_buffer,UINT w,UINT row,UCHAR ** map,BMP_SUBTYPE type)222 int read_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR **map,
223                   BMP_SUBTYPE type)
224 /*---------------------------------------------------------------------------*/
225 {
226   LPIXEL *pic = (LPIXEL *)line_buffer;
227   unsigned int pad;
228   int rv = 0;
229 
230   switch (type) {
231   case BMP_BW:
232     pad = ((w + 31) / 32) * 32;
233     rv  = load_lineBMP1(fp, pic, w, pad, map);
234     CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8;
235     rv = load_lineBMP4(fp, pic, w, pad, map);
236     CASE BMP_GREY16C : __OR BMP_CMAPPED16C
237                        : rv = load_lineBMPC4(fp, pic, w, row, map);
238     if (rv == -1)
239       rv = 1;
240     else if (rv == -2)
241       rv = 0;
242     else if (rv == -3)
243       rv = 0;
244     else
245       rv                                         = 0;
246     CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4;
247     rv = load_lineBMP8(fp, pic, w, pad, map);
248     CASE BMP_GREY256C : __OR BMP_CMAPPED256C
249                         : rv = load_lineBMPC8(fp, pic, w, row, map);
250     if (rv == -1)
251       rv = 1;
252     else if (rv == -2)
253       rv = 0;
254     else if (rv == -3)
255       rv = 0;
256     else
257       rv               = 0;
258     CASE BMP_RGB : pad = (4 - ((w * 3) % 4)) & 0x03;
259     rv                 = load_lineBMP24(fp, pic, w, pad);
260   DEFAULT:
261     break;
262   }
263 
264   return !rv; /* return 0 for unsuccess */
265 }
266 
267 /*---------------------------------------------------------------------------*/
write_bmp_line(FILE * fp,void * line_buffer,UINT w,UINT row,UCHAR * map,BMP_SUBTYPE type)268 int write_bmp_line(FILE *fp, void *line_buffer, UINT w, UINT row, UCHAR *map,
269                    BMP_SUBTYPE type)
270 /*---------------------------------------------------------------------------*/
271 {
272   UCHAR *pic  = (UCHAR *)line_buffer;
273   LPIXEL *p24 = (LPIXEL *)line_buffer;
274   unsigned int pad;
275   int rv = 0;
276 
277   switch (type) {
278   case BMP_BW:
279     pad = ((w + 31) / 32) * 32;
280     rv  = line_writeBMP1(fp, pic, w, pad, map);
281     CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8;
282     rv = line_writeBMP4(fp, pic, w, pad, map);
283     CASE BMP_GREY16C : __OR BMP_CMAPPED16C
284                        : rv = line_writeBMPC4(fp, pic, w, row, map);
285     CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4;
286     rv = line_writeBMP8(fp, pic, w, pad, map);
287     CASE BMP_GREY256C : __OR BMP_CMAPPED256C
288                         : rv = line_writeBMPC8(fp, pic, w, row, map);
289     CASE BMP_RGB : pad       = (4 - ((w * 3) % 4)) & 0x03;
290     rv                       = line_writeBMP24(fp, p24, w, pad);
291   DEFAULT:
292     break;
293   }
294 
295   return rv; /* 0 for unsuccess */
296 }
297 
298 /*---------------------------------------------------------------------------*/
skip_bmp_lines(FILE * fp,UINT w,UINT rows,int whence,BMP_SUBTYPE type)299 int skip_bmp_lines(FILE *fp, UINT w, UINT rows, int whence, BMP_SUBTYPE type)
300 /*---------------------------------------------------------------------------*/
301 {
302   unsigned int pad;
303   int rv = 0;
304 
305   switch (type) {
306   case BMP_BW:
307     pad = ((w + 31) / 32) * 32;
308     rv  = skip_rowsBMP1(fp, w, pad, rows, whence);
309     CASE BMP_GREY16 : __OR BMP_CMAPPED16 : pad = ((w + 7) / 8) * 8;
310     rv = skip_rowsBMP4(fp, w, pad, rows, whence);
311     CASE BMP_GREY16C : __OR BMP_CMAPPED16C : rv  = skip_rowsBMPC4(fp, rows);
312     CASE BMP_GREY256 : __OR BMP_CMAPPED256 : pad = ((w + 3) / 4) * 4;
313     rv = skip_rowsBMP8(fp, w, pad, rows, whence);
314     CASE BMP_GREY256C : __OR BMP_CMAPPED256C : rv = skip_rowsBMPC8(fp, rows);
315     CASE BMP_RGB : pad                            = (4 - ((w * 3) % 4)) & 0x03;
316     rv = skip_rowsBMP24(fp, w, pad, rows, whence);
317   DEFAULT:
318     break;
319   }
320 
321   return !rv;
322 }
323 
324 /*---------------------------------------------------------------------------*/
error_checking_bmp(BMP_HEADER * hd)325 int error_checking_bmp(BMP_HEADER *hd)
326 /*---------------------------------------------------------------------------*/
327 {
328   /* error checking */
329   if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 &&
330        hd->biBitCount != 24) ||
331       hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) {
332     return UNSUPPORTED_BMP_FORMAT;
333   }
334 
335   /* error checking */
336   if (((hd->biBitCount == 1 || hd->biBitCount == 24) &&
337        hd->biCompression != BMP_BI_RGB) ||
338       (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) ||
339       (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) {
340     return UNSUPPORTED_BMP_FORMAT;
341   }
342 
343   return OK;
344 }
345 
346 /*---------------------------------------------------------------------------*/
load_bmp_header(FILE * fp,BMP_HEADER ** header)347 int load_bmp_header(FILE *fp, BMP_HEADER **header)
348 /*---------------------------------------------------------------------------*/
349 {
350   BMP_HEADER *hd = NULL;
351   int c, c1;
352 
353   *header = NULL;
354 
355   hd = (BMP_HEADER *)calloc((size_t)1, sizeof(BMP_HEADER));
356   if (!hd) return OUT_OF_MEMORY;
357 
358   /* figure out the file size */
359   fseek(fp, 0L, SEEK_END);
360   hd->biFilesize = ftell(fp);
361   fseek(fp, 0L, 0);
362 
363   /* read the file type (first two bytes) */
364   c  = getc(fp);
365   c1 = getc(fp);
366   if (c != 'B' || c1 != 'M') {
367     free(hd);
368     return UNSUPPORTED_BMP_FORMAT;
369   }
370 
371   hd->bfSize = getint(fp);
372 
373   /* reserved and ignored */
374   getshort(fp);
375   getshort(fp);
376 
377   hd->bfOffBits = getint(fp);
378   hd->biSize    = getint(fp);
379 
380   if (hd->biSize == BMP_WIN_NEW || hd->biSize == BMP_OS2_NEW) {
381     hd->biWidth         = getint(fp);
382     hd->biHeight        = getint(fp);
383     hd->biPlanes        = getshort(fp);
384     hd->biBitCount      = getshort(fp);
385     hd->biCompression   = getint(fp);
386     hd->biSizeImage     = getint(fp);
387     hd->biXPelsPerMeter = getint(fp);
388     hd->biYPelsPerMeter = getint(fp);
389     hd->biClrUsed       = getint(fp);
390     hd->biClrImportant  = getint(fp);
391   } else /* old bitmap format */
392   {
393     hd->biWidth    = getshort(fp);
394     hd->biHeight   = getshort(fp);
395     hd->biPlanes   = getshort(fp);
396     hd->biBitCount = getshort(fp);
397 
398     /* Not in old versions so have to compute them */
399     hd->biSizeImage =
400         (((hd->biPlanes * hd->biBitCount * hd->biWidth) + 31) / 32) * 4 *
401         hd->biHeight;
402 
403     hd->biCompression   = BMP_BI_RGB;
404     hd->biXPelsPerMeter = 0;
405     hd->biYPelsPerMeter = 0;
406     hd->biClrUsed       = 0;
407     hd->biClrImportant  = 0;
408   }
409 
410   if (BMP_DEBUG) {
411     printf("\nLoadBMP:\tbfSize=%u, bfOffBits=%u\n", hd->bfSize, hd->bfOffBits);
412     printf("\t\tbiSize=%u, biWidth=%u, biHeight=%u, biPlanes=%u\n", hd->biSize,
413            hd->biWidth, hd->biHeight, hd->biPlanes);
414     printf("\t\tbiBitCount=%u, biCompression=%u, biSizeImage=%u\n",
415            hd->biBitCount, hd->biCompression, hd->biSizeImage);
416     printf("\t\tbiX,YPelsPerMeter=%u,%u  biClrUsed=%u, biClrImp=%u\n",
417            hd->biXPelsPerMeter, hd->biYPelsPerMeter, hd->biClrUsed,
418            hd->biClrImportant);
419   }
420 
421   if (BMP_FERROR(fp)) {
422     free(hd);
423     return UNEXPECTED_EOF;
424   }
425 
426   *header = hd;
427   return OK;
428 }
429 
430 /*---------------------------------------------------------------------------*/
release_bmp_header(BMP_HEADER * hd)431 void release_bmp_header(BMP_HEADER *hd)
432 /*---------------------------------------------------------------------------*/
433 {
434   if (hd) free(hd);
435 }
436 
437 #ifndef __LIBSIMAGE__
438 
439 /*---------------------------------------------------------------------------*/
img_read_bmp(const MYSTRING fname,IMAGE ** pimg)440 int img_read_bmp(const MYSTRING fname, IMAGE **pimg)
441 /*---------------------------------------------------------------------------*/
442 {
443   return img_read_bmp_generic(fname, BMP_READ_IMAGE, pimg);
444 }
445 
446 /*---------------------------------------------------------------------------*/
img_read_bmp_generic(const MYSTRING fname,int type,IMAGE ** pimg)447 static int img_read_bmp_generic(const MYSTRING fname, int type, IMAGE **pimg)
448 /*---------------------------------------------------------------------------*/
449 {
450   int retCode = OK;
451 
452   UCHAR r[256], g[256], b[256];
453   BMP_HEADER *hd = NULL;
454   IMAGE *img     = NULL;
455 
456   int rv, c, i;
457   LPIXEL *pic;
458   FILE *fp;
459 
460   *pimg = 0;
461 
462   /* returns  'NULL' on unsuccess */
463 
464   pic = (LPIXEL *)NULL;
465 
466   /* open image file */
467   fp = _wfopen(fname, L"rb");
468   if (!fp) return CANT_OPEN_FILE;
469 
470   /* load up the image header */
471   retCode = load_bmp_header(fp, &hd);
472   if (retCode != OK) goto ERROR;
473 
474   /* error checking */
475   if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 &&
476        hd->biBitCount != 24) ||
477       hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) {
478     retCode = UNSUPPORTED_BMP_FORMAT;
479     goto ERROR;
480   }
481 
482   /* error checking */
483   if (((hd->biBitCount == 1 || hd->biBitCount == 24) &&
484        hd->biCompression != BMP_BI_RGB) ||
485       (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) ||
486       (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) {
487     retCode = UNSUPPORTED_BMP_FORMAT;
488     goto ERROR;
489   }
490 
491   img       = new_img();
492   img->type = TOONZRGB;
493 
494   if (type == BMP_READ_INFO) {
495     fclose(fp);
496     img->xSBsize = img->xsize = hd->biWidth;
497     img->ySBsize = img->ysize = hd->biHeight;
498     release_bmp_header(hd);
499     *pimg = img;
500     return OK;
501   }
502 
503   allocate_pixmap(img, (int)hd->biWidth, (int)hd->biHeight);
504 
505   /* hd->biPad; */
506   if (hd->biSize != BMP_WIN_OS2_OLD) {
507     /* skip ahead to colormap, using biSize */
508     c = hd->biSize - 40; /* 40 bytes read from biSize to biClrImportant */
509     for (i    = 0; i < c; i++) getc(fp);
510     hd->biPad = hd->bfOffBits - (hd->biSize + 14);
511   }
512 
513   /* load up colormap, if any */
514   if (hd->biBitCount != 24) {
515     int i, cmaplen;
516 
517     /*cmaplen = (hd->biClrUsed) ? hd->biClrUsed : 1 << hd->biBitCount;*/
518     if (hd->biClrUsed)
519       cmaplen = hd->biClrUsed;
520     else
521       cmaplen = 1 << hd->biBitCount;
522 
523     for (i = 0; i < cmaplen; i++) {
524       b[i] = getc(fp);
525       g[i] = getc(fp);
526       r[i] = getc(fp);
527       if (hd->biSize != BMP_WIN_OS2_OLD) {
528         getc(fp);
529         hd->biPad -= 4;
530       }
531     }
532 
533     if (BMP_FERROR(fp)) {
534       retCode = UNEXPECTED_EOF;
535       goto ERROR;
536     }
537 
538     if (BMP_DEBUG) {
539       printf("LoadBMP:  BMP colormap:  (RGB order)\n");
540       for (i = 0; i < cmaplen; i++) printf("%02x%02x%02x  ", r[i], g[i], b[i]);
541       printf("\n\n");
542     }
543   }
544 
545   if (hd->biSize != BMP_WIN_OS2_OLD) {
546     /* Waste any unused bytes between the colour map (if present)
547 and the start of the actual bitmap data.
548 */
549 
550     while (hd->biPad > 0) {
551       (void)getc(fp);
552       hd->biPad--;
553     }
554   }
555 
556   /* create 32 bit image buffer */
557 
558   pic = (LPIXEL *)img->buffer;
559 
560   /* load up the image */
561   switch (hd->biBitCount) {
562   case 1:
563     rv          = loadBMP1(fp, pic, hd->biWidth, hd->biHeight, r, g, b);
564     CASE 4 : rv = loadBMP4(fp, pic, hd->biWidth, hd->biHeight,
565                            hd->biCompression, r, g, b);
566     CASE 8 : rv = loadBMP8(fp, pic, hd->biWidth, hd->biHeight,
567                            hd->biCompression, r, g, b);
568     CASE 24 : rv = loadBMP24(fp, pic, hd->biWidth, hd->biHeight);
569   DEFAULT:
570     retCode = UNSUPPORTED_BMP_FORMAT;
571     goto ERROR;
572   }
573 
574   if (rv) {
575     retCode = UNEXPECTED_EOF;
576     goto ERROR;
577   }
578 
579   fclose(fp);
580   release_bmp_header(hd);
581 
582   *pimg = img;
583   return OK;
584 
585 ERROR:
586 
587   fclose(fp);
588   release_bmp_header(hd);
589 
590   if (img) {
591     TFREE(img->buffer)
592     TFREE(img)
593   }
594 
595   return retCode;
596 }
597 
598 #endif /* __LIBSIMAGE__ */
599 
img_read_bmp_region(const MYSTRING fname,IMAGE ** pimg,int x1,int y1,int x2,int y2,int scale)600 static int img_read_bmp_region(const MYSTRING fname, IMAGE **pimg, int x1,
601                                int y1, int x2, int y2, int scale) {
602   UCHAR r[256], g[256], b[256] /*  ,*map[3]  */;
603   LPIXEL *line   = NULL;
604   UINT line_size = 0;
605   BMP_HEADER *hd = NULL;
606   EXT_INFO_REGION info;
607   BMP_SUBTYPE subtype;
608   LPIXEL *pic, *appo;
609   IMAGE *img = NULL;
610   UINT start_offset;
611   UINT c, i, j;
612   char buf[512];
613   FILE *fp;
614   UINT pad;
615   enum BMP_ERROR_CODE bmp_error = OK;
616 
617   /* initialize some variables */
618   i = pad = 0;
619 
620   /* returns  'NULL' on unsuccess */
621   pic = (LPIXEL *)NULL;
622 
623   /* open image file */
624   fp = _wfopen(fname, L"rb");
625   if (!fp) {
626     return CANT_OPEN_FILE;
627   }
628 
629   /* load up the image header */
630   load_bmp_header(fp, &hd);
631   if (!hd) goto ERROR;
632 
633   /* error checking */
634   if ((hd->biBitCount != 1 && hd->biBitCount != 4 && hd->biBitCount != 8 &&
635        hd->biBitCount != 24) ||
636       hd->biPlanes != 1 || hd->biCompression > BMP_BI_RLE4) {
637     snprintf(buf, sizeof(buf),
638              "Bogus BMP File! (bitCount=%d, Planes=%d, Compression=%d)",
639              hd->biBitCount, hd->biPlanes, hd->biCompression);
640 
641     bmp_error = UNSUPPORTED_BMP_FORMAT;
642     goto ERROR;
643   }
644 
645   /* error checking */
646   if (((hd->biBitCount == 1 || hd->biBitCount == 24) &&
647        hd->biCompression != BMP_BI_RGB) ||
648       (hd->biBitCount == 4 && hd->biCompression == BMP_BI_RLE8) ||
649       (hd->biBitCount == 8 && hd->biCompression == BMP_BI_RLE4)) {
650     snprintf(buf, sizeof(buf),
651              "Bogus BMP File!  (bitCount=%d, Compression=%d)",
652              hd->biBitCount, hd->biCompression);
653     bmp_error = UNSUPPORTED_BMP_FORMAT;
654     goto ERROR;
655   }
656 
657   img = new_img();
658 
659   img->type = TOONZRGB;
660 
661   img->xsize   = hd->biWidth;
662   img->ysize   = hd->biHeight;
663   img->xSBsize = hd->biWidth;
664   img->ySBsize = hd->biHeight;
665   img->x_dpi   = (double)(hd->biXPelsPerMeter / 39);
666   img->y_dpi   = (double)(hd->biYPelsPerMeter / 39);
667 
668   hd->biPad = 0;
669   if (hd->biSize != BMP_WIN_OS2_OLD) {
670     /* skip ahead to colormap, using biSize */
671     c = hd->biSize - 40; /* 40 bytes read from biSize to biClrImportant */
672     for (i    = 0; i < c; i++) getc(fp);
673     hd->biPad = hd->bfOffBits - (hd->biSize + 14);
674   }
675 
676   /* load up colormap, if any */
677   if (hd->biBitCount != 24) {
678     int i, cmaplen;
679 
680     /*cmaplen = (hd->biClrUsed) ? hd->biClrUsed : 1 << hd->biBitCount;*/
681     if (hd->biClrUsed)
682       cmaplen = hd->biClrUsed;
683     else
684       cmaplen = hd->biBitCount;
685 
686     for (i = 0; i < cmaplen; i++) {
687       b[i] = getc(fp);
688       g[i] = getc(fp);
689       r[i] = getc(fp);
690       if (hd->biSize != BMP_WIN_OS2_OLD) {
691         getc(fp);
692         hd->biPad -= 4;
693       }
694     }
695 
696     if (BMP_FERROR(fp)) {
697       bmp_error = UNEXPECTED_EOF;
698       goto ERROR;
699     }
700 
701     if (BMP_DEBUG) {
702       printf("LoadBMP:  BMP colormap:  (RGB order)\n");
703       for (i = 0; i < cmaplen; i++) printf("%02x%02x%02x  ", r[i], g[i], b[i]);
704       printf("\n\n");
705     }
706   }
707 
708   if (hd->biSize != BMP_WIN_OS2_OLD) {
709     /* Waste any unused bytes between the colour map (if present)
710 and the start of the actual bitmap data.
711 */
712 
713     while (hd->biPad > 0) {
714       (void)getc(fp);
715       hd->biPad--;
716     }
717   }
718 
719   /* get information about the portion of the image to load */
720   get_info_region(&info, x1, y1, x2, y2, scale, (int)hd->biWidth,
721                   (int)hd->biHeight, TNZ_BOTLEFT);
722 
723   /* create 32 bit image buffer */
724   if (!allocate_pixmap(img, info.xsize, info.ysize)) {
725     bmp_error = OUT_OF_MEMORY;
726     goto ERROR;
727   }
728 
729   start_offset = info.y_offset * info.xsize + info.x_offset;
730   pic          = ((LPIXEL *)img->buffer) + start_offset;
731 
732   if (line_size < hd->biWidth + 32) {
733     line_size = hd->biWidth + 32;
734     if (!line)
735       TCALLOC((LPIXEL *)line, (size_t)line_size)
736     else
737       TREALLOC(line, line_size)
738   }
739   if (!line) {
740     bmp_error = OUT_OF_MEMORY;
741     goto ERROR;
742   }
743 
744   switch (hd->biBitCount) {
745   case 1:
746     pad           = ((hd->biWidth + 31) / 32) * 32;
747     CASE 4 : pad  = ((hd->biWidth + 7) / 8) * 8;
748     CASE 8 : pad  = ((hd->biWidth + 3) / 4) * 4;
749     CASE 24 : pad = (4 - ((hd->biWidth * 3) % 4)) & 0x03;
750   DEFAULT:
751     /* segnala errore ed esci */
752     break;
753   }
754 
755   subtype = bmp_get_colorstyle(img);
756   if (subtype == BMP_NONE) goto ERROR;
757 
758   if (info.y_offset > 0) info.scanNrow++;
759   if (info.x_offset > 0) info.scanNcol++;
760 
761   /*  print_info_region(&info);      */
762 
763   if (info.startScanRow > 0)
764     skip_bmp_lines(fp, hd->biWidth, (unsigned int)(info.startScanRow - 1),
765                    (unsigned int)SEEK_CUR, subtype);
766 
767   for (i = 0; i < (UINT)info.scanNrow; i++) {
768     if (load_lineBMP24(fp, line, hd->biWidth, pad)) goto ERROR;
769 
770     /*  QUESTO SWITCH VA AGGIUSTATO!
771 switch (subtype)
772 {
773 CASE BMP_BW:
774  if (load_lineBMP1(fp, line, hd->biWidth, pad, map))
775     goto ERROR;
776 CASE BMP_GREY16:
777 __OR BMP_CMAPPED16:
778  if (load_lineBMP4(fp, line, hd->biWidth, pad, map))
779     goto ERROR;
780 CASE BMP_GREY16C:
781 __OR BMP_CMAPPED16C:
782  if (load_lineBMPC4(fp, line, hd->biWidth, i, map)==-1)
783     goto ERROR;
784 CASE BMP_GREY256:
785 __OR BMP_CMAPPED256:
786  if (load_lineBMP8(fp, line, hd->biWidth, pad, map))
787     goto ERROR;
788 CASE BMP_GREY256C:
789 __OR BMP_CMAPPED256C:
790  if (load_lineBMPC8(fp, line, hd->biWidth, i, map)==-1)
791     goto ERROR;
792 CASE BMP_RGB:
793  if (load_lineBMP24(fp, line, hd->biWidth, pad))
794     goto ERROR;
795 }
796 */
797     for (appo = pic, j = c = 0; j < (UINT)info.scanNcol; j++, c += info.step)
798       *appo++ = *(line + info.startScanCol + c);
799     pic += info.xsize;
800 
801     skip_bmp_lines(fp, hd->biWidth, (unsigned int)(info.step - 1),
802                    (unsigned int)SEEK_CUR, subtype);
803   }
804 
805   /*
806 if (BMP_FERROR(fp))
807 {
808 bmp_error(fname, "File appears truncated.  Winging it.\n");
809 goto ERROR;
810 }
811 */
812 
813   fclose(fp);
814   release_bmp_header(hd);
815   TFREE(line);
816   *pimg = img;
817   return OK;
818 
819 ERROR:
820 
821   printf("error: (row=%d)\n", i);
822 
823   fclose(fp);
824   release_bmp_header(hd);
825 
826   if (img) free_img(img);
827   TFREE(line);
828   return bmp_error;
829 }
830 /*---------------------------------------------------------------------------*/
loadBMP1(FILE * fp,LPIXEL * pic,UINT w,UINT h,UCHAR * r,UCHAR * g,UCHAR * b)831 static int loadBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT h, UCHAR *r, UCHAR *g,
832                     UCHAR *b)
833 /*---------------------------------------------------------------------------*/
834 {
835   UINT i, j, c, bitnum, padw, rv;
836   UCHAR byte;
837   LPIXEL *pp;
838 #ifdef BMP_READ_LINE_BY_LINE
839   UCHAR *map[3];
840 
841   map[0] = r;
842   map[1] = g;
843   map[2] = b;
844 #endif
845 
846   rv = c = 0;
847   padw   = ((w + 31) / 32) * 32; /* 'w', padded to be a multiple of 32 */
848 
849   for (i = 0; i < h; i++) {
850 #ifdef BMP_READ_LINE_BY_LINE
851     pp = pic + (i * w);
852     rv = load_lineBMP1(fp, pp, w, padw, map);
853     if (rv) break;
854 #else
855     pp = pic + (i * w);
856     for (j = bitnum = 0; j < padw; j++, bitnum++) {
857       if ((bitnum & 7) == 0) /* read the next byte */
858       {
859         c      = getc(fp);
860         bitnum = 0;
861       }
862       if (j < w) {
863         byte = (c & 0x80) ? 1 : 0;
864         c <<= 1;
865 
866         pp->r = r[byte];
867         pp->g = g[byte];
868         pp->b = b[byte];
869         pp->m = 255;
870 
871         pp++;
872       }
873     }
874     if (BMP_FERROR(fp)) break;
875 #endif
876   }
877 
878   if (BMP_FERROR(fp)) rv = 1;
879 
880   return rv;
881 }
882 
883 /*---------------------------------------------------------------------------*/
load_lineBMP1(FILE * fp,LPIXEL * pic,UINT w,UINT padw,UCHAR ** map)884 int load_lineBMP1(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map)
885 /*---------------------------------------------------------------------------*/
886 {
887   UINT j, c, bitnum;
888   UCHAR byte;
889   LPIXEL *pp;
890 
891   for (c = 0, pp = pic, j = bitnum = 0; j < padw; j++, bitnum++) {
892     if ((bitnum & 7) == 0) /* read the next byte */
893     {
894       c      = getc(fp);
895       bitnum = 0;
896     }
897     if (j < w) {
898       byte = (c & 0x80) ? 1 : 0;
899       c <<= 1;
900 
901       pp->r = map[0][byte];
902       pp->g = map[1][byte];
903       pp->b = map[2][byte];
904       pp->m = 255;
905 
906       pp++;
907     }
908   }
909 
910   return (BMP_FERROR(fp));
911 }
912 
913 /*---------------------------------------------------------------------------*/
skip_rowsBMP1(FILE * fp,UINT w,UINT pad,UINT rows,int whence)914 static int skip_rowsBMP1(FILE *fp, UINT w, UINT pad, UINT rows, int whence)
915 /*---------------------------------------------------------------------------*/
916 {
917   UINT offset = pad * rows;
918   UINT i, bitnum;
919 
920   for (i = bitnum = 0; i < offset; i++, bitnum++) {
921     if ((bitnum & 7) == 0) {
922       getc(fp);
923       bitnum = 0;
924     }
925   }
926 
927   return (BMP_FERROR(fp));
928 }
929 
930 /*---------------------------------------------------------------------------*/
loadBMP4(FILE * fp,LPIXEL * pic,UINT w,UINT h,UINT comp,UCHAR * r,UCHAR * g,UCHAR * b)931 static int loadBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r,
932                     UCHAR *g, UCHAR *b)
933 /*---------------------------------------------------------------------------*/
934 {
935   UINT i, j, c, c1, x, y, nybnum, padw, rv;
936   UCHAR byte;
937   LPIXEL *pp;
938 #ifdef BMP_READ_LINE_BY_LINE
939   UCHAR *map[3];
940 
941   map[0] = r;
942   map[1] = g;
943   map[2] = b;
944 #endif
945 
946   rv = 0;
947   c = c1 = 0;
948 
949   if (comp == BMP_BI_RGB) /* read uncompressed data */
950   {
951     padw = ((w + 7) / 8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
952     for (i = 0; i < h; i++) {
953       pp = pic + (i * w);
954 #ifdef BMP_READ_LINE_BY_LINE
955       rv = load_lineBMP4(fp, pp, w, padw, map);
956       if (rv) break;
957 #else
958       for (j = nybnum = 0; j < padw; j++, nybnum++) {
959         if ((nybnum & 1) == 0) /* read next byte */
960         {
961           c      = getc(fp);
962           nybnum = 0;
963         }
964         if (j < w) {
965           byte = (c & 0xf0) >> 4;
966           c <<= 4;
967 
968           pp->r = r[byte];
969           pp->g = g[byte];
970           pp->b = b[byte];
971           pp->m = 255;
972 
973           pp++;
974         }
975       }
976       if (BMP_FERROR(fp)) break;
977 #endif
978     }
979   } else if (comp == BMP_BI_RLE4) /* read RLE4 compressed data */
980   {
981     x = y = 0;
982     pp    = pic + x + (y)*w;
983     while (y < h) {
984 #ifdef BMP_READ_LINE_BY_LINE
985 
986       rv = load_lineBMPC4(fp, pp, w, y, map);
987       if (rv == -1) {
988         rv = 1;
989         break;
990       } else if (rv == -2) {
991         rv = 0;
992         y++;
993         pp = pic + y * w;
994       } else if (rv == -3) {
995         rv = 0;
996         break;
997       } else {
998         y += (rv / w);
999         pp = pic + rv;
1000         rv = 0;
1001       }
1002 
1003 #else
1004       c = getc(fp);
1005       if ((int)c == EOF) {
1006         rv = 1;
1007         break;
1008       }
1009 
1010       if (c) /* encoded mode */
1011       {
1012         c1 = getc(fp);
1013         for (i = 0; i < c; i++, x++, pp++) {
1014           byte  = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f);
1015           pp->r = r[byte];
1016           pp->g = g[byte];
1017           pp->b = b[byte];
1018           pp->m = 255;
1019         }
1020       } else /* c==0x00  :  escape codes */
1021       {
1022         c = getc(fp);
1023         if ((int)c == EOF) {
1024           rv = 1;
1025           break;
1026         }
1027 
1028         if (c == 0x00) /* end of line */
1029         {
1030           x = 0;
1031           y++;
1032           if (y < h) pp = pic + x + (y)*w;
1033         } else if (c == 0x01)
1034           break;            /* end of  pic */
1035         else if (c == 0x02) /* delta */
1036         {
1037           c = getc(fp);
1038           x += c;
1039           c = getc(fp);
1040           y += c;
1041           if (y < h) pp = pic + x + (y)*w;
1042         } else /* absolute mode */
1043         {
1044           for (i = 0; i < c; i++, x++, pp++) {
1045             if ((i & 1) == 0) c1 = getc(fp);
1046             byte                 = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f);
1047             pp->r                = r[byte];
1048             pp->g                = g[byte];
1049             pp->b                = b[byte];
1050             pp->m                = 255;
1051           }
1052           if (((c & 3) == 1) || ((c & 3) == 2)) /* read pad byte */
1053             getc(fp);
1054         }
1055       }
1056       if (BMP_FERROR(fp)) break;
1057 #endif
1058     }
1059   } else {
1060     return 1;
1061   }
1062 
1063   if (BMP_FERROR(fp)) rv = 1;
1064 
1065   return rv;
1066 }
1067 
1068 /*---------------------------------------------------------------------------*/
load_lineBMP4(FILE * fp,LPIXEL * pic,UINT w,UINT padw,UCHAR ** map)1069 int load_lineBMP4(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map)
1070 /*---------------------------------------------------------------------------*/
1071 {
1072   UINT nybnum, j, c;
1073   UCHAR byte;
1074   LPIXEL *pp;
1075 
1076   for (c = 0, pp = pic, j = nybnum = 0; j < padw; j++, nybnum++) {
1077     if ((nybnum & 1) == 0) /* read next byte */
1078     {
1079       c      = getc(fp);
1080       nybnum = 0;
1081     }
1082     if (j < w) {
1083       byte = (c & 0xf0) >> 4;
1084       c <<= 4;
1085 
1086       pp->r = map[0][byte];
1087       pp->g = map[1][byte];
1088       pp->b = map[2][byte];
1089       pp->m = 255;
1090 
1091       pp++;
1092     }
1093   }
1094 
1095   return (BMP_FERROR(fp));
1096 }
1097 
1098 /*---------------------------------------------------------------------------*/
skip_rowsBMP4(FILE * fp,UINT w,UINT pad,UINT rows,int whence)1099 static int skip_rowsBMP4(FILE *fp, UINT w, UINT pad, UINT rows, int whence)
1100 /*---------------------------------------------------------------------------*/
1101 {
1102   UINT offset = pad * rows;
1103   UINT i, nybnum;
1104 
1105   for (i = nybnum = 0; i < offset; i++, nybnum++) {
1106     if ((nybnum & 1) == 0) {
1107       getc(fp);
1108       nybnum = 0;
1109     }
1110   }
1111 
1112   return (BMP_FERROR(fp));
1113 }
1114 
1115 /*---------------------------------------------------------------------------*/
load_lineBMPC4(FILE * fp,LPIXEL * pic,UINT w,UINT y,UCHAR ** map)1116 int load_lineBMPC4(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map)
1117 /*---------------------------------------------------------------------------*/
1118 {
1119   UINT i, c, c1, x;
1120   UCHAR byte;
1121   LPIXEL *pp;
1122 
1123   /*
1124 *  Codici di ritorno:
1125 *
1126 *     -1:   incontrata la file del file       (EOF)
1127 *     -2:   incontrata la fine della linea    (Escape code 0x00 0x00)
1128 *     -3:   incontrata la fine dell' immagine (Escape code 0x00 0x01)
1129 *    altro:   incontrato un delta               (Escape code 0x00 0x02)
1130 */
1131 
1132   /* initialize some variables */
1133   x  = 0;
1134   pp = pic;
1135   c = c1 = 0;
1136 
1137   while (1) {
1138     c = getc(fp);
1139     if ((int)c == EOF) return -1;
1140     if (c) { /* encoded mode */
1141       c1 = getc(fp);
1142       for (i = 0; i < c; i++, x++, pp++) {
1143         byte  = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f);
1144         pp->r = map[0][byte];
1145         pp->g = map[1][byte];
1146         pp->b = map[2][byte];
1147         pp->m = 255;
1148       }
1149     } else /* c==0x00  :  escape codes */
1150     {
1151       c = getc(fp);
1152       if ((int)c == EOF) return -1;
1153       if (c == 0x00) /* end of line */
1154         return -2;
1155       else if (c == 0x01) /* end of pic */
1156         return -3;
1157       else if (c == 0x02) /* delta */
1158       {
1159         c = getc(fp);
1160         x += c;
1161         c = getc(fp);
1162         y += c;
1163 
1164         return (x + y * w);
1165       } else /* absolute mode */
1166       {
1167         for (i = 0; i < c; i++, x++, pp++) {
1168           if ((i & 1) == 0) c1 = getc(fp);
1169           byte                 = (i & 1) ? (c1 & 0x0f) : ((c1 >> 4) & 0x0f);
1170           pp->r                = map[0][byte];
1171           pp->g                = map[1][byte];
1172           pp->b                = map[2][byte];
1173           pp->m                = 255;
1174         }
1175         if (((c & 3) == 1) || ((c & 3) == 2)) /* read pad byte */
1176           getc(fp);
1177       }
1178     }
1179     if (BMP_FERROR(fp)) break;
1180   }
1181 
1182   return -1;
1183 }
1184 
1185 /*---------------------------------------------------------------------------*/
skip_rowsBMPC4(FILE * fp,UINT rows)1186 static int skip_rowsBMPC4(FILE *fp, UINT rows)
1187 /*---------------------------------------------------------------------------*/
1188 {
1189   UINT i, c, c1, rv = 0;
1190 
1191   while (rows > 0) {
1192     c = getc(fp);
1193     switch (c) {
1194     case 0x00:
1195       c = getc(fp);
1196       switch (c) {
1197       case 0x00:
1198         rows--;
1199         CASE 0x01 : rows = 0;
1200         CASE 0x02 : c1   = getc(fp); /* x buffer offest */
1201         c1               = getc(fp); /* y buffer offest */
1202         rows -= c1;
1203       DEFAULT:
1204         for (i = 0; i < c; i++) {
1205           if ((i & 1) == 0) getc(fp);
1206         }
1207         if (((c & 3) == 1) || ((c & 3) == 2)) getc(fp);
1208       }
1209     DEFAULT:
1210       c1 = getc(fp);
1211     }
1212   }
1213 
1214   if (BMP_FERROR(fp)) rv = 1;
1215 
1216   return rv;
1217 }
1218 
1219 /*---------------------------------------------------------------------------*/
loadBMP8(FILE * fp,LPIXEL * pic,UINT w,UINT h,UINT comp,UCHAR * r,UCHAR * g,UCHAR * b)1220 static int loadBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT h, UINT comp, UCHAR *r,
1221                     UCHAR *g, UCHAR *b)
1222 /*---------------------------------------------------------------------------*/
1223 {
1224   UINT i, j, c, c1, padw, x, y, rv;
1225 
1226   LPIXEL *pp;
1227 #ifdef BMP_READ_LINE_BY_LINE
1228   UCHAR *map[3];
1229 
1230   map[0] = r;
1231   map[1] = g;
1232   map[2] = b;
1233 #endif
1234 
1235   rv = 0;
1236 
1237   if (comp == BMP_BI_RGB) /* read uncompressed data */
1238   {
1239     padw = ((w + 3) / 4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
1240     for (i = 0; i < h; i++) {
1241 #ifdef BMP_READ_LINE_BY_LINE
1242       pp = pic + (i * w);
1243       rv = load_lineBMP8(fp, pp, w, padw, map);
1244       if (rv) break;
1245 #else
1246       pp = pic + (i * w);
1247       for (j = 0; j < padw; j++) {
1248         c                     = getc(fp);
1249         if ((int)c == EOF) rv = 1;
1250         if (j < w) {
1251           pp->r = r[c];
1252           pp->g = g[c];
1253           pp->b = b[c];
1254           pp->m = 255;
1255 
1256           pp++;
1257         }
1258       }
1259       if (BMP_FERROR(fp)) break;
1260 #endif
1261     }
1262   } else if (comp == BMP_BI_RLE8) /* read RLE8 compressed data */
1263   {
1264     x = y = 0;
1265     pp    = pic + x + y * w;
1266     while (y < h) {
1267 #ifdef BMP_READ_LINE_BY_LINE
1268 
1269       rv = load_lineBMPC8(fp, pp, w, y, map);
1270       if (rv == -1) {
1271         rv = 1;
1272         break;
1273       } else if (rv == -2) {
1274         rv = 0;
1275         y++;
1276         pp = pic + y * w;
1277       } else if (rv == -3) {
1278         rv = 0;
1279         break;
1280       } else {
1281         y += (rv / w);
1282         pp = pic + rv;
1283         rv = 0;
1284       }
1285 
1286 #else
1287       c = getc(fp);
1288       if ((int)c == EOF) {
1289         rv = 1;
1290         break;
1291       }
1292 
1293       if (c) { /* encoded mode */
1294         c1 = getc(fp);
1295         for (i = 0; i < c; i++, x++, pp++) {
1296           pp->r = r[c1];
1297           pp->g = g[c1];
1298           pp->b = b[c1];
1299           pp->m = 255;
1300         }
1301       } else /* c==0x00  :  escape codes */
1302       {
1303         c = getc(fp);
1304         if ((int)c == EOF) {
1305           rv = 1;
1306           break;
1307         }
1308 
1309         if (c == 0x00) /* end of line */
1310         {
1311           x = 0;
1312           y++;
1313           pp = pic + x + y * w;
1314         } else if (c == 0x01)
1315           break;            /* end of pic */
1316         else if (c == 0x02) /* delta */
1317         {
1318           c = getc(fp);
1319           x += c;
1320           c = getc(fp);
1321           y += c;
1322           pp = pic + x + y * w;
1323         } else /* absolute mode */
1324         {
1325           for (i = 0; i < c; i++, x++, pp++) {
1326             c1 = getc(fp);
1327 
1328             pp->r = r[c1];
1329             pp->g = g[c1];
1330             pp->b = b[c1];
1331             pp->m = 255;
1332           }
1333           if (c & 1) /* odd length run: read an extra pad byte */
1334             getc(fp);
1335         }
1336       }
1337       if (BMP_FERROR(fp)) break;
1338 #endif
1339     }
1340   } else {
1341     return 1;
1342   }
1343 
1344   if (BMP_FERROR(fp)) rv = 1;
1345 
1346   return rv;
1347 }
1348 
1349 /*---------------------------------------------------------------------------*/
load_lineBMP8(FILE * fp,LPIXEL * pic,UINT w,UINT padw,UCHAR ** map)1350 int load_lineBMP8(FILE *fp, LPIXEL *pic, UINT w, UINT padw, UCHAR **map)
1351 /*---------------------------------------------------------------------------*/
1352 {
1353   UINT j, c, rv = 0;
1354   LPIXEL *pp;
1355 
1356   for (pp = pic, j = 0; j < padw; j++) {
1357     c = getc(fp);
1358     if ((int)c == EOF) {
1359       rv = 1;
1360       break;
1361     }
1362     if (j < w) {
1363       pp->r = map[0][c];
1364       pp->g = map[1][c];
1365       pp->b = map[2][c];
1366       pp->m = 255;
1367 
1368       pp++;
1369     }
1370   }
1371   if (BMP_FERROR(fp)) rv = 1;
1372 
1373   return rv;
1374 }
1375 
1376 /*---------------------------------------------------------------------------*/
skip_rowsBMP8(FILE * fp,UINT w,UINT pad,UINT rows,int whence)1377 static int skip_rowsBMP8(FILE *fp, UINT w, UINT pad, UINT rows, int whence)
1378 /*---------------------------------------------------------------------------*/
1379 {
1380   UINT offset = pad * rows;
1381 
1382   fseek(fp, (long)offset, whence);
1383 
1384   return (BMP_FERROR(fp));
1385 }
1386 
1387 /*---------------------------------------------------------------------------*/
load_lineBMPC8(FILE * fp,LPIXEL * pic,UINT w,UINT y,UCHAR ** map)1388 int load_lineBMPC8(FILE *fp, LPIXEL *pic, UINT w, UINT y, UCHAR **map)
1389 /*---------------------------------------------------------------------------*/
1390 {
1391   int i, c, c1, x;
1392   LPIXEL *pp;
1393 
1394   /*
1395 *  Codici di ritorno:
1396 *
1397 *     -1:   incontrata la file del file       (EOF)
1398 *     -2:   incontrata la fine della linea    (Escape code 0x00 0x00)
1399 *     -3:   incontrata la fine dell' immagine (Escape code 0x00 0x01)
1400 *  altro:   incontrato un delta               (Escape code 0x00 0x02)
1401 */
1402 
1403   x  = 0;
1404   pp = pic;
1405 
1406   while (1) {
1407     c = getc(fp);
1408     if (c == EOF) return -1;
1409     if (c) { /* encoded mode */
1410       c1 = getc(fp);
1411       for (i = 0; i < c; i++, x++, pp++) {
1412         pp->r = map[0][c1];
1413         pp->g = map[1][c1];
1414         pp->b = map[2][c1];
1415         pp->m = 255;
1416       }
1417     } else /* c==0x00  :  escape codes */
1418     {
1419       c = getc(fp);
1420       if (c == EOF) return -1;
1421       if (c == 0x00) /* end of line */
1422         return -2;
1423       else if (c == 0x01) /* end of pic */
1424         return -3;
1425       else if (c == 0x02) /* delta */
1426       {
1427         c = getc(fp);
1428         x += c;
1429         c = getc(fp);
1430         y += c;
1431 
1432         return (x + y * w);
1433       } else /* absolute mode */
1434       {
1435         for (i = 0; i < c; i++, x++, pp++) {
1436           c1 = getc(fp);
1437 
1438           pp->r = map[0][c1];
1439           pp->g = map[1][c1];
1440           pp->b = map[2][c1];
1441           pp->m = 255;
1442         }
1443         if (c & 1) /* odd length run: read an extra pad byte */
1444           getc(fp);
1445       }
1446     }
1447   }
1448 }
1449 
1450 /*---------------------------------------------------------------------------*/
skip_rowsBMPC8(FILE * fp,UINT rows)1451 static int skip_rowsBMPC8(FILE *fp, UINT rows)
1452 /*---------------------------------------------------------------------------*/
1453 {
1454   int i, c, c1, rv = 0;
1455 
1456   while (rows > 0) {
1457     c = getc(fp);
1458     switch (c) {
1459     case 0x00:
1460       c = getc(fp);
1461       switch (c) {
1462       case 0x00:
1463         rows--;
1464         CASE 0x01 : rows = 0;
1465         CASE 0x02 : c1   = getc(fp); /* x buffer offest */
1466         c1               = getc(fp); /* y buffer offest */
1467         rows -= c1;
1468       DEFAULT:
1469         for (i = 0; i < c; i++) getc(fp);
1470         if (c & 1) getc(fp);
1471       }
1472     DEFAULT:
1473       c1 = getc(fp);
1474     }
1475   }
1476 
1477   if (BMP_FERROR(fp)) rv = 1;
1478 
1479   return rv;
1480 }
1481 
1482 /*---------------------------------------------------------------------------*/
loadBMP24(FILE * fp,LPIXEL * pic,UINT w,UINT h)1483 static int loadBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT h)
1484 /*---------------------------------------------------------------------------*/
1485 {
1486   UINT i, j, padb, rv;
1487   LPIXEL *pp;
1488 
1489   rv = 0;
1490 
1491   padb = (4 - ((w * 3) % 4)) & 0x03; /* # of pad bytes to read at EOscanline */
1492 
1493   for (i = 0; i < h; i++) {
1494 #ifdef BMP_READ_LINE_BY_LINE
1495     pp = pic + i * w;
1496     rv = load_lineBMP24(fp, pp, w, padb);
1497 #else
1498     for (pp = pic + i * w, j = 0; j < w; j++, pp++) {
1499       pp->b = getc(fp); /* blue  */
1500       pp->g = getc(fp); /* green */
1501       pp->r = getc(fp); /* red   */
1502       pp->m = 255;
1503     }
1504     for (j = 0; j < padb; j++) getc(fp);
1505 
1506     rv = (BMP_FERROR(fp));
1507 #endif
1508     if (rv) break;
1509   }
1510 
1511   return rv;
1512 }
1513 
1514 /*---------------------------------------------------------------------------*/
load_lineBMP24(FILE * fp,LPIXEL * pic,UINT w,UINT padb)1515 int load_lineBMP24(FILE *fp, LPIXEL *pic, UINT w, UINT padb)
1516 /*---------------------------------------------------------------------------*/
1517 {
1518   LPIXEL *pp;
1519   UINT j;
1520 
1521   for (pp = pic, j = 0; j < w; j++, pp++) {
1522     pp->b = getc(fp); /* blue  */
1523     pp->g = getc(fp); /* green */
1524     pp->r = getc(fp); /* red   */
1525     pp->m = 255;
1526   }
1527   for (j = 0; j < padb; j++) getc(fp);
1528 
1529   return (BMP_FERROR(fp));
1530 }
1531 
1532 /*---------------------------------------------------------------------------*/
skip_rowsBMP24(FILE * fp,UINT w,UINT pad,UINT rows,int whence)1533 static int skip_rowsBMP24(FILE *fp, UINT w, UINT pad, UINT rows, int whence)
1534 /*---------------------------------------------------------------------------*/
1535 {
1536   UINT offset = (w * 3 + pad) * rows;
1537 
1538   fseek(fp, (long)offset, whence);
1539 
1540   return (BMP_FERROR(fp));
1541 }
1542 
1543 /*---------------------------------------------------------------------------*/
1544 /*-- BMP WRITE --------------------------------------------------------------*/
1545 
1546 /*---------------------------------------------------------------------------*/
bmp_get_colorstyle(IMAGE * img)1547 BMP_SUBTYPE bmp_get_colorstyle(IMAGE *img)
1548 /*---------------------------------------------------------------------------*/
1549 {
1550   return img->type;
1551 }
1552 
1553 /*---------------------------------------------------------------------------*/
write_bmp_header(FILE * fp,BMP_HEADER * hd)1554 int write_bmp_header(FILE *fp, BMP_HEADER *hd)
1555 /*---------------------------------------------------------------------------*/
1556 {
1557   putc('B', fp);
1558   putc('M', fp); /* BMP file magic number           */
1559 
1560   putint(fp, (int)hd->bfSize);
1561   putshort(fp, 0); /* reserved1                       */
1562   putshort(fp, 0); /* reserved2                       */
1563 
1564   putint(fp, (int)hd->bfOffBits); /* offset from BOfile to BObitmap */
1565 
1566   putint(fp, (int)hd->biSize);       /* size of bitmap info header     */
1567   putint(fp, (int)hd->biWidth);      /* width                          */
1568   putint(fp, (int)hd->biHeight);     /* height                         */
1569   putshort(fp, (int)hd->biPlanes);   /* must be '1'                    */
1570   putshort(fp, (int)hd->biBitCount); /* 1,4,8, or 24                   */
1571   putint(fp,
1572          (int)hd->biCompression);   /* BMP_BI_RGB, BMP_BI_RLE8 or BMP_BI_RLE4 */
1573   putint(fp, (int)hd->biSizeImage); /* size of raw image data         */
1574   putint(fp, (int)hd->biXPelsPerMeter); /* dpi * 39" per meter            */
1575   putint(fp, (int)hd->biYPelsPerMeter); /* dpi * 39" per meter            */
1576   putint(fp, (int)hd->biClrUsed);       /* colors used in cmap            */
1577   putint(fp, (int)hd->biClrImportant);  /* same as above                  */
1578 
1579   if (BMP_FERROR(fp)) return FALSE;
1580 
1581   return TRUE;
1582 }
1583 
1584 /*---------------------------------------------------------------------------*/
write_bmp_palette(FILE * fp,int nc,UCHAR * b,UCHAR * g,UCHAR * r)1585 int write_bmp_palette(FILE *fp, int nc, UCHAR *b, UCHAR *g, UCHAR *r)
1586 /*---------------------------------------------------------------------------*/
1587 {
1588   int i;
1589 
1590   for (i = 0; i < nc; i++) {
1591     putc(b[i], fp);
1592     putc(g[i], fp);
1593     putc(r[i], fp);
1594     putc(0, fp);
1595   }
1596 
1597   if (BMP_FERROR(fp)) return FALSE;
1598 
1599   return TRUE;
1600 }
1601 
1602 #ifndef __LIBSIMAGE__
1603 
1604 /*---------------------------------------------------------------------------*/
img_write_bmp(const MYSTRING fname,IMAGE * img)1605 int img_write_bmp(const MYSTRING fname, IMAGE *img)
1606 /*---------------------------------------------------------------------------*/
1607 {
1608   int (*write_function)(FILE * fp, UCHAR * pic, UINT w, UINT h, UCHAR * map);
1609   int h, w, i, nc, nbits, bperlin, comp;
1610   UCHAR val;
1611   UCHAR pc2nc[256], r1[256], g1[256], b1[256];
1612   UCHAR *pic, *graypic;
1613   BMP_SUBTYPE subtype;
1614   BMP_HEADER hd;
1615   FILE *fp;
1616 
1617   subtype = bmp_get_colorstyle(img);
1618   if (subtype == BMP_NONE) return UNSUPPORTED_BMP_FORMAT;
1619 
1620   fp = _wfopen(fname, L"wb");
1621   if (!fp) return CANT_OPEN_FILE;
1622 
1623   graypic = NULL;
1624   nc      = 0;
1625   nbits   = 0;
1626   comp    = 0;
1627   h       = img->ysize;
1628   w       = img->xsize;
1629   pic     = (UCHAR *)img->buffer;
1630 
1631   switch (subtype) {
1632   case BMP_BW:
1633     __OR BMP_GREY16 : __OR BMP_GREY16C :
1634 
1635                       __OR BMP_CMAPPED256 : __OR BMP_CMAPPED256C
1636                                             : return UNSUPPORTED_BMP_FORMAT;
1637     CASE BMP_GREY256 : __OR BMP_GREY256C : nbits = 8;
1638     CASE BMP_RGB : nbits                         = 24;
1639   DEFAULT:
1640     goto BMP_WRITE_ERROR;
1641   }
1642 
1643   /* number bytes written per line */
1644   bperlin = ((w * nbits + 31) / 32) * 4;
1645 
1646   /* compute filesize and write it */
1647   i = 14 +         /* size of bitmap file header */
1648       40 +         /* size of bitmap info header */
1649       (nc * 4) +   /* size of colormap */
1650       bperlin * h; /* size of image data */
1651 
1652   switch (nbits) {
1653   case 4:
1654     comp          = (comp == TRUE) ? BMP_BI_RLE4 : BMP_BI_RGB;
1655     CASE 8 : comp = (comp == TRUE) ? BMP_BI_RLE8 : BMP_BI_RGB;
1656   DEFAULT:
1657     comp = BMP_BI_RGB;
1658   }
1659 
1660   /* fill image header */
1661   hd.bfSize          = i;
1662   hd.bfOffBits       = 14 + 40 + (nc * 4);
1663   hd.biSize          = 40;
1664   hd.biWidth         = w;
1665   hd.biHeight        = h;
1666   hd.biPlanes        = 1;
1667   hd.biBitCount      = nbits;
1668   hd.biCompression   = comp;
1669   hd.biSizeImage     = bperlin * h;
1670   hd.biXPelsPerMeter = 0 * 39;
1671   hd.biYPelsPerMeter = 0 * 39;
1672   hd.biClrUsed       = nc;
1673   hd.biClrImportant  = nc;
1674 
1675   if (!write_bmp_header(fp, &hd)) goto BMP_WRITE_ERROR;
1676 
1677   write_bmp_palette(fp, nc, b1, g1, r1);
1678 
1679   switch (nbits) {
1680   case 1:
1681     write_function                                  = writeBMP1;
1682     CASE 4 : if (comp == BMP_BI_RGB) write_function = writeBMP4;
1683     else write_function                             = writeBMPC4;
1684     CASE 8 : if (comp == BMP_BI_RGB) write_function = writeBMP8;
1685     else write_function                             = writeBMPC8;
1686     CASE 24 : write_function                        = writeBMP24;
1687   DEFAULT:
1688     goto BMP_WRITE_ERROR;
1689   }
1690 
1691   /* write out the image */
1692   val = write_function(fp, pic, (unsigned int)w, (unsigned int)h, pc2nc);
1693 
1694   if (graypic) free(graypic);
1695   fclose(fp);
1696 
1697   /* 0 failed , 1 ok */
1698   return val == 1 ? OK : WRITE_ERROR;
1699 
1700 BMP_WRITE_ERROR:
1701 
1702   fclose(fp);
1703   if (graypic) free(graypic);
1704 
1705   _wremove(fname);
1706 
1707   return WRITE_ERROR;
1708 }
1709 
1710 #endif /* __LIBSIMAGE__ */
1711 
1712 /*---------------------------------------------------------------------------*/
writeBMP1(FILE * fp,UCHAR * pic8,UINT w,UINT h,UCHAR * pc2nc)1713 static int writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc)
1714 /*---------------------------------------------------------------------------*/
1715 {
1716   UINT i, j, c, bitnum, padw;
1717   UCHAR *pp;
1718 
1719   padw = ((w + 31) / 32) * 32; /* 'w', padded to be a multiple of 32 */
1720 
1721   for (i = 0; i < h; i++) {
1722     pp = pic8 + (i * w);
1723 #ifdef BMP_WRITE_LINE_BY_LINE
1724     if (line_writeBMP1(fp, pp, w, padw, pc2nc) == FALSE) return FALSE;
1725 #else
1726     for (j = bitnum = c = 0; j <= padw; j++, bitnum++) {
1727       if (bitnum == 8) /* write the next byte */
1728       {
1729         putc((int)c, fp);
1730         bitnum = c = 0;
1731       }
1732       c <<= 1;
1733       if (j < w) {
1734         c |= (pc2nc[*pp++] & 0x01);
1735       }
1736     }
1737 #endif
1738   }
1739   if (BMP_FERROR(fp)) return FALSE;
1740 
1741   return TRUE;
1742 }
1743 
1744 /*---------------------------------------------------------------------------*/
line_writeBMP1(FILE * fp,UCHAR * pic8,UINT w,UINT padw,UCHAR * pc2nc)1745 static int line_writeBMP1(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
1746                           UCHAR *pc2nc)
1747 /*---------------------------------------------------------------------------*/
1748 {
1749   UCHAR *pp = pic8;
1750   UINT j, c, bitnum;
1751 
1752   for (j = bitnum = c = 0; j <= padw; j++, bitnum++) {
1753     if (bitnum == 8) /* write the next byte */
1754     {
1755       putc((int)c, fp);
1756       bitnum = c = 0;
1757     }
1758     c <<= 1;
1759     if (j < w) {
1760       c |= (pc2nc[*pp++] & 0x01);
1761     }
1762   }
1763   if (BMP_FERROR(fp)) return FALSE;
1764 
1765   return TRUE;
1766 }
1767 
1768 /*---------------------------------------------------------------------------*/
writeBMP4(FILE * fp,UCHAR * pic8,UINT w,UINT h,UCHAR * pc2nc)1769 static int writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc)
1770 /*---------------------------------------------------------------------------*/
1771 {
1772   UINT i, j, c, nybnum, padw;
1773   UCHAR *pp;
1774 
1775   padw = ((w + 7) / 8) * 8; /* 'w' padded to a multiple of 8pix (32 bits) */
1776 
1777   for (i = 0; i < h; i++) {
1778     pp = pic8 + (i * w);
1779 #ifdef BMP_WRITE_LINE_BY_LINE
1780     if (line_writeBMP4(fp, pp, w, padw, pc2nc) == FALSE) return FALSE;
1781 #else
1782     for (j = nybnum = c = 0; j <= padw; j++, nybnum++) {
1783       if (nybnum == 2) /* write next byte */
1784       {
1785         putc((int)(c & 0xff), fp);
1786         nybnum = c = 0;
1787       }
1788       c <<= 4;
1789       if (j < w) {
1790         c |= (pc2nc[*pp] & 0x0f);
1791         pp++;
1792       }
1793     }
1794 #endif
1795   }
1796   if (BMP_FERROR(fp)) return FALSE;
1797 
1798   return TRUE;
1799 }
1800 
1801 /*---------------------------------------------------------------------------*/
line_writeBMP4(FILE * fp,UCHAR * pic8,UINT w,UINT padw,UCHAR * pc2nc)1802 static int line_writeBMP4(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
1803                           UCHAR *pc2nc)
1804 /*---------------------------------------------------------------------------*/
1805 {
1806   UINT j, c, nybnum;
1807   UCHAR *pp = pic8;
1808 
1809   for (j = nybnum = c = 0; j <= padw; j++, nybnum++) {
1810     if (nybnum == 2) /* write next byte */
1811     {
1812       putc((int)(c & 0xff), fp);
1813       nybnum = c = 0;
1814     }
1815     c <<= 4;
1816     if (j < w) {
1817       c |= (pc2nc[*pp] & 0x0f);
1818       pp++;
1819     }
1820   }
1821   if (BMP_FERROR(fp)) return FALSE;
1822 
1823   return TRUE;
1824 }
1825 
1826 /*---------------------------------------------------------------------------*/
writeBMPC4(FILE * fp,UCHAR * pic8,UINT w,UINT h,UCHAR * pc2nc)1827 static int writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc)
1828 /*---------------------------------------------------------------------------*/
1829 {
1830   UCHAR *pp1, *pp2, *pp3, byte1, byte2;
1831   UINT i, cnt;
1832 
1833   for (i = 0; i < h; i++) {
1834     pp1 = pic8 + i * w;
1835     pp2 = pp1 + 2;
1836     pp3 = pp1 + w + 2;
1837 
1838     for (; pp2 < pp3; pp2 += 2) {
1839       cnt = 2;
1840 
1841       byte1 = ((pc2nc[*pp1] << 4) & 0xf0) | (pc2nc[*(pp1 + 1)] & 0x0f);
1842       byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f);
1843 
1844       if (byte1 != byte2) {
1845         putc((int)cnt, fp);
1846         putc(byte1, fp);
1847         pp1 = pp2;
1848       } else {
1849         while (cnt <= 254 && pp2 < pp3) {
1850           cnt += 2;
1851           pp2 += 2;
1852           byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f);
1853           if (byte1 != byte2 || cnt >= 254 || pp2 + 2 > pp3) {
1854             if (pp2 + 2 > pp3) cnt -= 2;
1855             putc((int)cnt, fp);
1856             putc(byte1, fp);
1857             break;
1858           }
1859         }
1860         pp1 = pp2;
1861       }
1862     }
1863     putc(0x00, fp);
1864     putc(0x00, fp);
1865     if (BMP_FERROR(fp)) return FALSE;
1866   }
1867   putc(0x00, fp);
1868   putc(0x01, fp);
1869 
1870   if (BMP_FERROR(fp)) return FALSE;
1871 
1872   return TRUE;
1873 }
1874 
1875 /*---------------------------------------------------------------------------*/
line_writeBMPC4(FILE * fp,UCHAR * pic8,UINT w,UINT row,UCHAR * pc2nc)1876 static int line_writeBMPC4(FILE *fp, UCHAR *pic8, UINT w, UINT row,
1877                            UCHAR *pc2nc)
1878 /*---------------------------------------------------------------------------*/
1879 {
1880   UCHAR *pp1, *pp2, *pp3, byte1, byte2;
1881   UINT cnt;
1882 
1883   pp1 = pic8 + row * w;
1884   pp2 = pp1 + 2;
1885   pp3 = pp1 + w + 2;
1886 
1887   for (; pp2 < pp3; pp2 += 2) {
1888     cnt = 2;
1889 
1890     byte1 = ((pc2nc[*pp1] << 4) & 0xf0) | (pc2nc[*(pp1 + 1)] & 0x0f);
1891     byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f);
1892 
1893     if (byte1 != byte2) {
1894       putc((int)cnt, fp);
1895       putc(byte1, fp);
1896       pp1 = pp2;
1897     } else {
1898       while (cnt <= 254 && pp2 < pp3) {
1899         cnt += 2;
1900         pp2 += 2;
1901         byte2 = ((pc2nc[*pp2] << 4) & 0xf0) | (pc2nc[*(pp2 + 1)] & 0x0f);
1902         if (byte1 != byte2 || cnt >= 254 || pp2 + 2 > pp3) {
1903           if (pp2 + 2 > pp3) cnt -= 2;
1904           putc((int)cnt, fp);
1905           putc(byte1, fp);
1906           break;
1907         }
1908       }
1909       pp1 = pp2;
1910     }
1911   }
1912   putc(0x00, fp);
1913   putc(0x00, fp);
1914 
1915   if (BMP_FERROR(fp)) return FALSE;
1916 
1917   return TRUE;
1918 }
1919 
1920 /*---------------------------------------------------------------------------*/
writeBMP8(FILE * fp,UCHAR * pic8,UINT w,UINT h,UCHAR * pc2nc)1921 static int writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc)
1922 /*---------------------------------------------------------------------------*/
1923 {
1924   UINT i, j, padw;
1925   UCHAR *pp;
1926 
1927   padw = ((w + 3) / 4) * 4; /* 'w' padded to a multiple of 4pix (32 bits) */
1928 
1929   for (i = 0; i < h; i++) {
1930     pp = pic8 + (i * w);
1931 #ifdef BMP_WRITE_LINE_BY_LINE
1932     if (line_writeBMP8(fp, pp, w, padw, pc2nc) == FALSE) return FALSE;
1933 #else
1934     /* for (j=0; j<w; j++) putc(pc2nc[*pp++], fp);*/
1935     for (j = 0; j < w; j++) {
1936       putc(*pp, fp);
1937       pp++;
1938     }
1939     for (; j < padw; j++) putc(0, fp);
1940 #endif
1941   }
1942   if (BMP_FERROR(fp)) return FALSE;
1943 
1944   return TRUE;
1945 }
1946 
1947 /*---------------------------------------------------------------------------*/
line_writeBMP8(FILE * fp,UCHAR * pic8,UINT w,UINT padw,UCHAR * pc2nc)1948 static int line_writeBMP8(FILE *fp, UCHAR *pic8, UINT w, UINT padw,
1949                           UCHAR *pc2nc)
1950 /*---------------------------------------------------------------------------*/
1951 {
1952   UCHAR *pp = pic8;
1953   UINT j;
1954 
1955   for (j = 0; j < w; j++) putc(pc2nc[*pp++], fp);
1956   for (; j < padw; j++) putc(0, fp);
1957   if (BMP_FERROR(fp)) return FALSE;
1958 
1959   return TRUE;
1960 }
1961 
1962 /*---------------------------------------------------------------------------*/
writeBMPC8(FILE * fp,UCHAR * pic8,UINT w,UINT h,UCHAR * pc2nc)1963 static int writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT h, UCHAR *pc2nc)
1964 /*---------------------------------------------------------------------------*/
1965 {
1966   UCHAR *pp1, *pp2, *pp3, byte1, byte2;
1967   UINT i, cnt;
1968 
1969   for (i = 0; i < h; i++) {
1970     pp1 = pic8 + i * w;
1971     pp2 = pp1 + 1;
1972     pp3 = pp1 + w + 1;
1973 
1974     for (; pp2 < pp3; pp2++) {
1975       cnt = 1;
1976 
1977       byte1 = pc2nc[*pp1];
1978       byte2 = pc2nc[*pp2];
1979 
1980       if (byte1 != byte2) {
1981         putc((int)cnt, fp);
1982         putc(byte1, fp);
1983         pp1 = pp2;
1984       } else {
1985         while (cnt <= 254 && pp2 < pp3) {
1986           cnt++;
1987           pp2++;
1988           byte2 = pc2nc[*pp2];
1989           if (byte1 != byte2 || cnt >= 254 || pp2 + 1 > pp3) {
1990             if (pp2 + 1 > pp3) cnt--;
1991             putc((int)cnt, fp);
1992             putc(byte1, fp);
1993             break;
1994           }
1995         }
1996         pp1 = pp2;
1997       }
1998     }
1999     putc(0x00, fp);
2000     putc(0x00, fp);
2001     if (BMP_FERROR(fp)) return FALSE;
2002   }
2003   putc(0x00, fp);
2004   putc(0x01, fp);
2005 
2006   if (BMP_FERROR(fp)) return FALSE;
2007 
2008   return TRUE;
2009 }
2010 
2011 /*---------------------------------------------------------------------------*/
line_writeBMPC8(FILE * fp,UCHAR * pic8,UINT w,UINT row,UCHAR * pc2nc)2012 static int line_writeBMPC8(FILE *fp, UCHAR *pic8, UINT w, UINT row,
2013                            UCHAR *pc2nc)
2014 /*---------------------------------------------------------------------------*/
2015 {
2016   UCHAR *pp1, *pp2, *pp3, byte1, byte2;
2017   UINT cnt;
2018 
2019   pp1 = pic8 + row * w;
2020   pp2 = pp1 + 1;
2021   pp3 = pp1 + w + 1;
2022 
2023   for (; pp2 < pp3; pp2++) {
2024     cnt = 1;
2025 
2026     byte1 = pc2nc[*pp1];
2027     byte2 = pc2nc[*pp2];
2028 
2029     if (byte1 != byte2) {
2030       putc((int)cnt, fp);
2031       putc(byte1, fp);
2032       pp1 = pp2;
2033     } else {
2034       while (cnt <= 254 && pp2 < pp3) {
2035         cnt++;
2036         pp2++;
2037         byte2 = pc2nc[*pp2];
2038         if (byte1 != byte2 || cnt >= 254 || pp2 + 1 > pp3) {
2039           if (pp2 + 1 > pp3) cnt--;
2040           putc((int)cnt, fp);
2041           putc(byte1, fp);
2042           break;
2043         }
2044       }
2045       pp1 = pp2;
2046     }
2047   }
2048   putc(0x00, fp);
2049   putc(0x00, fp);
2050 
2051   if (BMP_FERROR(fp)) return FALSE;
2052 
2053   return TRUE;
2054 }
2055 
2056 /*---------------------------------------------------------------------------*/
writeBMP24(FILE * fp,UCHAR * pic24,UINT w,UINT h,UCHAR * whence)2057 static int writeBMP24(FILE *fp, UCHAR *pic24, UINT w, UINT h, UCHAR *whence)
2058 /*---------------------------------------------------------------------------*/
2059 {
2060   UINT i, j, padb;
2061   LPIXEL *pixel;
2062   UCHAR *pp;
2063 
2064   /* pc2nc not used */
2065 
2066   padb = (4 - ((w * 3) % 4)) & 0x03; /* # of pad bytes to write at EOscanline */
2067 
2068   for (i = 0; i < h; i++) {
2069     pp    = pic24 + (i * w * 4);
2070     pixel = (LPIXEL *)pp;
2071 #ifdef BMP_WRITE_LINE_BY_LINE
2072     if (line_writeBMP24(fp, pixel, w, padb) == FALSE) return FALSE;
2073 #else
2074     for (j = 0; j < w; j++) {
2075       putc(pixel->b, fp);
2076       putc(pixel->g, fp);
2077       putc(pixel->r, fp);
2078 
2079       pixel++;
2080     }
2081     for (j = 0; j < padb; j++) putc(0, fp);
2082 #endif
2083   }
2084   if (BMP_FERROR(fp)) return FALSE;
2085 
2086   return TRUE;
2087 }
2088 
2089 /*---------------------------------------------------------------------------*/
line_writeBMP24(FILE * fp,LPIXEL * pp,UINT w,UINT padb)2090 static int line_writeBMP24(FILE *fp, LPIXEL *pp, UINT w, UINT padb)
2091 /*---------------------------------------------------------------------------*/
2092 {
2093   UINT j;
2094 
2095   for (j = 0; j < w; j++) {
2096     putc(pp->b, fp);
2097     putc(pp->g, fp);
2098     putc(pp->r, fp);
2099 
2100     pp++;
2101   }
2102   for (j = 0; j < padb; j++) putc(0, fp);
2103   if (BMP_FERROR(fp)) return FALSE;
2104 
2105   return TRUE;
2106 }
2107 
2108 #ifndef __LIBSIMAGE__
2109 
2110 #ifndef UNUSED_REDUCE_COLORS
2111 /*---------------------------------------------------------------------------*/
reduce_colors(UCHAR * buffin,int xsize,int ysize,UCHAR * rmap,UCHAR * gmap,UCHAR * bmap,int nc)2112 static UCHAR *reduce_colors(UCHAR *buffin, int xsize, int ysize, UCHAR *rmap,
2113                             UCHAR *gmap, UCHAR *bmap, int nc)
2114 /*---------------------------------------------------------------------------*/
2115 {
2116   LPIXEL *curr_pix, *next_pix, *prev_pix, *buffer;
2117   static LPIXEL *mbuffer = NULL;
2118   static UCHAR *ret_buf  = NULL;
2119   static int outbuf_size = 0;
2120   static int buffin_size = 0;
2121   int r1, g1, b1, dim;
2122   int i, j, tmp;
2123   int imax, jmax;
2124   UCHAR *outbuf;
2125   USHORT val;
2126 
2127   dim = xsize * ysize;
2128 
2129   if (dim > outbuf_size) {
2130     if (!ret_buf)
2131       TCALLOC(ret_buf, dim)
2132     else
2133       TREALLOC(ret_buf, dim);
2134     if (!ret_buf) return NULL;
2135     outbuf_size = dim;
2136   }
2137 
2138   if (dim > buffin_size) {
2139     if (!mbuffer)
2140       TCALLOC(mbuffer, dim)
2141     else
2142       TREALLOC(mbuffer, dim);
2143     if (!ret_buf) return NULL;
2144     buffin_size = dim;
2145   }
2146 
2147   memcpy(mbuffer, buffin, dim * sizeof(LPIXEL));
2148   buffer = mbuffer;
2149   outbuf = ret_buf;
2150 
2151   imax = ysize - 1;
2152   jmax = xsize - 1;
2153 
2154   for (i = 0; i < ysize; i++) {
2155     curr_pix = buffer;
2156     buffer += xsize;
2157     next_pix = buffer;
2158     prev_pix = NIL;
2159 
2160     for (j = 0; j < xsize; j++) {
2161       r1 = curr_pix->r;
2162       g1 = curr_pix->g;
2163       b1 = curr_pix->b;
2164 
2165       val = BMP_REDUCE_COLORS(r1, g1, b1);
2166 
2167       *(outbuf++) = (unsigned char)val;
2168 
2169       /* errors on colors */
2170       r1 -= rmap[val];
2171       g1 -= gmap[val];
2172       b1 -= bmap[val];
2173 
2174       if (j != jmax) BMP_ADD_ERROR(curr_pix[1], 7) /*  RIGHT   */
2175       if (i != imax)                               /*  UP      */
2176       {
2177         BMP_ADD_ERROR(*next_pix, 5)
2178         if (j > 0) BMP_ADD_ERROR(*prev_pix, 3)       /* UP LEFT  */
2179         if (j != jmax) BMP_ADD_ERROR(next_pix[1], 1) /* UP RIGHT */
2180         prev_pix = next_pix;
2181         next_pix++;
2182       }
2183       curr_pix++;
2184     }
2185   }
2186 
2187   return ret_buf;
2188 }
2189 #endif
2190 
2191 #endif /* __LIBSIMAGE__ */
2192 
2193 /*---------------------------------------------------------------------------*/
make_bmp_palette(int colors,int grey,UCHAR * r,UCHAR * g,UCHAR * b)2194 int make_bmp_palette(int colors, int grey, UCHAR *r, UCHAR *g, UCHAR *b)
2195 /*---------------------------------------------------------------------------*/
2196 {
2197   int i, j, ind, val;
2198 
2199   switch (colors) {
2200   case 2:
2201     for (i = 0; i < 2; i++) r[i] = g[i] = b[i] = i * 255;
2202     CASE 16 : for (i = 0; i < 16; i++) {
2203       for (j = 0; j < 16; j++) {
2204         ind    = i * 16 + j;
2205         val    = i * 16;
2206         r[ind] = g[ind] = b[ind] = val;
2207       }
2208     }
2209     CASE 256 : if (grey) {
2210       for (i = 0; i < 256; i++) r[i] = g[i] = b[i] = i;
2211     }
2212     else {
2213       for (i = 0; i < 256; i++) {
2214         r[i] = BMP_RMAP(i);
2215         g[i] = BMP_GMAP(i);
2216         b[i] = BMP_BMAP(i);
2217       }
2218     }
2219   DEFAULT:
2220     return FALSE;
2221   }
2222 
2223   return TRUE;
2224 }
2225 
2226 /*---------------------------------------------------------------------------*/
getshort(FILE * fp)2227 static UINT getshort(FILE *fp)
2228 /*---------------------------------------------------------------------------*/
2229 {
2230   int c = getc(fp), c1 = getc(fp);
2231 
2232   return ((UINT)c) + (((UINT)c1) << 8);
2233 }
2234 
2235 /*---------------------------------------------------------------------------*/
getint(FILE * fp)2236 static UINT getint(FILE *fp)
2237 /*---------------------------------------------------------------------------*/
2238 {
2239   int c = getc(fp), c1 = getc(fp), c2 = getc(fp), c3 = getc(fp);
2240 
2241   return (((UINT)c) << 0) + (((UINT)c1) << 8) + (((UINT)c2) << 16) +
2242          (((UINT)c3) << 24);
2243 }
2244 
2245 /*---------------------------------------------------------------------------*/
putshort(FILE * fp,int i)2246 static void putshort(FILE *fp, int i)
2247 /*---------------------------------------------------------------------------*/
2248 {
2249   int c = (((UINT)i)) & 0xff, c1 = (((UINT)i) >> 8) & 0xff;
2250 
2251   putc(c, fp);
2252   putc(c1, fp);
2253 }
2254 
2255 /*---------------------------------------------------------------------------*/
putint(FILE * fp,int i)2256 static void putint(FILE *fp, int i)
2257 /*---------------------------------------------------------------------------*/
2258 {
2259   int c = ((UINT)i) & 0xff, c1 = (((UINT)i) >> 8) & 0xff,
2260       c2 = (((UINT)i) >> 16) & 0xff, c3 = (((UINT)i) >> 24) & 0xff;
2261 
2262   putc(c, fp);
2263   putc(c1, fp);
2264   putc(c2, fp);
2265   putc(c3, fp);
2266 }
2267 
2268 /*---------------------------------------------------------------------------*/
2269 
writebmp(const MYSTRING filename,int xsize,int ysize,void * buffer,int bpp)2270 int writebmp(const MYSTRING filename, int xsize, int ysize, void *buffer,
2271              int bpp) {
2272   IMAGE img;
2273   img.xsize  = xsize;
2274   img.ysize  = ysize;
2275   img.buffer = buffer;
2276   switch (bpp) {
2277   case 8:
2278     img.type           = BMP_GREY256C;
2279     CASE 32 : img.type = BMP_RGB;
2280   }
2281   return img_write_bmp(filename, &img);
2282 }
2283 
2284 /*---------------------------------------------------------------------------*/
2285 
readbmp(const MYSTRING filename,int * xsize,int * ysize,void ** buffer)2286 int readbmp(const MYSTRING filename, int *xsize, int *ysize, void **buffer) {
2287   IMAGE *img;
2288   int retCode = img_read_bmp(filename, &img);
2289   if (retCode != OK) {
2290     *xsize = *ysize = 0;
2291     *buffer         = 0;
2292   } else {
2293     *xsize      = img->xsize;
2294     *ysize      = img->ysize;
2295     *buffer     = img->buffer;
2296     img->buffer = 0;
2297     free_img(img);
2298   }
2299   return retCode;
2300 }
2301 
2302 /*---------------------------------------------------------------------------*/
2303 
readbmpregion(const MYSTRING filename,void ** pimg,int x1,int y1,int x2,int y2,int scale)2304 int readbmpregion(const MYSTRING filename, void **pimg, int x1, int y1, int x2,
2305                   int y2, int scale) {
2306   IMAGE *img;
2307 
2308   int retCode = img_read_bmp_region(filename, &img, x1, y1, x2, y2, scale);
2309 
2310   if (retCode != OK) {
2311     *pimg = 0;
2312   } else {
2313     *pimg = img->buffer;
2314     free(img);
2315   }
2316   return retCode;
2317 }
2318 /*---------------------------------------------------------------------------*/
2319 
readbmp_size(const MYSTRING fname,int * lx,int * ly)2320 int readbmp_size(const MYSTRING fname, int *lx, int *ly) {
2321   IMAGE *img;
2322   int retCode = img_read_bmp_generic(fname, BMP_READ_INFO, &img);
2323   if (retCode == OK) {
2324     *lx = img->xsize;
2325     *ly = img->ysize;
2326     free(img);
2327   }
2328   return retCode;
2329 }
2330 
2331 /*---------------------------------------------------------------------------*/
2332 
readbmp_bbox(const MYSTRING fname,int * x0,int * y0,int * x1,int * y1)2333 int readbmp_bbox(const MYSTRING fname, int *x0, int *y0, int *x1, int *y1) {
2334   IMAGE *img;
2335   int retCode = img_read_bmp_generic(fname, BMP_READ_INFO, &img);
2336   if (retCode == OK) {
2337     *x0 = 0;
2338     *x1 = 0;
2339     *x1 = img->xsize - 1;
2340     *y1 = img->ysize - 1;
2341     free(img);
2342   }
2343   return retCode;
2344 }
2345