gvsig-raster / libjni-potrace / trunk / libjni-potrace / resources / potrace-1.8 / src / bitmap_io.c @ 1780
History | View | Annotate | Download (16.9 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: bitmap_io.c 147 2007-04-09 00:44:09Z selinger $ */
|
6 |
|
7 |
/* Routines for manipulating bitmaps, including reading pbm files. */
|
8 |
|
9 |
#include <stdio.h> |
10 |
|
11 |
#include "bitmap.h" |
12 |
|
13 |
#define INTBITS (8*sizeof(int)) |
14 |
|
15 |
static int bm_readbody_bmp(FILE *f, double threshold, potrace_bitmap_t **bmp); |
16 |
static int bm_readbody_pnm(FILE *f, double threshold, potrace_bitmap_t **bmp, int magic); |
17 |
|
18 |
/* ---------------------------------------------------------------------- */
|
19 |
/* routines for reading pnm streams */
|
20 |
|
21 |
/* read next character after whitespace and comments. Return EOF on
|
22 |
end of file or error. */
|
23 |
static int fgetc_ws(FILE *f) { |
24 |
int c;
|
25 |
|
26 |
while (1) { |
27 |
c = fgetc(f); |
28 |
if (c == '#') { |
29 |
while (1) { |
30 |
c = fgetc(f); |
31 |
if (c == '\n' || c == EOF) { |
32 |
break;
|
33 |
} |
34 |
} |
35 |
} |
36 |
/* space, tab, line feed, carriage return, form-feed */
|
37 |
if (c != ' ' && c != '\t' && c != '\r' && c != '\n' && c != 12) { |
38 |
return c;
|
39 |
} |
40 |
} |
41 |
} |
42 |
|
43 |
/* skip whitespace and comments, then read a non-negative decimal
|
44 |
number from a stream. Return -1 on EOF. Tolerate other errors (skip
|
45 |
bad characters). Do not the read any characters following the
|
46 |
number (put next character back into the stream) */
|
47 |
|
48 |
static int readnum(FILE *f) { |
49 |
int c;
|
50 |
int acc;
|
51 |
|
52 |
/* skip whitespace and comments */
|
53 |
while (1) { |
54 |
c = fgetc_ws(f); |
55 |
if (c == EOF) { |
56 |
return -1; |
57 |
} |
58 |
if (c >= '0' && c <= '9') { |
59 |
break;
|
60 |
} |
61 |
} |
62 |
|
63 |
/* first digit is already in c */
|
64 |
acc = c - '0';
|
65 |
while (1) { |
66 |
c = fgetc(f); |
67 |
if (c == EOF) { |
68 |
break;
|
69 |
} |
70 |
if (c < '0' || c > '9') { |
71 |
ungetc(c, f); |
72 |
break;
|
73 |
} |
74 |
acc *= 10;
|
75 |
acc += c - '0';
|
76 |
} |
77 |
return acc;
|
78 |
} |
79 |
|
80 |
/* similar to readnum, but read only a single 0 or 1, and do not read
|
81 |
any characters after it. */
|
82 |
|
83 |
static int readbit(FILE *f) { |
84 |
int c;
|
85 |
|
86 |
/* skip whitespace and comments */
|
87 |
while (1) { |
88 |
c = fgetc_ws(f); |
89 |
if (c == EOF) { |
90 |
return -1; |
91 |
} |
92 |
if (c >= '0' && c <= '1') { |
93 |
break;
|
94 |
} |
95 |
} |
96 |
|
97 |
return c - '0'; |
98 |
} |
99 |
|
100 |
/* ---------------------------------------------------------------------- */
|
101 |
|
102 |
/* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
|
103 |
convert the output to a bitmap. Return bitmap in *bmp. Return 0 on
|
104 |
success, -1 on error with errno set, -2 on bad file format (with
|
105 |
error message in bm_read_error), and 1 on premature end of file, -3
|
106 |
on empty file (including files which contain only whitespace and
|
107 |
comments), -4 if wrong magic number. If the return value is >=0,
|
108 |
*bmp is valid. */
|
109 |
|
110 |
char *bm_read_error = NULL; |
111 |
|
112 |
int bm_read(FILE *f, double threshold, potrace_bitmap_t **bmp) { |
113 |
int magic[2]; |
114 |
|
115 |
/* read magic number. We ignore whitespace and comments before the
|
116 |
magic, for the benefit of concatenated files in P1-P3 format.
|
117 |
Multiple P1-P3 images in a single file are not formally allowed
|
118 |
by the PNM standard, but there is no harm in being lenient. */
|
119 |
|
120 |
magic[0] = fgetc_ws(f);
|
121 |
if (magic[0] == EOF) { |
122 |
return -3; |
123 |
} |
124 |
magic[1] = fgetc(f);
|
125 |
if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') { |
126 |
return bm_readbody_pnm(f, threshold, bmp, magic[1]); |
127 |
} |
128 |
if (magic[0] == 'B' && magic[1] == 'M') { |
129 |
return bm_readbody_bmp(f, threshold, bmp);
|
130 |
} |
131 |
return -4; |
132 |
} |
133 |
|
134 |
/* ---------------------------------------------------------------------- */
|
135 |
/* read PNM format */
|
136 |
|
137 |
/* read PNM stream after magic number. Return values as for bm_read */
|
138 |
static int bm_readbody_pnm(FILE *f, double threshold, potrace_bitmap_t **bmp, int magic) { |
139 |
potrace_bitmap_t *bm; |
140 |
int x, y, i, b, b1, sum;
|
141 |
int bpr; /* bytes per row (as opposed to 4*bm->c) */ |
142 |
int w, h, max;
|
143 |
|
144 |
bm = NULL;
|
145 |
|
146 |
w = readnum(f); |
147 |
if (w < 0) { |
148 |
goto format_error;
|
149 |
} |
150 |
|
151 |
h = readnum(f); |
152 |
if (h < 0) { |
153 |
goto format_error;
|
154 |
} |
155 |
|
156 |
/* allocate bitmap */
|
157 |
bm = bm_new(w, h); |
158 |
if (!bm) {
|
159 |
return -1; |
160 |
} |
161 |
|
162 |
/* zero it out */
|
163 |
bm_clear(bm, 0);
|
164 |
|
165 |
switch (magic) {
|
166 |
default:
|
167 |
/* not reached */
|
168 |
goto format_error;
|
169 |
|
170 |
case '1': |
171 |
/* read P1 format: PBM ascii */
|
172 |
|
173 |
for (y = h - 1; y >= 0; y--) { |
174 |
for (x = 0; x < w; x++) { |
175 |
b = readbit(f); |
176 |
if (b < 0) { |
177 |
goto eof;
|
178 |
} |
179 |
BM_UPUT(bm, x, y, b); |
180 |
} |
181 |
} |
182 |
break;
|
183 |
|
184 |
case '2': |
185 |
/* read P2 format: PGM ascii */
|
186 |
|
187 |
max = readnum(f); |
188 |
if (max < 1) { |
189 |
goto format_error;
|
190 |
} |
191 |
|
192 |
for (y = h - 1; y >= 0; y--) { |
193 |
for (x = 0; x < w; x++) { |
194 |
b = readnum(f); |
195 |
if (b < 0) { |
196 |
goto eof;
|
197 |
} |
198 |
BM_UPUT(bm, x, y, b > threshold * max ? 0 : 1); |
199 |
} |
200 |
} |
201 |
break;
|
202 |
|
203 |
case '3': |
204 |
/* read P3 format: PPM ascii */
|
205 |
|
206 |
max = readnum(f); |
207 |
if (max < 1) { |
208 |
goto format_error;
|
209 |
} |
210 |
|
211 |
for (y = h - 1; y >= 0; y--) { |
212 |
for (x = 0; x < w; x++) { |
213 |
sum = 0;
|
214 |
for (i = 0; i < 3; i++) { |
215 |
b = readnum(f); |
216 |
if (b < 0) { |
217 |
goto eof;
|
218 |
} |
219 |
sum += b; |
220 |
} |
221 |
BM_UPUT(bm, x, y, sum > 3 * threshold * max ? 0 : 1); |
222 |
} |
223 |
} |
224 |
break;
|
225 |
|
226 |
case '4': |
227 |
/* read P4 format: PBM raw */
|
228 |
|
229 |
b = fgetc(f); /* read single white-space character after height */
|
230 |
if (b == EOF) { |
231 |
goto format_error;
|
232 |
} |
233 |
|
234 |
bpr = (w + 7) / 8; |
235 |
|
236 |
for (y = h - 1; y >= 0; y--) { |
237 |
for (i = 0; i < bpr; i++) { |
238 |
b = fgetc(f); |
239 |
if (b == EOF) { |
240 |
goto eof;
|
241 |
} |
242 |
*bm_index(bm, i * 8, y) |= ((potrace_word) b) << (8 * (BM_WORDSIZE - 1 - (i % BM_WORDSIZE))); |
243 |
} |
244 |
} |
245 |
break;
|
246 |
|
247 |
case '5': |
248 |
/* read P5 format: PGM raw */
|
249 |
|
250 |
max = readnum(f); |
251 |
if (max < 1) { |
252 |
goto format_error;
|
253 |
} |
254 |
|
255 |
b = fgetc(f); /* read single white-space character after max */
|
256 |
if (b == EOF) { |
257 |
goto format_error;
|
258 |
} |
259 |
|
260 |
for (y = h - 1; y >= 0; y--) { |
261 |
for (x = 0; x < w; x++) { |
262 |
b = fgetc(f); |
263 |
if (b == EOF) |
264 |
goto eof;
|
265 |
if (max >= 256) { |
266 |
b <<= 8;
|
267 |
b1 = fgetc(f); |
268 |
if (b1 == EOF) |
269 |
goto eof;
|
270 |
b |= b1; |
271 |
} |
272 |
BM_UPUT(bm, x, y, b > threshold * max ? 0 : 1); |
273 |
} |
274 |
} |
275 |
break;
|
276 |
|
277 |
case '6': |
278 |
/* read P6 format: PPM raw */
|
279 |
|
280 |
max = readnum(f); |
281 |
if (max < 1) { |
282 |
goto format_error;
|
283 |
} |
284 |
|
285 |
b = fgetc(f); /* read single white-space character after max */
|
286 |
if (b == EOF) { |
287 |
goto format_error;
|
288 |
} |
289 |
|
290 |
for (y = h - 1; y >= 0; y--) { |
291 |
for (x = 0; x < w; x++) { |
292 |
sum = 0;
|
293 |
for (i = 0; i < 3; i++) { |
294 |
b = fgetc(f); |
295 |
if (b == EOF) { |
296 |
goto eof;
|
297 |
} |
298 |
if (max >= 256) { |
299 |
b <<= 8;
|
300 |
b1 = fgetc(f); |
301 |
if (b1 == EOF) |
302 |
goto eof;
|
303 |
b |= b1; |
304 |
} |
305 |
sum += b; |
306 |
} |
307 |
BM_UPUT(bm, x, y, sum > 3 * threshold * max ? 0 : 1); |
308 |
} |
309 |
} |
310 |
break;
|
311 |
} |
312 |
|
313 |
*bmp = bm; |
314 |
return 0; |
315 |
|
316 |
eof: *bmp = bm;
|
317 |
return 1; |
318 |
|
319 |
format_error: bm_free(bm);
|
320 |
if (magic == '1' || magic == '4') { |
321 |
bm_read_error = "invalid pbm file";
|
322 |
} else
|
323 |
if (magic == '2' || magic == '5') { |
324 |
bm_read_error = "invalid pgm file";
|
325 |
} else {
|
326 |
bm_read_error = "invalid ppm file";
|
327 |
} |
328 |
return -2; |
329 |
} |
330 |
|
331 |
/* ---------------------------------------------------------------------- */
|
332 |
/* read BMP format */
|
333 |
|
334 |
struct bmp_info_s {
|
335 |
unsigned int FileSize; |
336 |
unsigned int reserved; |
337 |
unsigned int DataOffset; |
338 |
unsigned int InfoSize; |
339 |
unsigned int w; /* width */ |
340 |
unsigned int h; /* height */ |
341 |
unsigned int Planes; |
342 |
unsigned int bits; /* bits per sample */ |
343 |
unsigned int comp; /* compression mode */ |
344 |
unsigned int ImageSize; |
345 |
unsigned int XpixelsPerM; |
346 |
unsigned int YpixelsPerM; |
347 |
unsigned int ncolors; /* number of colors in palette */ |
348 |
unsigned int ColorsImportant; |
349 |
unsigned int ctbits; /* sample size for color table */ |
350 |
}; |
351 |
typedef struct bmp_info_s bmp_info_t; |
352 |
|
353 |
/* auxiliary */
|
354 |
|
355 |
static int bmp_count = 0; /* counter for byte padding */ |
356 |
static int bmp_pos = 0; /* counter from start of BMP data */ |
357 |
|
358 |
/* read n-byte little-endian integer. Return 1 on EOF or error, else
|
359 |
0. Assume n<=4. */
|
360 |
static int bmp_readint(FILE *f, int n, unsigned int *p) { |
361 |
int i;
|
362 |
unsigned int sum = 0; |
363 |
int b;
|
364 |
|
365 |
for (i = 0; i < n; i++) { |
366 |
b = fgetc(f); |
367 |
if (b == EOF) { |
368 |
return 1; |
369 |
} |
370 |
sum += b << (8 * i);
|
371 |
} |
372 |
bmp_count += n; |
373 |
bmp_pos += n; |
374 |
*p = sum; |
375 |
return 0; |
376 |
} |
377 |
|
378 |
/* reset padding boundary */
|
379 |
static void bmp_pad_reset(void) { |
380 |
bmp_count = 0;
|
381 |
} |
382 |
|
383 |
/* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
|
384 |
else 0. */
|
385 |
static int bmp_pad(FILE *f) { |
386 |
int c, i, b;
|
387 |
|
388 |
c = (-bmp_count) & 3;
|
389 |
for (i = 0; i < c; i++) { |
390 |
b = fgetc(f); |
391 |
if (b == EOF) { |
392 |
return 1; |
393 |
} |
394 |
} |
395 |
bmp_pos += c; |
396 |
bmp_count = 0;
|
397 |
return 0; |
398 |
} |
399 |
|
400 |
/* forward to the new file position. Return 1 on EOF or error, else 0 */
|
401 |
static int bmp_forward(FILE *f, int pos) { |
402 |
int b;
|
403 |
|
404 |
while (bmp_pos < pos) {
|
405 |
b = fgetc(f); |
406 |
if (b == EOF) { |
407 |
return 1; |
408 |
} |
409 |
bmp_pos++; |
410 |
bmp_count++; |
411 |
} |
412 |
return 0; |
413 |
} |
414 |
|
415 |
#define TRY(x) if (x) goto try_error |
416 |
#define TRY_EOF(x) if (x) goto eof |
417 |
|
418 |
/* read BMP stream after magic number. Return values as for bm_read.
|
419 |
We choose to be as permissive as possible, since there are many
|
420 |
programs out there which produce BMP. For instance, ppmtobmp can
|
421 |
produce codings with anywhere from 1-8 or 24 bits per sample,
|
422 |
although most specifications only allow 1,4,8,24,32. We can also
|
423 |
read both the old and new OS/2 BMP formats in addition to the
|
424 |
Windows BMP format. */
|
425 |
static int bm_readbody_bmp(FILE *f, double threshold, potrace_bitmap_t **bmp) { |
426 |
bmp_info_t bmpinfo; |
427 |
int *coltable;
|
428 |
unsigned int b, c; |
429 |
unsigned int i; |
430 |
potrace_bitmap_t *bm; |
431 |
int mask;
|
432 |
unsigned int x, y; |
433 |
int col[2]; |
434 |
unsigned int bitbuf; |
435 |
unsigned int n; |
436 |
int col1[2]; |
437 |
|
438 |
bm_read_error = NULL;
|
439 |
bm = NULL;
|
440 |
coltable = NULL;
|
441 |
|
442 |
bmp_pos = 2; /* set file position */ |
443 |
|
444 |
/* file header (minus magic number) */
|
445 |
TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
|
446 |
TRY(bmp_readint(f, 4, &bmpinfo.reserved));
|
447 |
TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
|
448 |
|
449 |
/* info header */
|
450 |
TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
|
451 |
if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64) { |
452 |
/* Windows or new OS/2 format */
|
453 |
bmpinfo.ctbits = 32; /* sample size in color table */ |
454 |
TRY(bmp_readint(f, 4, &bmpinfo.w));
|
455 |
TRY(bmp_readint(f, 4, &bmpinfo.h));
|
456 |
TRY(bmp_readint(f, 2, &bmpinfo.Planes));
|
457 |
TRY(bmp_readint(f, 2, &bmpinfo.bits));
|
458 |
TRY(bmp_readint(f, 4, &bmpinfo.comp));
|
459 |
TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
|
460 |
TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
|
461 |
TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
|
462 |
TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
|
463 |
TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
|
464 |
} else if (bmpinfo.InfoSize == 12) { |
465 |
/* old OS/2 format */
|
466 |
bmpinfo.ctbits = 24; /* sample size in color table */ |
467 |
TRY(bmp_readint(f, 2, &bmpinfo.w));
|
468 |
TRY(bmp_readint(f, 2, &bmpinfo.h));
|
469 |
TRY(bmp_readint(f, 2, &bmpinfo.Planes));
|
470 |
TRY(bmp_readint(f, 2, &bmpinfo.bits));
|
471 |
bmpinfo.comp = 0;
|
472 |
bmpinfo.ncolors = 0;
|
473 |
} else {
|
474 |
goto format_error;
|
475 |
} |
476 |
|
477 |
/* forward to color table (i.e., if bmpinfo.InfoSize == 64) */
|
478 |
TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
|
479 |
|
480 |
if (bmpinfo.Planes != 1) { |
481 |
bm_read_error = "cannot handle bmp planes";
|
482 |
goto format_error; /* can't handle planes */ |
483 |
} |
484 |
|
485 |
if (bmpinfo.ncolors == 0) { |
486 |
bmpinfo.ncolors = 1 << bmpinfo.bits;
|
487 |
} |
488 |
|
489 |
/* color table, present only if bmpinfo.bits <= 8. */
|
490 |
if (bmpinfo.bits <= 8) { |
491 |
coltable = (int *) malloc(bmpinfo.ncolors * sizeof(int)); |
492 |
if (!coltable) {
|
493 |
goto std_error;
|
494 |
} |
495 |
/* NOTE: since we are reading a bitmap, we can immediately convert
|
496 |
the color table entries to bits. */
|
497 |
for (i=0; i<bmpinfo.ncolors; i++) { |
498 |
TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
|
499 |
c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff); |
500 |
coltable[i] = (c> 3 * threshold * 255 ? 0 : 1); |
501 |
if (i<2) { |
502 |
col1[i] = c; |
503 |
} |
504 |
} |
505 |
} |
506 |
|
507 |
/* forward to data */
|
508 |
if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */ |
509 |
TRY(bmp_forward(f, bmpinfo.DataOffset)); |
510 |
} |
511 |
|
512 |
/* allocate bitmap */
|
513 |
bm = bm_new(bmpinfo.w, bmpinfo.h); |
514 |
if (!bm) {
|
515 |
goto std_error;
|
516 |
} |
517 |
|
518 |
/* zero it out */
|
519 |
bm_clear(bm, 0);
|
520 |
|
521 |
switch (bmpinfo.bits + 0x100*bmpinfo.comp) { |
522 |
|
523 |
default:
|
524 |
goto format_error;
|
525 |
break;
|
526 |
|
527 |
case 0x001: /* monochrome palette */ |
528 |
if (col1[0] < col1[1]) { /* make the darker color black */ |
529 |
mask = 0xff;
|
530 |
} else {
|
531 |
mask = 0;
|
532 |
} |
533 |
|
534 |
/* raster data */
|
535 |
for (y=0; y<bmpinfo.h; y++) { |
536 |
bmp_pad_reset(); |
537 |
for (i=0; 8*i<bmpinfo.w; i++) { |
538 |
TRY_EOF(bmp_readint(f, 1, &b));
|
539 |
b ^= mask; |
540 |
*bm_index(bm, i*8, y) |= ((potrace_word)b) << (8*(BM_WORDSIZE-1-(i % BM_WORDSIZE))); |
541 |
} |
542 |
TRY(bmp_pad(f)); |
543 |
} |
544 |
break;
|
545 |
|
546 |
case 0x002: /* 2-bit to 8-bit palettes */ |
547 |
case 0x003: |
548 |
case 0x004: |
549 |
case 0x005: |
550 |
case 0x006: |
551 |
case 0x007: |
552 |
case 0x008: |
553 |
for (y=0; y<bmpinfo.h; y++) { |
554 |
bmp_pad_reset(); |
555 |
bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */ |
556 |
n = 0; /* number of bits currently in bitbuffer */ |
557 |
for (x=0; x<bmpinfo.w; x++) { |
558 |
if (n < bmpinfo.bits) {
|
559 |
TRY_EOF(bmp_readint(f, 1, &b));
|
560 |
bitbuf |= b << (INTBITS - 8 - n);
|
561 |
n += 8;
|
562 |
} |
563 |
b = bitbuf >> (INTBITS - bmpinfo.bits); |
564 |
bitbuf <<= bmpinfo.bits; |
565 |
n -= bmpinfo.bits; |
566 |
BM_UPUT(bm, x, y, coltable[b]); |
567 |
} |
568 |
TRY(bmp_pad(f)); |
569 |
} |
570 |
break;
|
571 |
|
572 |
case 0x010: /* 16-bit encoding */ |
573 |
/* can't do this format because it is not well-documented and I
|
574 |
don't have any samples */
|
575 |
bm_read_error = "cannot handle bmp 16-bit coding";
|
576 |
goto format_error;
|
577 |
break;
|
578 |
|
579 |
case 0x018: /* 24-bit encoding */ |
580 |
case 0x020: /* 32-bit encoding */ |
581 |
for (y=0; y<bmpinfo.h; y++) { |
582 |
bmp_pad_reset(); |
583 |
for (x=0; x<bmpinfo.w; x++) { |
584 |
TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
|
585 |
c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff); |
586 |
BM_UPUT(bm, x, y, c> 3 * threshold * 255 ? 0 : 1); |
587 |
} |
588 |
TRY(bmp_pad(f)); |
589 |
} |
590 |
break;
|
591 |
|
592 |
case 0x204: /* 4-bit runlength compressed encoding (RLE4) */ |
593 |
x = 0;
|
594 |
y = 0;
|
595 |
while (1) { |
596 |
TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */ |
597 |
TRY_EOF(bmp_readint(f, 1, &c)); /* argument */ |
598 |
if (b>0) { |
599 |
/* repeat count */
|
600 |
col[0] = coltable[(c>>4) & 0xf]; |
601 |
col[1] = coltable[c & 0xf]; |
602 |
for (i=0; i<b && x<bmpinfo.w; i++) { |
603 |
if (x>=bmpinfo.w) {
|
604 |
x=0;
|
605 |
y++; |
606 |
} |
607 |
if (y>=bmpinfo.h) {
|
608 |
break;
|
609 |
} |
610 |
BM_UPUT(bm, x, y, col[i&1]);
|
611 |
x++; |
612 |
} |
613 |
} else if (c == 0) { |
614 |
/* end of line */
|
615 |
y++; |
616 |
x = 0;
|
617 |
} else if (c == 1) { |
618 |
/* end of bitmap */
|
619 |
break;
|
620 |
} else if (c == 2) { |
621 |
/* "delta": skip pixels in x and y directions */
|
622 |
TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */ |
623 |
TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */ |
624 |
x += b; |
625 |
y += c; |
626 |
} else {
|
627 |
/* verbatim segment */
|
628 |
for (i=0; i<c; i++) { |
629 |
if ((i&1)==0) { |
630 |
TRY_EOF(bmp_readint(f, 1, &b));
|
631 |
} |
632 |
if (x>=bmpinfo.w) {
|
633 |
x=0;
|
634 |
y++; |
635 |
} |
636 |
if (y>=bmpinfo.h) {
|
637 |
break;
|
638 |
} |
639 |
BM_PUT(bm, x, y, coltable[(b>>(4-4*(i&1))) & 0xf]); |
640 |
x++; |
641 |
} |
642 |
if ((c+1) & 2) { |
643 |
/* pad to 16-bit boundary */
|
644 |
TRY_EOF(bmp_readint(f, 1, &b));
|
645 |
} |
646 |
} |
647 |
} |
648 |
break;
|
649 |
|
650 |
case 0x108: /* 8-bit runlength compressed encoding (RLE8) */ |
651 |
x = 0;
|
652 |
y = 0;
|
653 |
while (1) { |
654 |
TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */ |
655 |
TRY_EOF(bmp_readint(f, 1, &c)); /* argument */ |
656 |
if (b>0) { |
657 |
/* repeat count */
|
658 |
for (i=0; i<b; i++) { |
659 |
if (x>=bmpinfo.w) {
|
660 |
x=0;
|
661 |
y++; |
662 |
} |
663 |
if (y>=bmpinfo.h) {
|
664 |
break;
|
665 |
} |
666 |
BM_UPUT(bm, x, y, coltable[c]); |
667 |
x++; |
668 |
} |
669 |
} else if (c == 0) { |
670 |
/* end of line */
|
671 |
y++; |
672 |
x = 0;
|
673 |
} else if (c == 1) { |
674 |
/* end of bitmap */
|
675 |
break;
|
676 |
} else if (c == 2) { |
677 |
/* "delta": skip pixels in x and y directions */
|
678 |
TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */ |
679 |
TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */ |
680 |
x += b; |
681 |
y += c; |
682 |
} else {
|
683 |
/* verbatim segment */
|
684 |
for (i=0; i<c; i++) { |
685 |
TRY_EOF(bmp_readint(f, 1, &b));
|
686 |
if (x>=bmpinfo.w) {
|
687 |
x=0;
|
688 |
y++; |
689 |
} |
690 |
if (y>=bmpinfo.h) {
|
691 |
break;
|
692 |
} |
693 |
BM_PUT(bm, x, y, coltable[b]); |
694 |
x++; |
695 |
} |
696 |
if (c & 1) { |
697 |
/* pad input to 16-bit boundary */
|
698 |
TRY_EOF(bmp_readint(f, 1, &b));
|
699 |
} |
700 |
} |
701 |
} |
702 |
break;
|
703 |
|
704 |
} /* switch */
|
705 |
|
706 |
/* skip any potential junk after the data section, but don't
|
707 |
complain in case EOF is encountered */
|
708 |
bmp_forward(f, bmpinfo.FileSize); |
709 |
|
710 |
free(coltable); |
711 |
*bmp = bm; |
712 |
return 0; |
713 |
|
714 |
eof:
|
715 |
free(coltable); |
716 |
*bmp = bm; |
717 |
return 1; |
718 |
|
719 |
format_error:
|
720 |
try_error:
|
721 |
free(coltable); |
722 |
free(bm); |
723 |
if (!bm_read_error) {
|
724 |
bm_read_error = "invalid bmp file";
|
725 |
} |
726 |
return -2; |
727 |
|
728 |
std_error:
|
729 |
free(coltable); |
730 |
free(bm); |
731 |
return -1; |
732 |
} |
733 |
|
734 |
/* ---------------------------------------------------------------------- */
|
735 |
/* output pbm format */
|
736 |
|
737 |
void bm_writepbm(FILE *f, potrace_bitmap_t *bm) {
|
738 |
int w, h, bpr, y, i, c;
|
739 |
|
740 |
w = bm->w; |
741 |
h = bm->h; |
742 |
|
743 |
bpr = (w + 7) / 8; |
744 |
|
745 |
fprintf(f, "P4\n%d %d\n", w, h);
|
746 |
for (y = h - 1; y >= 0; y--) { |
747 |
for (i = 0; i < bpr; i++) { |
748 |
c = (*bm_index(bm, i * 8, y) >> (8 * (BM_WORDSIZE - 1 - (i % BM_WORDSIZE)))) & 0xff; |
749 |
fputc(c, f); |
750 |
} |
751 |
} |
752 |
return;
|
753 |
} |
754 |
|
755 |
/* ---------------------------------------------------------------------- */
|
756 |
/* output - for primitive debugging purposes only! */
|
757 |
|
758 |
/* print bitmap to screen */
|
759 |
int bm_print(FILE *f, potrace_bitmap_t *bm) {
|
760 |
int x, y;
|
761 |
int xx, yy;
|
762 |
int d;
|
763 |
int sw, sh;
|
764 |
|
765 |
sw = bm->w < 79 ? bm->w : 79; |
766 |
sh = bm->w < 79 ? bm->h : bm->h * sw * 44 / (79 * bm->w); |
767 |
|
768 |
for (yy = sh - 1; yy >= 0; yy--) { |
769 |
for (xx = 0; xx < sw; xx++) { |
770 |
d = 0;
|
771 |
for (x = xx * bm->w / sw; x < (xx + 1) * bm->w / sw; x++) { |
772 |
for (y = yy * bm->h / sh; y < (yy + 1) * bm->h / sh; y++) { |
773 |
if (BM_GET(bm, x, y)) {
|
774 |
d++; |
775 |
} |
776 |
} |
777 |
} |
778 |
fputc(d ? '*' : ' ', f); |
779 |
} |
780 |
fputc('\n', f);
|
781 |
} |
782 |
return 0; |
783 |
} |
784 |
|