Statistics
| Revision:

gvsig-raster / libjni-potrace / trunk / libjni-potrace / src / main / native / jpotrace / greymap.c @ 1780

History | View | Annotate | Download (19.4 KB)

1
/* Copyright (C) 2001-2007 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
/* $Id: greymap.c 147 2007-04-09 00:44:09Z selinger $ */
6

    
7
/* Routines for manipulating greymaps, including reading pgm files. We
8
   only deal with greymaps of depth 8 bits. */
9

    
10
#include <stdlib.h>
11
#include <errno.h>
12
#include <string.h>
13
#include <math.h>
14

    
15
#include "greymap.h"
16

    
17
#define INTBITS (8*sizeof(int))
18

    
19
#define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
20

    
21
static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
22
static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
23

    
24
/* ---------------------------------------------------------------------- */
25
/* basic greymap routines */
26

    
27
/* return new un-initialized greymap. NULL with errno on error */
28

    
29
greymap_t *gm_new(int w, int h) {
30
  greymap_t *gm;
31
  int errno_save;
32

    
33
  gm = (greymap_t *) malloc(sizeof(greymap_t));
34
  if (!gm) {
35
    return NULL;
36
  }
37
  gm->w = w;
38
  gm->h = h;
39
  gm->map = (signed short int *) malloc(w*h*sizeof(signed short int));
40
  if (!gm->map) {
41
    errno_save = errno;
42
    free(gm);
43
    errno = errno_save;
44
    return NULL;
45
  }
46
  return gm;
47
}
48

    
49
/* free the given greymap */
50
void gm_free(greymap_t *gm) {
51
  if (gm) {
52
    free(gm->map);
53
  }
54
  free(gm);
55
}
56

    
57
/* duplicate the given greymap. Return NULL on error with errno set. */
58
greymap_t *gm_dup(greymap_t *gm) {
59
  greymap_t *gm1 = gm_new(gm->w, gm->h);
60
  if (!gm1) {
61
    return NULL;
62
  }
63
  memcpy(gm1->map, gm->map, gm->w*gm->h*2);
64
  return gm1;
65
}
66

    
67
/* clear the given greymap to color b. */
68
void gm_clear(greymap_t *gm, int b) {
69
  int i;
70

    
71
  if (b==0) {
72
    memset(gm->map, 0, gm->w*gm->h*2);
73
  } else {
74
    for (i=0; i<gm->w*gm->h; i++) {
75
      gm->map[i] = b;
76
    }
77
  }    
78
}
79

    
80
/* ---------------------------------------------------------------------- */
81
/* routines for reading pnm streams */
82

    
83
/* read next character after whitespace and comments. Return EOF on
84
   end of file or error. */
85
static int fgetc_ws(FILE *f) {
86
  int c;
87

    
88
  while (1) {
89
    c = fgetc(f);
90
    if (c=='#') {
91
      while (1) {
92
        c = fgetc(f);
93
        if (c=='\n' || c==EOF) {
94
          break;
95
        }
96
      }
97
    }
98
    /* space, tab, line feed, carriage return, form-feed */
99
    if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
100
      return c;
101
    }
102
  }
103
}
104

    
105
/* skip whitespace and comments, then read a non-negative decimal
106
   number from a stream. Return -1 on EOF. Tolerate other errors (skip
107
   bad characters). Do not the read any characters following the
108
   number (put next character back into the stream) */
109

    
110
static int readnum(FILE *f) {
111
  int c;
112
  int acc;
113

    
114
  /* skip whitespace and comments */
115
  while (1) {
116
    c = fgetc_ws(f);
117
    if (c==EOF) {
118
      return -1;
119
    }
120
    if (c>='0' && c<='9') {
121
      break;
122
    }
123
  }
124

    
125
  /* first digit is already in c */
126
  acc = c-'0';
127
  while (1) {
128
    c = fgetc(f);
129
    if (c==EOF) {
130
      break;
131
    }
132
    if (c<'0' || c>'9') {
133
      ungetc(c, f);
134
      break;
135
    }
136
    acc *= 10;
137
    acc += c-'0';
138
  }
139
  return acc;
140
}
141

    
142
/* similar to readnum, but read only a single 0 or 1, and do not read
143
   any characters after it. */
144

    
145
static int readbit(FILE *f) {
146
  int c;
147

    
148
  /* skip whitespace and comments */
149
  while (1) {
150
    c = fgetc_ws(f);
151
    if (c==EOF) {
152
      return -1;
153
    }
154
    if (c>='0' && c<='1') {
155
      break;
156
    }
157
  }
158

    
159
  return c-'0';
160
}
161

    
162
/* ---------------------------------------------------------------------- */
163

    
164
/* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
165
   convert the output to a greymap. Return greymap in *gmp. Return 0
166
   on success, -1 on error with errno set, -2 on bad file format (with
167
   error message in gm_read_error), and 1 on premature end of file, -3
168
   on empty file (including files with only whitespace and comments),
169
   -4 if wrong magic number. If the return value is >=0, *gmp is
170
   valid. */
171

    
172
char *gm_read_error = NULL;
173

    
174
int gm_read(FILE *f, greymap_t **gmp) {
175
  int magic[2];
176

    
177
  /* read magic number. We ignore whitespace and comments before the
178
     magic, for the benefit of concatenated files in P1-P3 format.
179
     Multiple P1-P3 images in a single file are not formally allowed
180
     by the PNM standard, but there is no harm in being lenient. */
181

    
182
  magic[0] = fgetc_ws(f);
183
  if (magic[0] == EOF) {
184
    /* files which contain only comments and whitespace count as "empty" */
185
    return -3;
186
  } 
187
  magic[1] = fgetc(f);
188
  if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
189
    return gm_readbody_pnm(f, gmp, magic[1]);
190
  }
191
  if (magic[0] == 'B' && magic[1] == 'M') {
192
    return gm_readbody_bmp(f, gmp);
193
  }
194
  return -4;
195
}
196

    
197
/* ---------------------------------------------------------------------- */
198
/* read PNM format */
199

    
200
/* read PNM stream after magic number. Return values as for gm_read */
201
static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
202
  greymap_t *gm;
203
  int x, y, i, j, b, b1, sum;
204
  int bpr; /* bytes per row (as opposed to 4*gm->c) */
205
  int w, h, max;
206

    
207
  gm = NULL;
208

    
209
  w = readnum(f);
210
  if (w<0) {
211
    goto format_error;
212
  }
213

    
214
  h = readnum(f);
215
  if (h<0) {
216
    goto format_error;
217
  }
218

    
219
  /* allocate greymap */
220
  gm = gm_new(w, h);
221
  if (!gm) {
222
    return -1;
223
  }
224

    
225
  /* zero it out */
226
  gm_clear(gm, 0);
227

    
228
  switch (magic) {
229
  default: 
230
    /* not reached */
231
    goto format_error;  
232

    
233
  case '1':
234
    /* read P1 format: PBM ascii */
235
    
236
    for (y=h-1; y>=0; y--) {
237
      for (x=0; x<w; x++) {
238
        b = readbit(f);
239
        if (b<0) {
240
          goto eof;
241
        }
242
        GM_UPUT(gm, x, y, b ? 0 : 255);
243
      }
244
    }
245
    break;
246

    
247
  case '2':
248
    /* read P2 format: PGM ascii */
249
    
250
    max = readnum(f);
251
    if (max<1) {
252
      goto format_error;
253
    }
254
    
255
    for (y=h-1; y>=0; y--) {
256
      for (x=0; x<w; x++) {
257
        b = readnum(f);
258
        if (b<0) {
259
          goto eof;
260
        }
261
        GM_UPUT(gm, x, y, b*255/max);
262
      }
263
    }
264
    break;
265

    
266
  case '3':
267
    /* read P3 format: PPM ascii */
268
    
269
    max = readnum(f);
270
    if (max<1) {
271
      goto format_error;
272
    }
273
    
274
    for (y=h-1; y>=0; y--) {
275
      for (x=0; x<w; x++) {
276
        sum = 0;
277
        for (i=0; i<3; i++) {
278
          b = readnum(f);
279
          if (b<0) {
280
            goto eof;
281
          }
282
          sum += b;
283
        }
284
        GM_UPUT(gm, x, y, sum*(255/3)/max);
285
      }
286
    }
287
    break;
288

    
289
  case '4':
290
    /* read P4 format: PBM raw */
291

    
292
    b = fgetc(f);  /* read single white-space character after height */
293
    if (b==EOF) {
294
      goto format_error;
295
    }
296

    
297
    bpr = (w+7)/8;
298

    
299
    for (y=h-1; y>=0; y--) {
300
      for (i=0; i<bpr; i++) {
301
        b = fgetc(f);
302
        if (b==EOF) {
303
          goto eof;
304
        }
305
        for (j=0; j<8; j++) {
306
          GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
307
        }
308
      }
309
    }
310
    break;
311

    
312
  case '5':
313
    /* read P5 format: PGM raw */
314

    
315
    max = readnum(f);
316
    if (max<1) {
317
      goto format_error;
318
    }
319

    
320
    b = fgetc(f);  /* read single white-space character after max */
321
    if (b==EOF) {
322
      goto format_error;
323
    }
324

    
325
    for (y=h-1; y>=0; y--) {
326
      for (x=0; x<w; x++) {
327
        b = fgetc(f);
328
        if (b==EOF)
329
          goto eof;
330
        if (max>=256) {
331
          b <<= 8;
332
          b1 = fgetc(f);
333
          if (b1==EOF)
334
            goto eof;
335
          b |= b1;
336
        }
337
        GM_UPUT(gm, x, y, b*255/max);
338
      }
339
    }
340
    break;
341

    
342
  case '6':
343
    /* read P6 format: PPM raw */
344

    
345
    max = readnum(f);
346
    if (max<1) {
347
      goto format_error;
348
    }
349

    
350
    b = fgetc(f);  /* read single white-space character after max */
351
    if (b==EOF) {
352
      goto format_error;
353
    }
354

    
355
    for (y=h-1; y>=0; y--) {
356
      for (x=0; x<w; x++) {
357
        sum = 0;
358
        for (i=0; i<3; i++) {
359
          b = fgetc(f);
360
          if (b==EOF) {
361
            goto eof;
362
          }
363
          if (max>=256) {
364
            b <<= 8;
365
            b1 = fgetc(f);
366
            if (b1==EOF)
367
              goto eof;
368
            b |= b1;
369
          }
370
          sum += b;
371
        }
372
        GM_UPUT(gm, x, y, sum*(255/3)/max);
373
      }
374
    }
375
    break;
376
  }
377

    
378
  *gmp = gm;
379
  return 0;
380

    
381
 eof:
382
  *gmp = gm;
383
  return 1;
384

    
385
 format_error:
386
  gm_free(gm);
387
  if (magic == '1' || magic == '4') {
388
    gm_read_error = "invalid pbm file";
389
  } else if (magic == '2' || magic == '5') {
390
    gm_read_error = "invalid pgm file";
391
  } else {
392
    gm_read_error = "invalid ppm file";
393
  }
394
  return -2;
395
}
396

    
397
/* ---------------------------------------------------------------------- */
398
/* read BMP format */
399

    
400
struct bmp_info_s {
401
  unsigned int FileSize;
402
  unsigned int reserved;
403
  unsigned int DataOffset;
404
  unsigned int InfoSize;
405
  unsigned int w;              /* width */
406
  unsigned int h;              /* height */
407
  unsigned int Planes;
408
  unsigned int bits;           /* bits per sample */
409
  unsigned int comp;           /* compression mode */
410
  unsigned int ImageSize;
411
  unsigned int XpixelsPerM;
412
  unsigned int YpixelsPerM;
413
  unsigned int ncolors;        /* number of colors in palette */
414
  unsigned int ColorsImportant;
415
  unsigned int ctbits;         /* sample size for color table */
416
};
417
typedef struct bmp_info_s bmp_info_t;
418

    
419
/* auxiliary */
420

    
421
static int bmp_count = 0; /* counter for byte padding */
422
static int bmp_pos = 0;   /* counter from start of BMP data */
423

    
424
/* read n-byte little-endian integer. Return 1 on EOF or error, else
425
   0. Assume n<=4. */
426
static int bmp_readint(FILE *f, int n, unsigned int *p) {
427
  int i;
428
  unsigned int sum = 0;
429
  int b;
430

    
431
  for (i=0; i<n; i++) {
432
    b = fgetc(f);
433
    if (b==EOF) {
434
      return 1;
435
    }
436
    sum += b << (8*i);
437
  }
438
  bmp_count += n;
439
  bmp_pos += n;
440
  *p = sum;
441
  return 0;
442
}
443

    
444
/* reset padding boundary */
445
static void bmp_pad_reset(void) {
446
  bmp_count = 0;
447
}
448

    
449
/* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
450
   else 0. */
451
static int bmp_pad(FILE *f) {
452
  int c, i, b;
453

    
454
  c = (-bmp_count) & 3;
455
  for (i=0; i<c; i++) {
456
    b = fgetc(f);
457
    if (b==EOF) {
458
      return 1;
459
    }
460
  }
461
  bmp_pos += c;
462
  bmp_count = 0;
463
  return 0;
464
}
465
  
466
/* forward to the new file position. Return 1 on EOF or error, else 0 */
467
static int bmp_forward(FILE *f, int pos) {
468
  int b;
469

    
470
  while (bmp_pos < pos) {
471
    b = fgetc(f);
472
    if (b==EOF) {
473
      return 1;
474
    }
475
    bmp_pos++;
476
    bmp_count++;
477
  }
478
  return 0;
479
}
480

    
481
#define TRY(x) if (x) goto try_error
482
#define TRY_EOF(x) if (x) goto eof
483

    
484
/* read BMP stream after magic number. Return values as for gm_read.
485
   We choose to be as permissive as possible, since there are many
486
   programs out there which produce BMP. For instance, ppmtobmp can
487
   produce codings with anywhere from 1-8 or 24 bits per sample,
488
   although most specifications only allow 1,4,8,24,32. We can also
489
   read both the old and new OS/2 BMP formats in addition to the
490
   Windows BMP format. */
491
static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
492
  bmp_info_t bmpinfo;
493
  int *coltable;
494
  unsigned int b, c;
495
  unsigned int i, j;
496
  greymap_t *gm;
497
  unsigned int x, y;
498
  int col[2];
499
  unsigned int bitbuf;
500
  unsigned int n;
501

    
502
  gm_read_error = NULL;
503
  gm = NULL;
504
  coltable = NULL;
505

    
506
  bmp_pos = 2;  /* set file position */
507

    
508
  /* file header (minus magic number) */
509
  TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
510
  TRY(bmp_readint(f, 4, &bmpinfo.reserved));
511
  TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
512

    
513
  /* info header */
514
  TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
515
  if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64) {
516
    /* Windows or new OS/2 format */
517
    bmpinfo.ctbits = 32; /* sample size in color table */
518
    TRY(bmp_readint(f, 4, &bmpinfo.w));
519
    TRY(bmp_readint(f, 4, &bmpinfo.h));
520
    TRY(bmp_readint(f, 2, &bmpinfo.Planes));
521
    TRY(bmp_readint(f, 2, &bmpinfo.bits));
522
    TRY(bmp_readint(f, 4, &bmpinfo.comp));
523
    TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
524
    TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
525
    TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
526
    TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
527
    TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
528
  } else if (bmpinfo.InfoSize == 12) {
529
    /* old OS/2 format */
530
    bmpinfo.ctbits = 24; /* sample size in color table */
531
    TRY(bmp_readint(f, 2, &bmpinfo.w));
532
    TRY(bmp_readint(f, 2, &bmpinfo.h));
533
    TRY(bmp_readint(f, 2, &bmpinfo.Planes));
534
    TRY(bmp_readint(f, 2, &bmpinfo.bits));
535
    bmpinfo.comp = 0;
536
    bmpinfo.ncolors = 0;
537
  } else {
538
    goto format_error;
539
  }
540

    
541
  /* forward to color table (i.e., if bmpinfo.InfoSize == 64) */
542
  TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
543

    
544
  if (bmpinfo.Planes != 1) {
545
    gm_read_error = "cannot handle bmp planes";
546
    goto format_error;  /* can't handle planes */
547
  }
548
  
549
  if (bmpinfo.ncolors == 0) {
550
    bmpinfo.ncolors = 1 << bmpinfo.bits;
551
  }
552

    
553
  /* color table, present only if bmpinfo.bits <= 8. */
554
  if (bmpinfo.bits <= 8) {
555
    coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int));
556
    if (!coltable) {
557
      goto std_error;
558
    }
559
    /* NOTE: since we are reading a greymap, we can immediately convert
560
       the color table entries to grey values. */
561
    for (i=0; i<bmpinfo.ncolors; i++) {
562
      TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
563
      c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
564
      coltable[i] = c/3;
565
    }
566
  }
567

    
568
  /* forward to data */
569
  if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
570
    TRY(bmp_forward(f, bmpinfo.DataOffset));
571
  }
572

    
573
  /* allocate greymap */
574
  gm = gm_new(bmpinfo.w, bmpinfo.h);
575
  if (!gm) {
576
    goto std_error;
577
  }
578
  
579
  /* zero it out */
580
  gm_clear(gm, 0);
581

    
582
  switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
583
    
584
  default:
585
    goto format_error;
586
    break;
587
    
588
  case 0x001:  /* monochrome palette */
589

    
590
    /* raster data */
591
    for (y=0; y<bmpinfo.h; y++) {
592
      bmp_pad_reset();
593
      for (i=0; 8*i<bmpinfo.w; i++) {
594
        TRY_EOF(bmp_readint(f, 1, &b));
595
        for (j=0; j<8; j++) {
596
          GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? coltable[1] : coltable[0]);
597
        }
598
      }
599
      TRY(bmp_pad(f));
600
    }
601
    break;
602
   
603
  case 0x002:  /* 2-bit to 8-bit palettes */
604
  case 0x003: 
605
  case 0x004: 
606
  case 0x005: 
607
  case 0x006: 
608
  case 0x007: 
609
  case 0x008:
610
    for (y=0; y<bmpinfo.h; y++) {
611
      bmp_pad_reset();
612
      bitbuf = 0;  /* bit buffer: bits in buffer are high-aligned */
613
      n = 0;       /* number of bits currently in bitbuffer */
614
      for (x=0; x<bmpinfo.w; x++) {
615
        if (n < bmpinfo.bits) {
616
          TRY_EOF(bmp_readint(f, 1, &b));
617
          bitbuf |= b << (INTBITS - 8 - n);
618
          n += 8;
619
        }
620
        b = bitbuf >> (INTBITS - bmpinfo.bits);
621
        bitbuf <<= bmpinfo.bits;
622
        n -= bmpinfo.bits;
623
        GM_UPUT(gm, x, y, coltable[b]);
624
      }
625
      TRY(bmp_pad(f));
626
    }
627
    break;
628

    
629
  case 0x010:  /* 16-bit encoding */
630
    /* can't do this format because it is not well-documented and I
631
       don't have any samples */
632
    gm_read_error = "cannot handle bmp 16-bit coding";
633
    goto format_error;
634
    break;
635

    
636
  case 0x018:  /* 24-bit encoding */
637
  case 0x020:  /* 32-bit encoding */
638
    for (y=0; y<bmpinfo.h; y++) {
639
      bmp_pad_reset();
640
      for (x=0; x<bmpinfo.w; x++) {
641
        TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
642
        c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
643
        GM_UPUT(gm, x, y, c/3);
644
      }
645
      TRY(bmp_pad(f));
646
    }
647
    break;
648

    
649
  case 0x204:  /* 4-bit runlength compressed encoding (RLE4) */
650
    x = 0;
651
    y = 0;
652
    while (1) {
653
      TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
654
      TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
655
      if (b>0) {
656
        /* repeat count */
657
        col[0] = coltable[(c>>4) & 0xf];
658
        col[1] = coltable[c & 0xf];
659
        for (i=0; i<b && x<bmpinfo.w; i++) {
660
          if (x>=bmpinfo.w) {
661
            x=0;
662
            y++;
663
          }
664
          if (y>=bmpinfo.h) {
665
            break;
666
          }
667
          GM_UPUT(gm, x, y, col[i&1]);
668
          x++;
669
        }
670
      } else if (c == 0) {
671
        /* end of line */
672
        y++;
673
        x = 0;
674
      } else if (c == 1) {
675
        /* end of greymap */
676
        break;
677
      } else if (c == 2) {
678
        /* "delta": skip pixels in x and y directions */
679
        TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
680
        TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
681
        x += b;
682
        y += c;
683
      } else {
684
        /* verbatim segment */
685
        for (i=0; i<c; i++) {
686
          if ((i&1)==0) {
687
            TRY_EOF(bmp_readint(f, 1, &b));
688
          }
689
          if (x>=bmpinfo.w) {
690
            x=0;
691
            y++;
692
          }
693
          if (y>=bmpinfo.h) {
694
            break;
695
          }
696
          GM_PUT(gm, x, y, coltable[(b>>(4-4*(i&1))) & 0xf]);
697
          x++;
698
        }
699
        if ((c+1) & 2) {
700
          /* pad to 16-bit boundary */
701
          TRY_EOF(bmp_readint(f, 1, &b));
702
        }
703
      }
704
    }
705
    break;
706

    
707
  case 0x108:  /* 8-bit runlength compressed encoding (RLE8) */
708
    x = 0;
709
    y = 0;
710
    while (1) {
711
      TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
712
      TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
713
      if (b>0) {
714
        /* repeat count */
715
        for (i=0; i<b; i++) {
716
          if (x>=bmpinfo.w) {
717
            x=0;
718
            y++;
719
          }
720
          if (y>=bmpinfo.h) {
721
            break;
722
          }
723
          GM_UPUT(gm, x, y, coltable[c]);
724
          x++;
725
        }
726
      } else if (c == 0) {
727
        /* end of line */
728
        y++;
729
        x = 0;
730
      } else if (c == 1) {
731
        /* end of greymap */
732
        break;
733
      } else if (c == 2) {
734
        /* "delta": skip pixels in x and y directions */
735
        TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
736
        TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
737
        x += b;
738
        y += c;
739
      } else {
740
        /* verbatim segment */
741
        for (i=0; i<c; i++) {
742
          TRY_EOF(bmp_readint(f, 1, &b));
743
          if (x>=bmpinfo.w) {
744
            x=0;
745
            y++;
746
          }
747
          if (y>=bmpinfo.h) {
748
            break;
749
          }
750
          GM_PUT(gm, x, y, coltable[b]);
751
          x++;
752
        }
753
        if (c & 1) {
754
          /* pad input to 16-bit boundary */
755
          TRY_EOF(bmp_readint(f, 1, &b));
756
        }
757
      }
758
    }
759
    break;
760

    
761
  } /* switch */
762

    
763
  /* skip any potential junk after the data section, but don't
764
     complain in case EOF is encountered */
765
  bmp_forward(f, bmpinfo.FileSize);
766

    
767
  free(coltable);
768
  *gmp = gm;
769
  return 0;
770

    
771
 eof:
772
  free(coltable);
773
  *gmp = gm;
774
  return 1;
775

    
776
 format_error:
777
 try_error:
778
  free(coltable);
779
  free(gm);
780
  if (!gm_read_error) {
781
    gm_read_error = "invalid bmp file";
782
  }
783
  return -2;
784

    
785
 std_error:
786
  free(coltable);
787
  free(gm);
788
  return -1;
789
}
790

    
791
/* ---------------------------------------------------------------------- */
792

    
793
/* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
794
   one-line comment if non-NULL. Mode determines how out-of-range
795
   color values are converted. Gamma is the desired gamma correction,
796
   if any (set to 2.2 if the image is to look optimal on a CRT monitor,
797
   2.8 for LCD). Set to 1.0 for no gamma correction */
798

    
799
int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) {
800
  int x, y, v;
801
  int gammatable[256];
802
  
803
  /* prepare gamma correction lookup table */
804
  if (gamma != 1.0) {
805
    gammatable[0] = 0;
806
    for (v=1; v<256; v++) {
807
      gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
808
    }
809
  } else {
810
    for (v=0; v<256; v++) {
811
      gammatable[v] = v;
812
    }
813
  }  
814

    
815
  fprintf(f, raw ? "P5\n" : "P2\n");
816
  if (comment && *comment) {
817
    fprintf(f, "# %s\n", comment);
818
  }
819
  fprintf(f, "%d %d 255\n", gm->w, gm->h);
820
  for (y=gm->h-1; y>=0; y--) {
821
    for (x=0; x<gm->w; x++) {
822
      v = GM_UGET(gm, x, y);
823
      if (mode == GM_MODE_NONZERO) {
824
        if (v > 255) {
825
          v = 510 - v;
826
        }
827
        if (v < 0) {
828
          v = 0;
829
        }
830
      } else if (mode == GM_MODE_ODD) {
831
        v = mod(v, 510);
832
        if (v > 255) {
833
          v = 510 - v;
834
        }
835
      } else if (mode == GM_MODE_POSITIVE) {
836
        if (v < 0) {
837
          v = 0;
838
        } else if (v > 255) {
839
          v = 255;
840
        }
841
      } else if (mode == GM_MODE_NEGATIVE) {
842
        v = 510 - v;
843
        if (v < 0) {
844
          v = 0;
845
        } else if (v > 255) {
846
          v = 255;
847
        }
848
      }
849
      v = gammatable[v];
850
      
851
      if (raw) {
852
        fputc(v, f);
853
      } else {
854
        fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
855
      }          
856
    }
857
  }
858
  return 0;
859
}
860

    
861
/* ---------------------------------------------------------------------- */
862
/* output - for primitive debugging purposes only! */
863

    
864
/* print greymap to screen */
865
int gm_print(FILE *f, greymap_t *gm) {
866
  int x, y;
867
  int xx, yy;
868
  int d, t;
869
  int sw, sh;
870

    
871
  sw = gm->w < 79 ? gm->w : 79;
872
  sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
873

    
874
  for (yy=sh-1; yy>=0; yy--) {
875
    for (xx=0; xx<sw; xx++) {
876
      d=0;
877
      t=0;
878
      for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
879
        for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
880
          d += GM_GET(gm, x, y);
881
          t += 256;
882
        }
883
      }
884
      fputc("*#=- "[5*d/t], f);  /* what a cute trick :) */
885
    }
886
    fputc('\n', f);
887
  }
888
  return 0;
889
}