w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

greymap.c
Go to the documentation of this file.
1 /* Copyright (C) 2001-2019 Peter Selinger.
2  This file is part of Potrace. It is free software and it is covered
3  by the GNU General Public License. See the file COPYING for details. */
4 
5 
6 /* Routines for manipulating greymaps, including reading pgm files. We
7  only deal with greymaps of depth 8 bits. */
8 
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include <math.h>
16 #include <errno.h>
17 #include <stddef.h>
18 #ifdef HAVE_INTTYPES_H
19 #include <inttypes.h>
20 #endif
21 
22 #include "greymap.h"
23 #include "bitops.h"
24 
25 #define INTBITS (8*sizeof(int))
26 
27 #define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
28 
29 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
30 static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
31 
32 #define TRY(x) if (x) goto try_error
33 #define TRY_EOF(x) if (x) goto eof
34 #define TRY_STD(x) if (x) goto std_error
35 
36 /* ---------------------------------------------------------------------- */
37 /* basic greymap routines */
38 
39 /* calculate the size, in bytes, required for the data area of a
40  greymap of the given dy and h. Assume h >= 0. Return -1 if the size
41  does not fit into the ptrdiff_t type. */
42 static inline ptrdiff_t getsize(int dy, int h) {
44 
45  if (dy < 0) {
46  dy = -dy;
47  }
48 
50 
51  /* check for overflow error */
52  if (size < 0 || (h != 0 && dy != 0 && size / h / dy != GM_SAMPLESIZE)) {
53  return -1;
54  }
55 
56  return size;
57 }
58 
59 /* return the size, in bytes, of the data area of the greymap. Return
60  -1 if the size does not fit into the ptrdiff_t type; however, this
61  cannot happen if the bitmap is well-formed, i.e., if created with
62  gm_new or gm_dup. */
63 static inline ptrdiff_t gm_size(const greymap_t *gm) {
64  return getsize(gm->dy, gm->h);
65 }
66 
67 
68 
69 /* return new greymap initialized to 0. NULL with errno on error.
70  Assumes w, h >= 0. */
71 greymap_t *gm_new(int w, int h) {
72  greymap_t *gm;
73  int dy = w;
75 
76  size = getsize(dy, h);
77  if (size < 0) {
78  errno = ENOMEM;
79  return NULL;
80  }
81  if (size == 0) {
82  size = GM_SAMPLESIZE; /* make sure calloc() doesn't return NULL */
83  }
84 
85  gm = (greymap_t *) malloc(sizeof(greymap_t));
86  if (!gm) {
87  return NULL;
88  }
89  gm->w = w;
90  gm->h = h;
91  gm->dy = dy;
92  gm->base = (gm_sample_t *) calloc(1, size);
93  if (!gm->base) {
94  free(gm);
95  return NULL;
96  }
97  gm->map = gm->base;
98  return gm;
99 }
100 
101 /* free the given greymap */
103  if (gm) {
104  free(gm->base);
105  }
106  free(gm);
107 }
108 
109 /* duplicate the given greymap. Return NULL on error with errno set. */
111  greymap_t *gm1 = gm_new(gm->w, gm->h);
112  int y;
113 
114  if (!gm1) {
115  return NULL;
116  }
117  for (y=0; y<gm->h; y++) {
118  memcpy(gm_scanline(gm1, y), gm_scanline(gm, y), (size_t)gm1->dy * GM_SAMPLESIZE);
119  }
120  return gm1;
121 }
122 
123 /* clear the given greymap to color b. */
124 void gm_clear(greymap_t *gm, int b) {
126  int x, y;
127 
128  if (b==0) {
129  memset(gm->base, 0, size);
130  } else {
131  for (y=0; y<gm->h; y++) {
132  for (x=0; x<gm->w; x++) {
133  GM_UPUT(gm, x, y, b);
134  }
135  }
136  }
137 }
138 
139 /* turn the given greymap upside down. This does not move the pixel
140  data or change the base address. */
141 static inline void gm_flip(greymap_t *gm) {
142  int dy = gm->dy;
143 
144  if (gm->h == 0 || gm->h == 1) {
145  return;
146  }
147 
148  gm->map = gm_scanline(gm, gm->h - 1);
149  gm->dy = -dy;
150 }
151 
152 /* resize the greymap to the given new height. The pixel data remains
153  bottom-aligned (truncated at the top) when dy >= 0 and top-aligned
154  (truncated at the bottom) when dy < 0. Return 0 on success, or 1 on
155  error with errno set. If the new height is <= the old one, no error
156  should occur. If the new height is larger, the additional pixel
157  data is *not* initialized. */
158 static inline int gm_resize(greymap_t *gm, int h) {
159  int dy = gm->dy;
160  ptrdiff_t newsize;
161  gm_sample_t *newbase;
162 
163  if (dy < 0) {
164  gm_flip(gm);
165  }
166 
167  newsize = getsize(dy, h);
168  if (newsize < 0) {
169  errno = ENOMEM;
170  goto error;
171  }
172  if (newsize == 0) {
173  newsize = GM_SAMPLESIZE; /* make sure realloc() doesn't return NULL */
174  }
175 
176  newbase = (gm_sample_t *)realloc(gm->base, newsize);
177  if (newbase == NULL) {
178  goto error;
179  }
180  gm->base = newbase;
181  gm->map = newbase;
182  gm->h = h;
183 
184  if (dy < 0) {
185  gm_flip(gm);
186  }
187  return 0;
188 
189  error:
190  if (dy < 0) {
191  gm_flip(gm);
192  }
193  return 1;
194 }
195 
196 
197 /* ---------------------------------------------------------------------- */
198 /* routines for reading pnm streams */
199 
200 /* read next character after whitespace and comments. Return EOF on
201  end of file or error. */
202 static int fgetc_ws(FILE *f) {
203  int c;
204 
205  while (1) {
206  c = fgetc(f);
207  if (c=='#') {
208  while (1) {
209  c = fgetc(f);
210  if (c=='\n' || c==EOF) {
211  break;
212  }
213  }
214  }
215  /* space, tab, line feed, carriage return, form-feed */
216  if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
217  return c;
218  }
219  }
220 }
221 
222 /* skip whitespace and comments, then read a non-negative decimal
223  number from a stream. Return -1 on EOF. Tolerate other errors (skip
224  bad characters). Do not the read any characters following the
225  number (put next character back into the stream) */
226 
227 static int readnum(FILE *f) {
228  int c;
229  uint64_t acc;
230 
231  /* skip whitespace and comments */
232  while (1) {
233  c = fgetc_ws(f);
234  if (c==EOF) {
235  return -1;
236  }
237  if (c>='0' && c<='9') {
238  break;
239  }
240  }
241 
242  /* first digit is already in c */
243  acc = c-'0';
244  while (1) {
245  c = fgetc(f);
246  if (c==EOF) {
247  break;
248  }
249  if (c<'0' || c>'9') {
250  ungetc(c, f);
251  break;
252  }
253  acc *= 10;
254  acc += c-'0';
255  if (acc > 0x7fffffff) {
256  return -1;
257  }
258  }
259  return acc;
260 }
261 
262 /* similar to readnum, but read only a single 0 or 1, and do not read
263  any characters after it. */
264 
265 static int readbit(FILE *f) {
266  int c;
267 
268  /* skip whitespace and comments */
269  while (1) {
270  c = fgetc_ws(f);
271  if (c==EOF) {
272  return -1;
273  }
274  if (c>='0' && c<='1') {
275  break;
276  }
277  }
278 
279  return c-'0';
280 }
281 
282 /* ---------------------------------------------------------------------- */
283 
284 /* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
285  convert the output to a greymap. Return greymap in *gmp. Return 0
286  on success, -1 on error with errno set, -2 on bad file format (with
287  error message in gm_read_error), and 1 on premature end of file, -3
288  on empty file (including files with only whitespace and comments),
289  -4 if wrong magic number. If the return value is >=0, *gmp is
290  valid. */
291 
292 const char *gm_read_error = NULL;
293 
294 int gm_read(FILE *f, greymap_t **gmp) {
295  int magic[2];
296 
297  /* read magic number. We ignore whitespace and comments before the
298  magic, for the benefit of concatenated files in P1-P3 format.
299  Multiple P1-P3 images in a single file are not formally allowed
300  by the PNM standard, but there is no harm in being lenient. */
301 
302  magic[0] = fgetc_ws(f);
303  if (magic[0] == EOF) {
304  /* files which contain only comments and whitespace count as "empty" */
305  return -3;
306  }
307  magic[1] = fgetc(f);
308  if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
309  return gm_readbody_pnm(f, gmp, magic[1]);
310  }
311  if (magic[0] == 'B' && magic[1] == 'M') {
312  return gm_readbody_bmp(f, gmp);
313  }
314  return -4;
315 }
316 
317 /* ---------------------------------------------------------------------- */
318 /* read PNM format */
319 
320 /* read PNM stream after magic number. Return values as for gm_read */
321 static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
322  greymap_t *gm;
323  int x, y, i, j, b, b1, sum;
324  int bpr; /* bytes per row (as opposed to 4*gm->c) */
325  int w, h, max;
326  int realheight; /* in case of incomplete file, keeps track of how
327  many scan lines actually contain data */
328 
329  gm = NULL;
330 
331  w = readnum(f);
332  if (w<0) {
333  goto format_error;
334  }
335 
336  h = readnum(f);
337  if (h<0) {
338  goto format_error;
339  }
340 
341  /* allocate greymap */
342  gm = gm_new(w, h);
343  if (!gm) {
344  goto std_error;
345  }
346 
347  realheight = 0;
348 
349  switch (magic) {
350  default:
351  /* not reached */
352  goto format_error;
353 
354  case '1':
355  /* read P1 format: PBM ascii */
356 
357  for (y=0; y<h; y++) {
358  realheight = y+1;
359  for (x=0; x<w; x++) {
360  b = readbit(f);
361  if (b<0) {
362  goto eof;
363  }
364  GM_UPUT(gm, x, y, b ? 0 : 255);
365  }
366  }
367  break;
368 
369  case '2':
370  /* read P2 format: PGM ascii */
371 
372  max = readnum(f);
373  if (max<1) {
374  goto format_error;
375  }
376 
377  for (y=0; y<h; y++) {
378  realheight = y+1;
379  for (x=0; x<w; x++) {
380  b = readnum(f);
381  if (b<0) {
382  goto eof;
383  }
384  GM_UPUT(gm, x, y, b*255/max);
385  }
386  }
387  break;
388 
389  case '3':
390  /* read P3 format: PPM ascii */
391 
392  max = readnum(f);
393  if (max<1) {
394  goto format_error;
395  }
396 
397  for (y=0; y<h; y++) {
398  realheight = y+1;
399  for (x=0; x<w; x++) {
400  sum = 0;
401  for (i=0; i<3; i++) {
402  b = readnum(f);
403  if (b<0) {
404  goto eof;
405  }
406  sum += b;
407  }
408  GM_UPUT(gm, x, y, sum*(255/3)/max);
409  }
410  }
411  break;
412 
413  case '4':
414  /* read P4 format: PBM raw */
415 
416  b = fgetc(f); /* read single white-space character after height */
417  if (b==EOF) {
418  goto format_error;
419  }
420 
421  bpr = (w+7)/8;
422 
423  for (y=0; y<h; y++) {
424  realheight = y+1;
425  for (i=0; i<bpr; i++) {
426  b = fgetc(f);
427  if (b==EOF) {
428  goto eof;
429  }
430  for (j=0; j<8; j++) {
431  GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
432  }
433  }
434  }
435  break;
436 
437  case '5':
438  /* read P5 format: PGM raw */
439 
440  max = readnum(f);
441  if (max<1) {
442  goto format_error;
443  }
444 
445  b = fgetc(f); /* read single white-space character after max */
446  if (b==EOF) {
447  goto format_error;
448  }
449 
450  for (y=0; y<h; y++) {
451  realheight = y+1;
452  for (x=0; x<w; x++) {
453  b = fgetc(f);
454  if (b==EOF)
455  goto eof;
456  if (max>=256) {
457  b <<= 8;
458  b1 = fgetc(f);
459  if (b1==EOF)
460  goto eof;
461  b |= b1;
462  }
463  GM_UPUT(gm, x, y, b*255/max);
464  }
465  }
466  break;
467 
468  case '6':
469  /* read P6 format: PPM raw */
470 
471  max = readnum(f);
472  if (max<1) {
473  goto format_error;
474  }
475 
476  b = fgetc(f); /* read single white-space character after max */
477  if (b==EOF) {
478  goto format_error;
479  }
480 
481  for (y=0; y<h; y++) {
482  realheight = y+1;
483  for (x=0; x<w; x++) {
484  sum = 0;
485  for (i=0; i<3; i++) {
486  b = fgetc(f);
487  if (b==EOF) {
488  goto eof;
489  }
490  if (max>=256) {
491  b <<= 8;
492  b1 = fgetc(f);
493  if (b1==EOF)
494  goto eof;
495  b |= b1;
496  }
497  sum += b;
498  }
499  GM_UPUT(gm, x, y, sum*(255/3)/max);
500  }
501  }
502  break;
503  }
504 
505  gm_flip(gm);
506  *gmp = gm;
507  return 0;
508 
509  eof:
510  TRY_STD(gm_resize(gm, realheight));
511  gm_flip(gm);
512  *gmp = gm;
513  return 1;
514 
515  format_error:
516  gm_free(gm);
517  if (magic == '1' || magic == '4') {
518  gm_read_error = "invalid pbm file";
519  } else if (magic == '2' || magic == '5') {
520  gm_read_error = "invalid pgm file";
521  } else {
522  gm_read_error = "invalid ppm file";
523  }
524  return -2;
525 
526  std_error:
527  gm_free(gm);
528  return -1;
529 }
530 
531 /* ---------------------------------------------------------------------- */
532 /* read BMP format */
533 
534 struct bmp_info_s {
535  unsigned int FileSize;
536  unsigned int reserved;
537  unsigned int DataOffset;
538  unsigned int InfoSize;
539  unsigned int w; /* width */
540  unsigned int h; /* height */
541  unsigned int Planes;
542  unsigned int bits; /* bits per sample */
543  unsigned int comp; /* compression mode */
544  unsigned int ImageSize;
545  unsigned int XpixelsPerM;
546  unsigned int YpixelsPerM;
547  unsigned int ncolors; /* number of colors in palette */
548  unsigned int ColorsImportant;
549  unsigned int RedMask;
550  unsigned int GreenMask;
551  unsigned int BlueMask;
552  unsigned int AlphaMask;
553  unsigned int ctbits; /* sample size for color table */
554  int topdown; /* top-down mode? */
555 };
556 typedef struct bmp_info_s bmp_info_t;
557 
558 /* auxiliary */
559 
560 static int bmp_count = 0; /* counter for byte padding */
561 static int bmp_pos = 0; /* counter from start of BMP data */
562 
563 /* read n-byte little-endian integer. Return 1 on EOF or error, else
564  0. Assume n<=4. */
565 static int bmp_readint(FILE *f, int n, unsigned int *p) {
566  int i;
567  unsigned int sum = 0;
568  int b;
569 
570  for (i=0; i<n; i++) {
571  b = fgetc(f);
572  if (b==EOF) {
573  return 1;
574  }
575  sum += (unsigned)b << (8*i);
576  }
577  bmp_count += n;
578  bmp_pos += n;
579  *p = sum;
580  return 0;
581 }
582 
583 /* reset padding boundary */
584 static void bmp_pad_reset(void) {
585  bmp_count = 0;
586 }
587 
588 /* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
589  else 0. */
590 static int bmp_pad(FILE *f) {
591  int c, i, b;
592 
593  c = (-bmp_count) & 3;
594  for (i=0; i<c; i++) {
595  b = fgetc(f);
596  if (b==EOF) {
597  return 1;
598  }
599  }
600  bmp_pos += c;
601  bmp_count = 0;
602  return 0;
603 }
604 
605 /* forward to the new file position. Return 1 on EOF or error, else 0 */
606 static int bmp_forward(FILE *f, int pos) {
607  int b;
608 
609  while (bmp_pos < pos) {
610  b = fgetc(f);
611  if (b==EOF) {
612  return 1;
613  }
614  bmp_pos++;
615  bmp_count++;
616  }
617  return 0;
618 }
619 
620 /* safe colortable access */
621 #define COLTABLE(c) ((c) < bmpinfo.ncolors ? coltable[(c)] : 0)
622 
623 /* read BMP stream after magic number. Return values as for gm_read.
624  We choose to be as permissive as possible, since there are many
625  programs out there which produce BMP. For instance, ppmtobmp can
626  produce codings with anywhere from 1-8 or 24 bits per sample,
627  although most specifications only allow 1,4,8,24,32. We can also
628  read both the old and new OS/2 BMP formats in addition to the
629  Windows BMP format. */
630 static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
631  bmp_info_t bmpinfo;
632  int *coltable;
633  unsigned int b, c;
634  unsigned int i, j;
635  greymap_t *gm;
636  unsigned int x, y;
637  int col[2];
638  unsigned int bitbuf;
639  unsigned int n;
640  unsigned int redshift, greenshift, blueshift;
641  int realheight; /* in case of incomplete file, keeps track of how
642  many scan lines actually contain data */
643 
645  gm = NULL;
646  coltable = NULL;
647 
648  bmp_pos = 2; /* set file position */
649 
650  /* file header (minus magic number) */
651  TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
652  TRY(bmp_readint(f, 4, &bmpinfo.reserved));
653  TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
654 
655  /* info header */
656  TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
657  if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64
658  || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) {
659  /* Windows or new OS/2 format */
660  bmpinfo.ctbits = 32; /* sample size in color table */
661  TRY(bmp_readint(f, 4, &bmpinfo.w));
662  TRY(bmp_readint(f, 4, &bmpinfo.h));
663  TRY(bmp_readint(f, 2, &bmpinfo.Planes));
664  TRY(bmp_readint(f, 2, &bmpinfo.bits));
665  TRY(bmp_readint(f, 4, &bmpinfo.comp));
666  TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
667  TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
668  TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
669  TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
670  TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
671  if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
672  TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
673  TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
674  TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
675  TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
676  }
677  if (bmpinfo.w > 0x7fffffff) {
678  goto format_error;
679  }
680  if (bmpinfo.h > 0x7fffffff) {
681  bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
682  bmpinfo.topdown = 1;
683  } else {
684  bmpinfo.topdown = 0;
685  }
686  if (bmpinfo.h > 0x7fffffff) {
687  goto format_error;
688  }
689  } else if (bmpinfo.InfoSize == 12) {
690  /* old OS/2 format */
691  bmpinfo.ctbits = 24; /* sample size in color table */
692  TRY(bmp_readint(f, 2, &bmpinfo.w));
693  TRY(bmp_readint(f, 2, &bmpinfo.h));
694  TRY(bmp_readint(f, 2, &bmpinfo.Planes));
695  TRY(bmp_readint(f, 2, &bmpinfo.bits));
696  bmpinfo.comp = 0;
697  bmpinfo.ncolors = 0;
698  bmpinfo.topdown = 0;
699  } else {
700  goto format_error;
701  }
702 
703  if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
704  /* bitfield feature is only understood with V4 and V5 format */
705  goto format_error;
706  }
707 
708  if (bmpinfo.comp > 3 || bmpinfo.bits > 32) {
709  goto format_error;
710  }
711 
712  /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
713  TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
714 
715  if (bmpinfo.Planes != 1) {
716  gm_read_error = "cannot handle bmp planes";
717  goto format_error; /* can't handle planes */
718  }
719 
720  if (bmpinfo.ncolors == 0 && bmpinfo.bits <= 8) {
721  bmpinfo.ncolors = 1 << bmpinfo.bits;
722  }
723 
724  /* color table, present only if bmpinfo.bits <= 8. */
725  if (bmpinfo.bits <= 8) {
726  coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
727  if (!coltable) {
728  goto std_error;
729  }
730  /* NOTE: since we are reading a greymap, we can immediately convert
731  the color table entries to grey values. */
732  for (i=0; i<bmpinfo.ncolors; i++) {
733  TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
734  c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
735  coltable[i] = c/3;
736  }
737  }
738 
739  /* forward to data */
740  if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
741  TRY(bmp_forward(f, bmpinfo.DataOffset));
742  }
743 
744  /* allocate greymap */
745  gm = gm_new(bmpinfo.w, bmpinfo.h);
746  if (!gm) {
747  goto std_error;
748  }
749 
750  realheight = 0;
751 
752  switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
753 
754  default:
755  goto format_error;
756  break;
757 
758  case 0x001: /* monochrome palette */
759 
760  /* raster data */
761  for (y=0; y<bmpinfo.h; y++) {
762  realheight = y+1;
763  bmp_pad_reset();
764  for (i=0; 8*i<bmpinfo.w; i++) {
765  TRY_EOF(bmp_readint(f, 1, &b));
766  for (j=0; j<8; j++) {
767  GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? COLTABLE(1) : COLTABLE(0));
768  }
769  }
770  TRY(bmp_pad(f));
771  }
772  break;
773 
774  case 0x002: /* 2-bit to 8-bit palettes */
775  case 0x003:
776  case 0x004:
777  case 0x005:
778  case 0x006:
779  case 0x007:
780  case 0x008:
781  for (y=0; y<bmpinfo.h; y++) {
782  realheight = y+1;
783  bmp_pad_reset();
784  bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
785  n = 0; /* number of bits currently in bitbuffer */
786  for (x=0; x<bmpinfo.w; x++) {
787  if (n < bmpinfo.bits) {
788  TRY_EOF(bmp_readint(f, 1, &b));
789  bitbuf |= b << (INTBITS - 8 - n);
790  n += 8;
791  }
792  b = bitbuf >> (INTBITS - bmpinfo.bits);
793  bitbuf <<= bmpinfo.bits;
794  n -= bmpinfo.bits;
795  GM_UPUT(gm, x, y, COLTABLE(b));
796  }
797  TRY(bmp_pad(f));
798  }
799  break;
800 
801  case 0x010: /* 16-bit encoding */
802  /* can't do this format because it is not well-documented and I
803  don't have any samples */
804  gm_read_error = "cannot handle bmp 16-bit coding";
805  goto format_error;
806  break;
807 
808  case 0x018: /* 24-bit encoding */
809  case 0x020: /* 32-bit encoding */
810  for (y=0; y<bmpinfo.h; y++) {
811  realheight = y+1;
812  bmp_pad_reset();
813  for (x=0; x<bmpinfo.w; x++) {
814  TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
815  c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
816  GM_UPUT(gm, x, y, c/3);
817  }
818  TRY(bmp_pad(f));
819  }
820  break;
821 
822  case 0x320: /* 32-bit encoding with bitfields */
823  redshift = lobit(bmpinfo.RedMask);
824  greenshift = lobit(bmpinfo.GreenMask);
825  blueshift = lobit(bmpinfo.BlueMask);
826 
827  for (y=0; y<bmpinfo.h; y++) {
828  realheight = y+1;
829  bmp_pad_reset();
830  for (x=0; x<bmpinfo.w; x++) {
831  TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
832  c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
833  GM_UPUT(gm, x, y, c/3);
834  }
835  TRY(bmp_pad(f));
836  }
837  break;
838 
839  case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
840  x = 0;
841  y = 0;
842  while (1) {
843  TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
844  TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
845  if (b>0) {
846  /* repeat count */
847  col[0] = COLTABLE((c>>4) & 0xf);
848  col[1] = COLTABLE(c & 0xf);
849  for (i=0; i<b && x<bmpinfo.w; i++) {
850  if (x>=bmpinfo.w) {
851  x=0;
852  y++;
853  }
854  if (x>=bmpinfo.w || y>=bmpinfo.h) {
855  break;
856  }
857  realheight = y+1;
858  GM_PUT(gm, x, y, col[i&1]);
859  x++;
860  }
861  } else if (c == 0) {
862  /* end of line */
863  y++;
864  x = 0;
865  } else if (c == 1) {
866  /* end of greymap */
867  break;
868  } else if (c == 2) {
869  /* "delta": skip pixels in x and y directions */
870  TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
871  TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
872  x += b;
873  y += c;
874  } else {
875  /* verbatim segment */
876  for (i=0; i<c; i++) {
877  if ((i&1)==0) {
878  TRY_EOF(bmp_readint(f, 1, &b));
879  }
880  if (x>=bmpinfo.w) {
881  x=0;
882  y++;
883  }
884  if (x>=bmpinfo.w || y>=bmpinfo.h) {
885  break;
886  }
887  realheight = y+1;
888  GM_PUT(gm, x, y, COLTABLE((b>>(4-4*(i&1))) & 0xf));
889  x++;
890  }
891  if ((c+1) & 2) {
892  /* pad to 16-bit boundary */
893  TRY_EOF(bmp_readint(f, 1, &b));
894  }
895  }
896  }
897  break;
898 
899  case 0x108: /* 8-bit runlength compressed encoding (RLE8) */
900  x = 0;
901  y = 0;
902  while (1) {
903  TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
904  TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
905  if (b>0) {
906  /* repeat count */
907  for (i=0; i<b; i++) {
908  if (x>=bmpinfo.w) {
909  x=0;
910  y++;
911  }
912  if (x>=bmpinfo.w || y>=bmpinfo.h) {
913  break;
914  }
915  realheight = y+1;
916  GM_PUT(gm, x, y, COLTABLE(c));
917  x++;
918  }
919  } else if (c == 0) {
920  /* end of line */
921  y++;
922  x = 0;
923  } else if (c == 1) {
924  /* end of greymap */
925  break;
926  } else if (c == 2) {
927  /* "delta": skip pixels in x and y directions */
928  TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
929  TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
930  x += b;
931  y += c;
932  } else {
933  /* verbatim segment */
934  for (i=0; i<c; i++) {
935  TRY_EOF(bmp_readint(f, 1, &b));
936  if (x>=bmpinfo.w) {
937  x=0;
938  y++;
939  }
940  if (x>=bmpinfo.w || y>=bmpinfo.h) {
941  break;
942  }
943  realheight = y+1;
944  GM_PUT(gm, x, y, COLTABLE(b));
945  x++;
946  }
947  if (c & 1) {
948  /* pad input to 16-bit boundary */
949  TRY_EOF(bmp_readint(f, 1, &b));
950  }
951  }
952  }
953  break;
954 
955  } /* switch */
956 
957  /* skip any potential junk after the data section, but don't
958  complain in case EOF is encountered */
959  bmp_forward(f, bmpinfo.FileSize);
960 
961  free(coltable);
962  if (bmpinfo.topdown) {
963  gm_flip(gm);
964  }
965  *gmp = gm;
966  return 0;
967 
968  eof:
969  TRY_STD(gm_resize(gm, realheight));
970  free(coltable);
971  if (bmpinfo.topdown) {
972  gm_flip(gm);
973  }
974  *gmp = gm;
975  return 1;
976 
977  format_error:
978  try_error:
979  free(coltable);
980  gm_free(gm);
981  if (!gm_read_error) {
982  gm_read_error = "invalid bmp file";
983  }
984  return -2;
985 
986  std_error:
987  free(coltable);
988  gm_free(gm);
989  return -1;
990 }
991 
992 /* ---------------------------------------------------------------------- */
993 
994 /* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
995  one-line comment if non-NULL. Mode determines how out-of-range
996  color values are converted. Gamma is the desired gamma correction,
997  if any (set to 2.2 if the image is to look optimal on a CRT monitor,
998  2.8 for LCD). Set to 1.0 for no gamma correction */
999 
1000 int gm_writepgm(FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma) {
1001  int x, y, v;
1002  int gammatable[256];
1003 
1004  /* prepare gamma correction lookup table */
1005  if (gamma != 1.0) {
1006  gammatable[0] = 0;
1007  for (v=1; v<256; v++) {
1008  gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
1009  }
1010  } else {
1011  for (v=0; v<256; v++) {
1012  gammatable[v] = v;
1013  }
1014  }
1015 
1016  fprintf(f, raw ? "P5\n" : "P2\n");
1017  if (comment && *comment) {
1018  fprintf(f, "# %s\n", comment);
1019  }
1020  fprintf(f, "%d %d 255\n", gm->w, gm->h);
1021  for (y=gm->h-1; y>=0; y--) {
1022  for (x=0; x<gm->w; x++) {
1023  v = GM_UGET(gm, x, y);
1024  if (mode == GM_MODE_NONZERO) {
1025  if (v > 255) {
1026  v = 510 - v;
1027  }
1028  if (v < 0) {
1029  v = 0;
1030  }
1031  } else if (mode == GM_MODE_ODD) {
1032  v = mod(v, 510);
1033  if (v > 255) {
1034  v = 510 - v;
1035  }
1036  } else if (mode == GM_MODE_POSITIVE) {
1037  if (v < 0) {
1038  v = 0;
1039  } else if (v > 255) {
1040  v = 255;
1041  }
1042  } else if (mode == GM_MODE_NEGATIVE) {
1043  v = 510 - v;
1044  if (v < 0) {
1045  v = 0;
1046  } else if (v > 255) {
1047  v = 255;
1048  }
1049  }
1050  v = gammatable[v];
1051 
1052  if (raw) {
1053  fputc(v, f);
1054  } else {
1055  fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
1056  }
1057  }
1058  }
1059  return 0;
1060 }
1061 
1062 /* ---------------------------------------------------------------------- */
1063 /* output - for primitive debugging purposes only! */
1064 
1065 /* print greymap to screen */
1067  int x, y;
1068  int xx, yy;
1069  int d, t;
1070  int sw, sh;
1071 
1072  sw = gm->w < 79 ? gm->w : 79;
1073  sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
1074 
1075  for (yy=sh-1; yy>=0; yy--) {
1076  for (xx=0; xx<sw; xx++) {
1077  d=0;
1078  t=0;
1079  for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
1080  for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
1081  d += GM_GET(gm, x, y);
1082  t += 256;
1083  }
1084  }
1085  fputc("*#=- "[5*d/t], f); /* what a cute trick :) */
1086  }
1087  fputc('\n', f);
1088  }
1089  return 0;
1090 }
double __cdecl exp(double _X)
double __cdecl log(double _X)
int ptrdiff_t
Definition: CPAL.d:3845
#define mode
Definition: aptex-macros.h:510
static unsigned int lobit(unsigned int x)
Definition: bitops.h:55
#define n
Definition: t4ht.c:1290
#define b
Definition: jpegint.h:372
#define free(a)
Definition: decNumber.cpp:310
int w
Definition: dviconv.c:26
int v
Definition: dviconv.c:10
int h
Definition: dviconv.c:9
#define fgetc
Definition: xxstdio.h:26
static int xx[600]
Definition: psspecial.c:35
static int yy[600]
Definition: psspecial.c:35
#define error(a)
Definition: dviinfo.c:48
mpz_t * f
Definition: gen-fib.c:34
#define t
Definition: afcover.h:96
#define c(n)
Definition: gpos-common.c:150
#define d(n)
Definition: gpos-common.c:151
static ptrdiff_t getsize(int dy, int h)
Definition: greymap.c:42
int gm_read(FILE *f, greymap_t **gmp)
Definition: greymap.c:294
static int bmp_readint(FILE *f, int n, unsigned int *p)
Definition: greymap.c:565
greymap_t * gm_new(int w, int h)
Definition: greymap.c:71
#define COLTABLE(c)
Definition: greymap.c:621
#define TRY_EOF(x)
Definition: greymap.c:33
static int gm_readbody_bmp(FILE *f, greymap_t **gmp)
Definition: greymap.c:630
void gm_clear(greymap_t *gm, int b)
Definition: greymap.c:124
static int readbit(FILE *f)
Definition: greymap.c:265
greymap_t * gm_dup(greymap_t *gm)
Definition: greymap.c:110
int gm_writepgm(FILE *f, greymap_t *gm, const char *comment, int raw, int mode, double gamma)
Definition: greymap.c:1000
static ptrdiff_t gm_size(const greymap_t *gm)
Definition: greymap.c:63
static int bmp_count
Definition: greymap.c:560
const char * gm_read_error
Definition: greymap.c:292
static int bmp_pad(FILE *f)
Definition: greymap.c:590
static void gm_flip(greymap_t *gm)
Definition: greymap.c:141
#define TRY(x)
Definition: greymap.c:32
static int gm_resize(greymap_t *gm, int h)
Definition: greymap.c:158
static int fgetc_ws(FILE *f)
Definition: greymap.c:202
static int bmp_forward(FILE *f, int pos)
Definition: greymap.c:606
static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic)
Definition: greymap.c:321
static void bmp_pad_reset(void)
Definition: greymap.c:584
#define mod(a, n)
Definition: greymap.c:27
static int readnum(FILE *f)
Definition: greymap.c:227
void gm_free(greymap_t *gm)
Definition: greymap.c:102
#define TRY_STD(x)
Definition: greymap.c:34
int gm_print(FILE *f, greymap_t *gm)
Definition: greymap.c:1066
#define INTBITS
Definition: greymap.c:25
static int bmp_pos
Definition: greymap.c:561
signed short int gm_sample_t
Definition: greymap.h:14
#define GM_MODE_POSITIVE
Definition: greymap.h:54
#define GM_UPUT(gm, x, y, b)
Definition: greymap.h:41
#define GM_MODE_NEGATIVE
Definition: greymap.h:55
#define GM_MODE_NONZERO
Definition: greymap.h:52
#define GM_PUT(gm, x, y, b)
Definition: greymap.h:45
#define gm_scanline(gm, y)
Definition: greymap.h:34
#define GM_UGET(gm, x, y)
Definition: greymap.h:38
#define GM_GET(gm, x, y)
Definition: greymap.h:42
#define GM_MODE_ODD
Definition: greymap.h:53
#define GM_SAMPLESIZE
Definition: greymap.h:16
#define memcpy(d, s, n)
Definition: gsftopk.c:64
int col
Definition: gsftopk.c:443
char comment[255+1]
Definition: hbf2gf.c:350
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
small capitals from c petite p scientific i
Definition: afcover.h:80
#define EOF
Definition: afmparse.c:59
kerning y
Definition: ttdriver.c:212
#define gamma
Definition: gd_nnquant.c:53
unsigned __int64 uint64_t
Definition: stdint.h:90
voidp calloc()
int errno
static int gammatable[]
Definition: set.c:185
int acc
Definition: exvar.h:3
#define fprintf
Definition: mendex.h:64
#define b1
Definition: texmfmem.h:169
#define malloc
Definition: alloca.c:91
boolean eof(FILE *file)
Definition: eofeoln.c:11
const int * pos
Definition: combiners.h:905
#define realloc
Definition: glob.c:206
float x
Definition: cordic.py:15
#define max(a, b)
Definition: pbmto4425.c:11
static int size
Definition: ppmlabel.c:24
bstring c int memset(void *s, int c, int length)
unsigned int FileSize
Definition: bitmap_io.c:365
unsigned int h
Definition: bitmap_io.c:370
unsigned int GreenMask
Definition: bitmap_io.c:380
unsigned int InfoSize
Definition: bitmap_io.c:368
unsigned int ctbits
Definition: bitmap_io.c:383
unsigned int DataOffset
Definition: bitmap_io.c:367
unsigned int bits
Definition: bitmap_io.c:372
unsigned int comp
Definition: bitmap_io.c:373
unsigned int XpixelsPerM
Definition: bitmap_io.c:375
unsigned int YpixelsPerM
Definition: bitmap_io.c:376
unsigned int ImageSize
Definition: bitmap_io.c:374
unsigned int RedMask
Definition: bitmap_io.c:379
unsigned int ncolors
Definition: bitmap_io.c:377
unsigned int BlueMask
Definition: bitmap_io.c:381
unsigned int w
Definition: bitmap_io.c:369
unsigned int Planes
Definition: bitmap_io.c:371
unsigned int reserved
Definition: bitmap_io.c:366
unsigned int AlphaMask
Definition: bitmap_io.c:382
unsigned int ColorsImportant
Definition: bitmap_io.c:378
int topdown
Definition: bitmap_io.c:384
Definition: bmp.h:66
signed char topdown
Definition: bmp.h:79
Definition: dvi.c:140
int dy
Definition: greymap.h:24
Definition: dvips.h:235
#define FILE
Definition: t1stdio.h:34
#define ungetc(c, f)
Definition: t1stdio.h:106
int j
Definition: t4ht.c:1589
return() int(((double) *(font_tbl[cur_fnt].wtbl+(int)(*(font_tbl[cur_fnt].char_wi+(int)(ch - font_tbl[cur_fnt].char_f)% 256)))/(double)(1L<< 20)) *(double) font_tbl[cur_fnt].scale)