source: trunk/indexers/mg/src/images/bilevel.c@ 3745

Last change on this file since 3745 was 3745, checked in by mdewsnip, 21 years ago

Addition of MG package for search and retrieval

  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1/**************************************************************************
2 *
3 * bilevel.c -- Compress a bilevel bitmap
4 * Copyright (C) 1994 Stuart Inglis
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * $Id: bilevel.c 3745 2003-02-20 21:20:24Z mdewsnip $
21 *
22 **************************************************************************
23 *
24 *
25 *
26 * This is the code used to compress a bitmap. The template is given in
27 * the following format.
28 * '.' = pixel not used
29 * 'p' = pixel used in 1st order context (the superset)
30 * '2' = pixel used in 2nd order context (the subset)
31 * ';' = marker used to denote the end of a row in the template
32 * '*' = the current context pixel.
33 * for instance, the common 22/10 template would be shown as:
34 * ".ppppp.;"
35 * "pp222pp;"
36 * "p22222p;"
37 * "p22*...;"
38 *
39 **************************************************************************/
40
41
42#include "sysfuncs.h"
43
44#include "bilevel.h"
45#include "extractor.h"
46#include "pbmtools.h"
47#include "marklist.h"
48#include "arithcode.h"
49#include "utils.h"
50
51
52
53#define INITVALUE 2
54#define INCREMENT 4
55
56#define MAX_T_W 32
57
58/* note memory usage is 2*TEMPLATESIZE*sizeof(prob), which is currently 4.9 Mb */
59#define TEMPLATESIZE 612317
60
61
62#define HASH(x) ((x)%TEMPLATESIZE)
63
64
65typedef struct
66 {
67 unsigned short s, n;
68 }
69prob; /* set and notset */
70typedef struct
71 {
72 short int x, y;
73 }
74coordinate;
75
76coordinate MM[MAX_T_W][MAX_T_W]; /* the actual (x,y) positions */
77unsigned int MMcount[MAX_T_W]; /* number of bits in this row of the template */
78unsigned int MMmask[MAX_T_W]; /* the "current" mask value */
79unsigned int MMbits[MAX_T_W]; /* the bitmask to mask out higher bits */
80unsigned int MMrows; /* total number of rows */
81unsigned int MM2level[MAX_T_W]; /* bitmask to calculate the 2nd level mask */
82int twolevel, curr_row, surr;
83
84prob *P = NULL; /* probability array, up to N bits */
85prob *P2 = NULL;
86
87void
88bl_clearmodel ()
89{
90 int i;
91
92 P = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
93 if (!P)
94 error_msg ("bl_clearmodel()", "not enough memory.", "");
95
96 P2 = (prob *) malloc (TEMPLATESIZE * sizeof (prob));
97 if (!P2)
98 error_msg ("bl_clearmodel()", "not enough memory.", "");
99
100 for (i = 0; i < TEMPLATESIZE; i++)
101 {
102 P[i].s = P[i].n = INITVALUE;
103 P2[i].s = P2[i].n = INITVALUE;
104 }
105}
106
107
108void
109bl_freemodel ()
110{
111 free (P);
112 free (P2);
113}
114
115
116
117
118#define update_counts(p, pixel) \
119 pixel ? (p->s+=INCREMENT) : (p->n+=INCREMENT); \
120 \
121 if(p->s+p->n >= (unsigned)(maxfrequency)) { \
122 p->s=(p->s+1)/(unsigned)2; \
123 p->n=(p->n+1)/(unsigned)2; \
124 }
125
126
127
128
129/* mask is the bigger one, mask2l is smaller one */
130static void
131bl_encode_in_context (unsigned long mask, unsigned long mask2l, unsigned long pixel)
132{
133 register int twol, t;
134 prob *p = &P[mask];
135 prob *p2 = &P2[mask2l];
136
137 twol = twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT));
138
139 t = twol ? (p2->s + p2->n) : (p->s + p->n);
140
141 if (twol == 0)
142 {
143 if (pixel)
144 arithmetic_encode (0, p->s, t);
145 else
146 arithmetic_encode (p->s, t, t);
147 update_counts (p, pixel);
148 }
149 else
150 {
151 if (pixel)
152 arithmetic_encode (0, p2->s, t);
153 else
154 arithmetic_encode (p2->s, t, t);
155 update_counts (p2, pixel);
156 update_counts (p, pixel);
157 }
158}
159
160
161static void
162bl_decode_in_context (unsigned long mask, unsigned long mask2l, unsigned long *val)
163{
164 register int twol, pixel, t;
165 prob *p = &P[mask];
166 prob *p2 = &P2[mask2l];
167
168
169 if (twolevel && (p->s + p->n < (unsigned) (2 * INITVALUE + 5 * INCREMENT)))
170 {
171 pixel = arithmetic_decode_target (p2->s + p2->n) < p2->s, twol = 1;
172 }
173 else
174 {
175 pixel = arithmetic_decode_target (p->s + p->n) < p->s, twol = 0;
176 }
177
178 t = twol ? (p2->s + p2->n) : (p->s + p->n);
179
180 if (twol == 0)
181 {
182 if (pixel)
183 arithmetic_decode (0, p->s, t);
184 else
185 arithmetic_decode (p->s, t, t);
186 update_counts (p, pixel);
187 }
188 else
189 {
190 if (pixel)
191 arithmetic_decode (0, p2->s, t);
192 else
193 arithmetic_decode (p2->s, t, t);
194 update_counts (p2, pixel);
195 update_counts (p, pixel);
196 }
197
198 *val = pixel;
199}
200
201static void
202bl_string_to_array (char inputstr[], char parsestr[], int *w, int *h)
203{
204 int r, c;
205 int i, j, lastc, p, l;
206 int xc, yc;
207 int foundstatus;
208
209 surr = twolevel = 0;
210 for (i = 0; i < MAX_T_W; i++)
211 MMcount[i] = MM2level[i] = 0;
212 MMrows = 0;
213
214 for (i = 0; i < (int) strlen (inputstr); i++)
215 {
216 p = inputstr[i];
217 if ((p != '.') && (p != '2') && (p != '*') && (p != 'p') && (p != ';'))
218 {
219 fprintf (stderr, "Template string can only contain [.p2*;], not \"%c\".\n", inputstr[i]);
220 exit (1);
221 }
222 }
223
224 /* get the width and height, test rectangularity... */
225 parsestr[l = 0] = 0;
226 for (c = 0, r = 0, lastc = -1, p = 0; p < (int) strlen (inputstr); p++)
227 {
228 if ((inputstr[p] == ';'))
229 {
230 r++;
231 if (lastc != -1)
232 { /* this is the 2nd row at least */
233 if (lastc != c)
234 {
235 fprintf (stderr, "The rows have to be the same width. "
236 "Row %d has width %d (previous row has width %d)\n", r, c, lastc);
237 exit (1);
238 }
239 }
240 lastc = c;
241 c = 0;
242 }
243 else
244 {
245 c++;
246 parsestr[l] = inputstr[p];
247 parsestr[++l] = 0;
248 }
249 }
250
251 if (c != 0)
252 lastc = c;
253 *w = lastc;
254 *h = r;
255 if ((*w) <= 0)
256 {
257 fprintf (stderr, "Must have at least one column!\n");
258 exit (1);
259 }
260 if ((*h) <= 0)
261 {
262 fprintf (stderr, "Must have at least one row! Terminate each row with a ';'\n");
263 exit (1);
264 }
265 if ((*w > MAX_T_W) || (*h > MAX_T_W))
266 {
267 fprintf (stderr, "template size bigger than internal threshold of %d\n", MAX_T_W);
268 exit (1);
269 }
270
271 /* get the (x,y) position of the current (*) pixel */
272 for (xc = -1, yc = 0, i = 0; i < *w; i++)
273 for (j = 0; j < *h; j++)
274 if (parsestr[j * (*w) + i] == '*')
275 {
276 if (xc >= 0)
277 {
278 fprintf (stderr, "There can only be ONE current ('*') pixel.\n");
279 exit (1);
280 }
281 xc = i;
282 yc = j;
283 curr_row = j + 1;
284 }
285 if (xc < 0)
286 error_msg ("bl_string_to_array", "Error in mask, no current ('*') pixel.", "");
287 /* found the position (xc,yc) */
288
289
290 /* convert parsestr[] into a MM[][] structure */
291 for (j = 0; j < *h; j++)
292 {
293 foundstatus = 0;
294 for (i = 0; i < *w; i++)
295 {
296 p = j * (*w) + i;
297 if ((parsestr[p] == 'p') || (parsestr[p] == '2'))
298 {
299 if (!foundstatus)
300 foundstatus = 1;
301 MM2level[j] = MM2level[j] * 2 | (parsestr[p] == '2');
302 if (parsestr[p] == '2')
303 twolevel = 1;
304
305 MM[j][MMcount[j]].x = i - xc;
306 MM[j][MMcount[j]++].y = j - yc;
307 if (((i - xc) >= 0) && ((j - yc) >= 0))
308 surr = 1;
309 }
310 else
311 {
312 if (foundstatus == 1)
313 foundstatus = 2;
314 }
315
316 }
317 if (foundstatus)
318 MMrows++;
319 MMbits[j] = (1 << MMcount[j]) - 1;
320 }
321
322 /* reverse matrix, so [][0] is the closest to the right */
323 {
324 coordinate temp;
325 for (i = 0; i < MMrows; i++)
326 for (j = 0; j < MMcount[i] / (unsigned) 2; j++)
327 {
328 temp = MM[i][MMcount[i] - 1 - j];
329 MM[i][MMcount[i] - 1 - j] = MM[i][j];
330 MM[i][j] = temp;
331 }
332 }
333}
334
335
336
337
338
339
340
341
342void
343bl_writetemplate (char inputstr[])
344{
345 register int i, j;
346 int w, h;
347 char ind[255];
348 char *str;
349
350 str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
351
352 bl_string_to_array (inputstr, str, &w, &h);
353
354 EncodeGammaDist (surr);
355 EncodeGammaDist (w);
356 EncodeGammaDist (h);
357 ind['.'] = 0;
358 ind['p'] = 1;
359 ind['2'] = 2;
360 ind['*'] = 3;
361 for (j = 0; j < h; j++)
362 for (i = 0; i < w; i++)
363 EncodeGammaDist (ind[(int) str[j * w + i]]);
364
365 free (str);
366}
367
368
369void
370bl_readtemplate ()
371{
372 register int i, j;
373 int w, h, p;
374 char ind[4];
375 char *inputstr, *str;
376
377 surr = DecodeGammaDist (surr);
378 if (surr)
379 {
380 fprintf (stderr, "It's fine compressing an image using a 'surrounding' template, but I can't "
381 "decompress it!\n");
382 exit (1);
383 }
384 w = DecodeGammaDist ();
385 h = DecodeGammaDist ();
386
387 inputstr = (char *) malloc ((w + 2) * h * sizeof (char) + 2);
388 ind[0] = '.';
389 ind[1] = 'p';
390 ind[2] = '2';
391 ind[3] = '*';
392 for (p = 0, j = 0; j < h; j++)
393 {
394 for (i = 0; i < w; i++)
395 {
396 inputstr[p++] = ind[DecodeGammaDist ()];
397 }
398 inputstr[p++] = ';';
399 inputstr[p] = 0;
400 }
401
402 str = (char *) malloc (strlen (inputstr) * sizeof (char) + 2);
403 bl_string_to_array (inputstr, str, &w, &h);
404}
405
406
407
408
409
410/* Currently if there are more than 32 bits, the topmost 32 will be discarded, if the
411 topbits are to be used in compression, define _MORETHAN32 */
412#undef _MORETHAN32
413
414void
415bl_compress_mark (marktype d)
416{
417 register int r, c;
418 register int i, j;
419 register unsigned long mask, mask2level;
420 char *array[MAX_T_W];
421
422
423 for (i = 0; i < MAX_T_W; i++)
424 {
425 array[i] = (char *) calloc ((size_t) d.w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
426 array[i] = array[i] + MAX_T_W;
427 }
428
429 EncodeGammaDist (d.w);
430 EncodeGammaDist (d.h);
431
432 for (r = 0; r < min (curr_row, d.h); r++)
433 for (c = 0; c < d.w; c++)
434 array[r % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r);
435
436 for (r = 0; r < d.h; r++)
437 {
438 if (V)
439 if (r && (r % 200 == 0))
440 fprintf (stderr, ".");
441
442 if (r + curr_row < d.h)
443 for (c = 0; c < d.w; c++)
444 array[(r + curr_row) % MAX_T_W][c] = pbm_getpixel (d.bitmap, c, r + curr_row);
445 else
446 for (c = 0; c < d.w; c++)
447 array[(r + curr_row) % MAX_T_W][c] = 0;
448
449 for (c = 0; c < d.w; c++)
450 {
451 for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
452 {
453 if (c != 0)
454 {
455 MMmask[i] = (MMmask[i] * 2);
456 MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
457 }
458 else
459 {
460 for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--)
461 MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
462 }
463 MMmask[i] &= MMbits[i];
464#ifdef _MORETHAN32
465 mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
466 mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
467#else
468 mask = (mask << MMcount[i]) | MMmask[i];
469 mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
470#endif
471 }
472
473 mask = HASH (mask);
474 mask2level = HASH (mask2level);
475
476 bl_encode_in_context (mask, mask2level, pbm_getpixel (d.bitmap, c, r));
477 }
478 }
479 for (i = 0; i < MAX_T_W; i++)
480 free (array[i] - MAX_T_W);
481}
482
483
484
485void
486bl_decompress_mark (marktype * d)
487{
488 register int r, c;
489 register int i, j;
490 unsigned long pix;
491 register unsigned long mask, mask2level;
492 char *array[MAX_T_W];
493
494
495 d->w = DecodeGammaDist ();
496 d->h = DecodeGammaDist ();
497
498 d->bitmap = pbm_allocarray (d->w, d->h);
499 for (i = 0; i < MAX_T_W; i++)
500 {
501 array[i] = (char *) calloc ((size_t) d->w + 2 * MAX_T_W + 1, (size_t) sizeof (char));
502 array[i] = array[i] + MAX_T_W;
503 }
504
505 for (r = 0; r < d->h; r++)
506 {
507 if (V)
508 if (r && (r % 200 == 0))
509 fprintf (stderr, ".");
510 for (c = 0; c < d->w; c++)
511 array[r % MAX_T_W][c] = pbm_getpixel (d->bitmap, c, r);
512 for (c = 0; c < d->w; c++)
513 {
514 for (mask = 0, mask2level = 0, i = 0; i < MMrows; i++)
515 {
516 if (c != 0)
517 {
518 MMmask[i] = (MMmask[i] * 2);
519 MMmask[i] |= array[(r + MM[i][0].y + MAX_T_W) % MAX_T_W][c + MM[i][0].x];
520 }
521 else
522 {
523 for (MMmask[i] = 0, j = MMcount[i] - 1; j >= 0; j--) /* get all pixels */
524 MMmask[i] = 2 * MMmask[i] | array[(r + MM[i][j].y + MAX_T_W) % MAX_T_W][c + MM[i][j].x];
525 }
526 MMmask[i] &= MMbits[i];
527
528#ifdef _MORETHAN32
529 mask = ((mask * 8191) << MMcount[i]) | MMmask[i];
530 mask2level = ((mask2level * 499) << MMcount[i]) | (MMmask[i] & MM2level[i]);
531#else
532 mask = (mask << MMcount[i]) | MMmask[i];
533 mask2level = (mask2level << MMcount[i]) | (MMmask[i] & MM2level[i]);
534#endif
535 }
536
537 mask = HASH (mask);
538 mask2level = HASH (mask2level);
539
540 bl_decode_in_context (mask, mask2level, &pix);
541 if (pix)
542 {
543 pbm_putpixel (d->bitmap, c, r, pix);
544 array[r % MAX_T_W][c] = pix;
545 }
546 }
547 }
548 for (i = 0; i < MAX_T_W; i++)
549 free (array[i] - MAX_T_W);
550}
551
552
553
554void
555bl_compress (marktype d, char inputstr[])
556{
557 bl_clearmodel ();
558 bl_writetemplate (inputstr);
559 bl_compress_mark (d);
560 bl_freemodel ();
561}
562
563
564void
565bl_decompress (marktype * d)
566{
567 bl_clearmodel ();
568 bl_readtemplate ();
569 bl_decompress_mark (d);
570 bl_freemodel ();
571}
572
573
574
575
576
577
578/*
579 The bitmap in d2, can be examined clairvoyantly. The ordering of the
580 params is therefore non-clairvoyant, and clairvoyant in that order.
581
582 */
583/*
584 coordinate M1[6]={ { 0,-2},
585 {-1,-1},{ 0,-1}, {1,-1},
586 {-2,0}, {-1, 0}};
587 };
588 coordinate M2[13]={ { 0,-2},
589 {-1,-1}, { 0,-1}, {1, -1},
590 {-2,0}, {-1, 0}, { 0, 0}, { 1, 0}, {2,0},
591 {-1, 1}, { 0, 1}, { 1, 1},
592 { 0, 2}
593 */
594
595coordinate M1[6] =
596{
597 {0, -2},
598 {-2, 0},
599 {1, -1},
600 {-1, -1},
601 {0, -1},
602 {-1, 0}};
603coordinate M2[13] =
604{
605 {0, -2},
606 {1, -1},
607 {-2, 0},
608 {2, 0},
609 {-1, 1},
610 {1, 1},
611 {0, 2},
612 {-1, -1},
613 {0, -1},
614 {1, 0},
615 {-1, 0},
616 {0, 1},
617 {0, 0}
618};
619#define M1S 6
620#define M1S_2level 3
621#define M2S 13
622#define M2S_2level 6
623
624
625void
626bl_clair_compress (marktype d1, marktype d2)
627{
628 register int r, c;
629 register int i, j, n;
630 register unsigned long mask, mask2level = 0;
631 int cols, rows;
632 int gap;
633 Pixel **b1, **b2;
634
635
636 bl_clearmodel ();
637 twolevel = 1;
638
639 b1 = d1.bitmap;
640 b2 = d2.bitmap;
641 cols = d1.w;
642 rows = d1.h;
643
644 gap = max (50, rows / 10);
645
646 EncodeGammaDist (cols);
647 EncodeGammaDist (rows);
648
649 for (r = 0; r < rows; r++)
650 {
651 if (V)
652 if (!(r % gap))
653 fprintf (stderr, ".");
654 for (c = 0; c < cols; c++)
655 {
656
657 mask = 0;
658 for (n = 0; n < M1S; n++)
659 {
660 i = c + M1[n].x;
661 j = r + M1[n].y;
662 mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
663 }
664
665 mask2level = mask & ((1 << M1S_2level) - 1);
666
667 for (n = 0; n < M2S; n++)
668 {
669 i = c + M2[n].x;
670 j = r + M2[n].y;
671 mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
672 }
673
674 mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
675
676 bl_encode_in_context (mask, mask2level, pbm_getpixel (b1, c, r));
677
678 }
679 }
680 if (V)
681 fprintf (stderr, "\n");
682 bl_freemodel ();
683}
684
685
686void
687bl_clair_decompress (marktype d1, marktype d2)
688{
689 register int r, c;
690 register int i, j, n;
691 register unsigned long mask, mask2level = 0;
692 unsigned long p;
693 int cols, rows;
694 int gap;
695 Pixel **b1, **b2;
696
697 bl_clearmodel ();
698 twolevel = 1;
699
700 b1 = d1.bitmap;
701 b2 = d2.bitmap;
702 cols = d1.w;
703 rows = d1.h;
704
705 gap = max (50, rows / 10);
706
707 i = DecodeGammaDist ();
708 j = DecodeGammaDist ();
709 if ((i != cols) || (j != rows))
710 error_msg ("bl_clair_decompress", "incorrect size of residue image", "");
711
712 if (V)
713 fprintf (stderr, "cols=%d rows=%d\n", cols, rows);
714
715 for (r = 0; r < rows; r++)
716 {
717 if (V)
718 if (!(r % gap))
719 fprintf (stderr, ".");
720 for (c = 0; c < cols; c++)
721 {
722 mask = 0;
723 for (n = 0; n < M1S; n++)
724 {
725 i = c + M1[n].x;
726 j = r + M1[n].y;
727 mask = (2 * mask) | pbm_getpixel_trunc (b1, i, j, cols, rows);
728 }
729 mask2level = mask & ((1 << M1S_2level) - 1);
730 for (n = 0; n < M2S; n++)
731 {
732 i = c + M2[n].x;
733 j = r + M2[n].y;
734 mask = (2 * mask) | pbm_getpixel_trunc (b2, i, j, cols, rows);
735 }
736 mask2level = (mask2level << M2S_2level) | (mask & ((1 << M2S_2level) - 1));
737
738
739 bl_decode_in_context (mask, mask2level, &p);
740 if (p)
741 pbm_putpixel (b1, c, r, 1);
742 }
743 }
744 if (V)
745 fprintf (stderr, "\n");
746 bl_freemodel ();
747}
Note: See TracBrowser for help on using the repository browser.