source: trunk/libdjvu/GBitmap.cpp @ 206

Last change on this file since 206 was 206, checked in by Eugene Romanenko, 14 years ago

DJVU plugin: djvulibre updated to version 3.5.19

File size: 44.1 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: GBitmap.cpp,v 1.13 2007/03/25 20:48:31 leonb Exp $
57// $Name: release_3_5_19 $
58
59#ifdef HAVE_CONFIG_H
60# include "config.h"
61#endif
62#if NEED_GNUG_PRAGMAS
63# pragma implementation
64#endif
65
66#include "GBitmap.h"
67#include "ByteStream.h"
68#include "GRect.h"
69#include "GString.h"
70#include "GThreads.h"
71#include "GException.h"
72#include <string.h>
73
74// File "$Id: GBitmap.cpp,v 1.13 2007/03/25 20:48:31 leonb Exp $"
75// - Author: Leon Bottou, 05/1997
76
77
78#ifdef HAVE_NAMESPACES
79namespace DJVU {
80# ifdef NOT_DEFINED // Just to fool emacs c++ mode
81}
82#endif
83#endif
84
85// ----- constructor and destructor
86
87GBitmap::~GBitmap()
88{
89}
90
91void
92GBitmap::destroy(void)
93{
94  gbytes_data.resize(0);
95  bytes = 0;
96  grle.resize(0);
97  grlerows.resize(0);
98  rlelength = 0;
99}
100
101GBitmap::GBitmap()
102  : nrows(0), ncolumns(0), border(0), 
103    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data), 
104    grle(rle), grlerows(rlerows), rlelength(0),
105    monitorptr(0)
106{
107}
108
109GBitmap::GBitmap(int nrows, int ncolumns, int border)
110  : nrows(0), ncolumns(0), border(0), 
111    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data), 
112    grle(rle), grlerows(rlerows), rlelength(0),
113    monitorptr(0)
114{
115  G_TRY
116  { 
117    init(nrows, ncolumns, border);
118  }
119  G_CATCH_ALL
120  {
121    destroy();
122    G_RETHROW;
123  }
124  G_ENDCATCH;
125}
126
127GBitmap::GBitmap(ByteStream &ref, int border)
128  : nrows(0), ncolumns(0), border(0), 
129    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
130    grle(rle), grlerows(rlerows), rlelength(0),
131    monitorptr(0)
132{
133  G_TRY
134  { 
135    init(ref, border);
136  }
137  G_CATCH_ALL
138  {
139    destroy();
140    G_RETHROW;
141  }
142  G_ENDCATCH;
143}
144
145GBitmap::GBitmap(const GBitmap &ref)
146  : nrows(0), ncolumns(0), border(0), 
147    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data), 
148    grle(rle), grlerows(rlerows), rlelength(0),
149    monitorptr(0)
150{
151  G_TRY
152  { 
153    init(ref, ref.border);
154  }
155  G_CATCH_ALL
156  {
157    destroy();
158    G_RETHROW;
159  }
160  G_ENDCATCH;
161}
162
163GBitmap::GBitmap(const GBitmap &ref, int border)
164  : nrows(0), ncolumns(0), border(0), 
165    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
166    grle(rle), grlerows(rlerows), rlelength(0),
167    monitorptr(0)
168{
169  G_TRY
170  { 
171    init(ref, border);
172  }
173  G_CATCH_ALL
174  {
175    destroy();
176    G_RETHROW;
177  }
178  G_ENDCATCH;
179}
180
181
182GBitmap::GBitmap(const GBitmap &ref, const GRect &rect, int border)
183  : nrows(0), ncolumns(0), border(0), 
184    bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
185    grle(rle), grlerows(rlerows), rlelength(0),
186    monitorptr(0)
187{
188  G_TRY
189  { 
190    init(ref, rect, border);
191  }
192  G_CATCH_ALL
193  {
194    destroy();
195    G_RETHROW;
196  }
197  G_ENDCATCH;
198}
199
200
201
202
203
204
205// ----- initialization
206
207void 
208GBitmap::init(int arows, int acolumns, int aborder)
209{
210  GMonitorLock lock(monitor());
211  destroy();
212  grays = 2;
213  nrows = arows;
214  ncolumns = acolumns;
215  border = aborder;
216  bytes_per_row = ncolumns + border;
217  int npixels = nrows * bytes_per_row + border;
218  gzerobuffer=zeroes(bytes_per_row + border);
219  if (npixels > 0) 
220    {
221      gbytes_data.resize(npixels);
222      gbytes_data.clear();
223      bytes = bytes_data;
224    }
225}
226
227
228void 
229GBitmap::init(const GBitmap &ref, int aborder)
230{
231  GMonitorLock lock(monitor());
232  if (this != &ref) 
233    {
234      GMonitorLock lock(ref.monitor());
235      init(ref.nrows, ref.ncolumns, aborder);
236      grays = ref.grays;
237      unsigned char *row = bytes_data+border;
238      for (int n=0; n<nrows; n++, row+=bytes_per_row)
239      memcpy( (void*)row, (void*)ref[n],  ncolumns );
240    }
241  else if (aborder > border)
242    {
243      minborder(aborder);
244    }
245}
246
247
248void 
249GBitmap::init(const GBitmap &ref, const GRect &rect, int border)
250{
251  GMonitorLock lock(monitor());
252  // test bitmap physical equality
253  if (this == &ref)
254    {
255      GBitmap tmp;
256      tmp.grays = grays;
257      tmp.border = border;
258      tmp.bytes_per_row = bytes_per_row;
259      tmp.ncolumns = ncolumns;
260      tmp.nrows = nrows;
261      tmp.bytes = bytes;
262      tmp.gbytes_data.swap(gbytes_data);
263      tmp.grle.swap(grle);
264      bytes = 0 ;
265      init(tmp, rect, border);
266    }
267  else
268    {
269      GMonitorLock lock(ref.monitor());
270      // create empty bitmap
271      init(rect.height(), rect.width(), border);
272      grays = ref.grays;
273      // compute destination rectangle
274      GRect rect2(0, 0, ref.columns(), ref.rows() );
275      rect2.intersect(rect2, rect);
276      rect2.translate(-rect.xmin, -rect.ymin);
277      // copy bits
278      if (! rect2.isempty())
279        {
280          for (int y=rect2.ymin; y<rect2.ymax; y++)
281            {
282              unsigned char *dst = (*this)[y];
283              const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
284              for (int x=rect2.xmin; x<rect2.xmax; x++)
285                dst[x] = src[x];
286            }
287        }
288    }
289}
290
291
292void 
293GBitmap::init(ByteStream &ref, int aborder)
294{
295  GMonitorLock lock(monitor());
296  // Get magic number
297  char magic[2];
298  magic[0] = magic[1] = 0;
299  ref.readall((void*)magic, sizeof(magic));
300  char lookahead = '\n';
301  int acolumns = read_integer(lookahead, ref);
302  int arows = read_integer(lookahead, ref);
303  int maxval = 1;
304  init(arows, acolumns, aborder);
305  // go reading file
306  if (magic[0]=='P')
307    {
308      switch(magic[1])
309        {
310        case '1':
311          grays = 2;
312          read_pbm_text(ref); 
313          return;
314        case '2':
315          maxval = read_integer(lookahead, ref);
316          if (maxval > 65535)
317            G_THROW("Cannot read PGM with depth greater than 16 bits.");
318          grays = (maxval>255 ? 256 : maxval+1);
319          read_pgm_text(ref, maxval); 
320          return;
321        case '4':
322          grays = 2;
323          read_pbm_raw(ref); 
324          return;
325        case '5':
326          maxval = read_integer(lookahead, ref);
327          if (maxval > 65535)
328            G_THROW("Cannot read PGM with depth greater than 16 bits.");
329          grays = (maxval>255 ? 256 : maxval+1);
330          read_pgm_raw(ref, maxval); 
331          return;
332        }
333    }
334  else if (magic[0]=='R')
335    {
336      switch(magic[1])
337        {
338        case '4':
339          grays = 2;
340          read_rle_raw(ref); 
341          return;
342        }
343    }
344  G_THROW( ERR_MSG("GBitmap.bad_format") );
345}
346
347void
348GBitmap::donate_data(unsigned char *data, int w, int h)
349{
350  destroy();
351  grays = 2;
352  nrows = h;
353  ncolumns = w;
354  border = 0;
355  bytes_per_row = w;
356  gbytes_data.replace(data,w*h);
357  bytes = bytes_data;
358  rlelength = 0;
359}
360
361void
362GBitmap::donate_rle(unsigned char *rledata, unsigned int rledatalen, int w, int h)
363{
364  destroy();
365  grays = 2;
366  nrows = h;
367  ncolumns = w;
368  border = 0;
369  bytes_per_row = w;
370//  rle = rledata;
371  grle.replace(rledata,rledatalen);
372  rlelength = rledatalen;
373}
374
375
376unsigned char *
377GBitmap::take_data(size_t &offset)
378{
379  GMonitorLock lock(monitor());
380  unsigned char *ret = bytes_data;
381  if (ret) offset = (size_t)border;
382  bytes_data=0;
383  return ret;
384}
385
386const unsigned char *
387GBitmap::get_rle(unsigned int &rle_length)
388{
389  if(!rle)
390    compress();
391  rle_length=rlelength;
392  return rle; 
393}
394
395// ----- compression
396
397
398void 
399GBitmap::compress()
400{
401  if (grays > 2)
402    G_THROW( ERR_MSG("GBitmap.cant_compress") );
403  GMonitorLock lock(monitor());
404  if (bytes)
405    {
406      grle.resize(0);
407      grlerows.resize(0);
408      rlelength = encode(rle,grle);
409      if (rlelength)
410        {
411          gbytes_data.resize(0);
412          bytes = 0;
413        }
414    }
415}
416
417void
418GBitmap::uncompress()
419{
420  GMonitorLock lock(monitor());
421  if (!bytes && rle)
422    decode(rle);
423}
424
425
426
427unsigned int 
428GBitmap::get_memory_usage() const
429{
430  unsigned long usage = sizeof(GBitmap);
431  if (bytes)
432    usage += nrows * bytes_per_row + border;
433  if (rle)
434    usage += rlelength;
435  return usage;
436}
437
438
439void 
440GBitmap::minborder(int minimum)
441{
442  if (border < minimum)
443    {
444      GMonitorLock lock(monitor());
445      if (border < minimum)
446        {
447          if (bytes)
448            {
449              GBitmap tmp(*this, minimum);
450              bytes_per_row = tmp.bytes_per_row;
451              tmp.gbytes_data.swap(gbytes_data);
452              bytes = bytes_data;
453              tmp.bytes = 0;
454            }
455          border = minimum;
456          gzerobuffer=zeroes(border + ncolumns + border);
457        }
458    }
459}
460
461
462#define NMONITORS 8
463static GMonitor monitors[NMONITORS];
464
465void
466GBitmap::share()
467{
468  if (!monitorptr)
469    {
470      unsigned long x = (unsigned long)this;
471      monitorptr = &monitors[(x^(x>>5)) % NMONITORS];
472    }
473}
474
475
476// ----- gray levels
477
478void
479GBitmap::set_grays(int ngrays)
480{
481  if (ngrays<2 || ngrays>256)
482    G_THROW( ERR_MSG("GBitmap.bad_levels") );
483  // set gray levels
484  GMonitorLock lock(monitor());
485  grays = ngrays;
486  if (ngrays>2 && !bytes)
487    uncompress();
488}
489
490void 
491GBitmap::change_grays(int ngrays)
492{
493  GMonitorLock lock(monitor());
494  // set number of grays
495  int ng = ngrays - 1;
496  int og = grays - 1;
497  set_grays(ngrays);
498  // setup conversion table
499  unsigned char conv[256];
500  for (int i=0; i<256; i++)
501    {
502      if (i > og)
503        conv[i] = ng;
504      else
505        conv[i] = (i*ng+og/2)/og;
506    }
507  // perform conversion
508  for (int row=0; row<nrows; row++)
509    {
510      unsigned char *p = (*this)[row];
511      for (int n=0; n<ncolumns; n++)
512        p[n] = conv[ p[n] ];
513    }
514}
515
516void 
517GBitmap::binarize_grays(int threshold)
518{
519  GMonitorLock lock(monitor());
520  if (bytes)
521    for (int row=0; row<nrows; row++)
522      {
523        unsigned char *p = (*this)[row];
524        for(unsigned char const * const pend=p+ncolumns;p<pend;++p)
525        {
526          *p = (*p>threshold) ? 1 : 0;
527        }
528      }
529  grays = 2;
530}
531
532
533// ----- additive blitting
534
535#undef min
536#undef max
537
538static inline int
539min(int x, int y) 
540{ 
541  return (x < y ? x : y);
542}
543
544static inline int
545max(int x, int y) 
546{ 
547  return (x > y ? x : y);
548}
549
550void 
551GBitmap::blit(const GBitmap *bm, int x, int y)
552{
553  // Check boundaries
554  if ((x >= ncolumns)              || 
555      (y >= nrows)                 ||
556      (x + (int)bm->columns() < 0) || 
557      (y + (int)bm->rows() < 0)     )
558    return;
559
560  // Perform blit
561  GMonitorLock lock1(monitor());
562  GMonitorLock lock2(bm->monitor());
563  if (bm->bytes)
564    {
565      if (!bytes_data)
566        uncompress();
567      // Blit from bitmap
568      const unsigned char *srow = bm->bytes + bm->border;
569      unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
570      for (int sr = 0; sr < bm->nrows; sr++)
571        {
572          if (sr+y>=0 && sr+y<nrows) 
573            {
574              int sc = max(0, -x);
575              int sc1 = min(bm->ncolumns, ncolumns-x);
576              while (sc < sc1)
577                {
578                  drow[sc] += srow[sc];
579                  sc += 1;
580                }
581            }
582          srow += bm->bytes_per_row;
583          drow += bytes_per_row;
584        }
585    }
586  else if (bm->rle)
587    {
588      if (!bytes_data)
589        uncompress();
590      // Blit from rle
591      const unsigned char *runs = bm->rle;
592      unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
593      int sr = bm->nrows - 1;
594      drow += sr * bytes_per_row;
595      int sc = 0;
596      char p = 0;
597      while (sr >= 0)
598        {
599          const int z = read_run(runs);
600          if (sc+z > bm->ncolumns)
601            G_THROW( ERR_MSG("GBitmap.lost_sync") );
602          int nc = sc + z;
603          if (p && sr+y>=0 && sr+y<nrows) 
604            {
605              if (sc + x < 0) 
606                sc = min(-x, nc); 
607              while (sc < nc && sc + x<ncolumns)
608                drow[sc++] += 1;
609            }
610          sc = nc;
611          p = 1 - p;
612          if (sc >= bm->ncolumns) 
613            {
614              p = 0;
615              sc = 0;
616              drow -= bytes_per_row;
617              sr -= 1; 
618            }
619        }
620    }
621}
622
623
624
625void 
626GBitmap::blit(const GBitmap *bm, int xh, int yh, int subsample)
627{
628  // Use code when no subsampling is necessary
629  if (subsample == 1)
630    {
631      blit(bm, xh, yh);
632      return;
633    }
634
635  // Check boundaries
636  if ((xh >= ncolumns * subsample) || 
637      (yh >= nrows * subsample)    ||
638      (xh + (int)bm->columns() < 0)   || 
639      (yh + (int)bm->rows() < 0)     )
640    return;
641
642  // Perform subsampling blit
643  GMonitorLock lock1(monitor());
644  GMonitorLock lock2(bm->monitor());
645  if (bm->bytes)
646    {
647      if (!bytes_data)
648        uncompress();
649      // Blit from bitmap
650      int dr, dr1, zdc, zdc1;
651      euclidian_ratio(yh, subsample, dr, dr1);
652      euclidian_ratio(xh, subsample, zdc, zdc1);
653      const unsigned char *srow = bm->bytes + bm->border;
654      unsigned char *drow = bytes_data + border + dr*bytes_per_row;
655      for (int sr = 0; sr < bm->nrows; sr++)
656        {
657          if (dr>=0 && dr<nrows) 
658            {
659              int dc = zdc;
660              int dc1 = zdc1;
661              for (int sc=0; sc < bm->ncolumns; sc++) 
662                {
663                  if (dc>=0 && dc<ncolumns)
664                    drow[dc] += srow[sc];
665                  if (++dc1 >= subsample) 
666                    {
667                      dc1 = 0;
668                      dc += 1;
669                    }
670                }
671            }
672          // next line in source
673          srow += bm->bytes_per_row;
674          // next line fraction in destination
675          if (++dr1 >= subsample)
676            {
677              dr1 = 0;
678              dr += 1;
679              drow += bytes_per_row;
680            }
681        }
682    }
683  else if (bm->rle)
684    {
685      if (!bytes_data)
686        uncompress();
687      // Blit from rle
688      int dr, dr1, zdc, zdc1;
689      euclidian_ratio(yh+bm->nrows-1, subsample, dr, dr1);
690      euclidian_ratio(xh, subsample, zdc, zdc1);
691      const unsigned char *runs = bm->rle;
692      unsigned char *drow = bytes_data + border + dr*bytes_per_row;
693      int sr = bm->nrows -1;
694      int sc = 0;
695      char p = 0;
696      int dc = zdc;
697      int dc1 = zdc1;
698      while (sr >= 0)
699        {
700          int z = read_run(runs);
701          if (sc+z > bm->ncolumns)
702            G_THROW( ERR_MSG("GBitmap.lost_sync") );
703          int nc = sc + z;
704
705          if (dr>=0 && dr<nrows)
706            while (z>0 && dc<ncolumns)
707              {
708                int zd = subsample - dc1;
709                if (zd > z) 
710                  zd = z;
711                if (p && dc>=0) 
712                  drow[dc] += zd;
713                z -= zd;
714                dc1 += zd;
715                if (dc1 >= subsample)
716                  {
717                    dc1 = 0;
718                    dc += 1;
719                  }
720              }
721          // next fractional row
722          sc = nc;
723          p = 1 - p;
724          if (sc >= bm->ncolumns) 
725            {
726              sc = 0;
727              dc = zdc;
728              dc1 = zdc1;
729              p = 0;
730              sr -= 1; 
731              if (--dr1 < 0)
732                {
733                  dr1 = subsample - 1;
734                  dr -= 1;
735                  drow -= bytes_per_row;
736                }
737            }
738        }
739    }
740}
741
742
743
744// ------ load bitmaps
745
746
747unsigned int 
748GBitmap::read_integer(char &c, ByteStream &bs)
749{
750  unsigned int x = 0;
751  // eat blank before integer
752  while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#') 
753    {
754      if (c=='#') 
755        do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
756      c = 0; 
757      bs.read(&c, 1);
758    }
759  // check integer
760  if (c<'0' || c>'9')
761    G_THROW( ERR_MSG("GBitmap.not_int") );
762  // eat integer
763  while (c>='0' && c<='9') 
764    {
765      x = x*10 + c - '0';
766      c = 0;
767      bs.read(&c, 1);
768    }
769  return x;
770}
771
772
773void 
774GBitmap::read_pbm_text(ByteStream &bs)
775{
776  unsigned char *row = bytes_data + border;
777  row += (nrows-1) * bytes_per_row;
778  for (int n = nrows-1; n>=0; n--) 
779    {
780      for (int c = 0; c<ncolumns; c++) 
781        {
782          char bit = 0;
783          bs.read(&bit,1);
784          while (bit==' ' || bit=='\t' || bit=='\r' || bit=='\n')
785            { 
786              bit=0; 
787              bs.read(&bit,1); 
788            }
789          if (bit=='1')
790            row[c] = 1;
791          else if (bit=='0')
792            row[c] = 0;
793          else
794            G_THROW( ERR_MSG("GBitmap.bad_PBM") );
795        }
796      row -= bytes_per_row;
797    }
798}
799
800void 
801GBitmap::read_pgm_text(ByteStream &bs, int maxval)
802{
803  unsigned char *row = bytes_data + border;
804  row += (nrows-1) * bytes_per_row;
805  char lookahead = '\n';
806  GTArray<unsigned char> ramp(0, maxval);
807  for (int i=0; i<=maxval; i++)
808    ramp[i] = (i<maxval ? ((grays-1)*(maxval-i) + maxval/2) / maxval : 0);
809  for (int n = nrows-1; n>=0; n--) 
810    {
811      for (int c = 0; c<ncolumns; c++)
812        row[c] = ramp[read_integer(lookahead, bs)];
813      row -= bytes_per_row;
814    }
815}
816
817void 
818GBitmap::read_pbm_raw(ByteStream &bs)
819{
820  unsigned char *row = bytes_data + border;
821  row += (nrows-1) * bytes_per_row;
822  for (int n = nrows-1; n>=0; n--) 
823    {
824      unsigned char acc = 0;
825      unsigned char mask = 0;
826      for (int c = 0; c<ncolumns; c++)
827        {
828          if (!mask) 
829            {
830              bs.read(&acc, 1);
831              mask = (unsigned char)0x80;
832            }
833          if (acc & mask)
834            row[c] = 1;
835          else
836            row[c] = 0;
837          mask >>= 1;
838        }
839      row -= bytes_per_row;
840    }
841}
842
843void 
844GBitmap::read_pgm_raw(ByteStream &bs, int maxval)
845{
846  int maxbin = (maxval>255) ? 65536 : 256;
847  GTArray<unsigned char> ramp(0, maxbin-1);
848  for (int i=0; i<maxbin; i++)
849    ramp[i] = (i<maxval ? ((grays-1)*(maxval-i) + maxval/2) / maxval : 0);
850  unsigned char *bramp = ramp;
851  unsigned char *row = bytes_data + border;
852  row += (nrows-1) * bytes_per_row;
853  for (int n = nrows-1; n>=0; n--) 
854    {
855      if (maxbin > 256)
856        {
857          for (int c = 0; c<ncolumns; c++)
858            {
859              unsigned char x[2];
860              bs.read((void*)&x, 2);
861              row[c] = bramp[x[0]*256+x[1]];
862            }
863        }
864      else
865        {
866          for (int c = 0; c<ncolumns; c++)
867            {
868              unsigned char x;
869              bs.read((void*)&x, 1);
870              row[c] = bramp[x];
871            }
872        }
873      row -= bytes_per_row;
874    }
875}
876
877void 
878GBitmap::read_rle_raw(ByteStream &bs)
879{
880  // interpret runs data
881  unsigned char h;
882  unsigned char p = 0;
883  unsigned char *row = bytes_data + border;
884  int n = nrows - 1;
885  row += n * bytes_per_row;
886  int c = 0;
887  while (n >= 0)
888    {
889      bs.read(&h, 1);
890      int x = h;
891      if (x >= (int)RUNOVERFLOWVALUE)
892        {
893          bs.read(&h, 1);
894          x = h + ((x - (int)RUNOVERFLOWVALUE) << 8);
895        }
896      if (c+x > ncolumns)
897        G_THROW( ERR_MSG("GBitmap.lost_sync") );
898      while (x-- > 0)
899        row[c++] = p;
900      p = 1 - p;
901      if (c >= ncolumns) 
902        {
903          c = 0;
904          p = 0;
905          row -= bytes_per_row;
906          n -= 1; 
907        }
908    }
909}
910
911
912// ------ save bitmaps
913
914void 
915GBitmap::save_pbm(ByteStream &bs, int raw)
916{
917  // check arguments
918  if (grays > 2)
919    G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
920  GMonitorLock lock(monitor());
921  // header
922  {
923    GUTF8String head;
924    head.format("P%c\n%d %d\n", (raw ? '4' : '1'), ncolumns, nrows);
925    bs.writall((void*)(const char *)head, head.length());
926  }
927  // body
928  if(raw)
929  {
930    if(!rle)
931      compress();
932    const unsigned char *runs=rle;
933    const unsigned char * const runs_end=rle+rlelength;
934    const int count=(ncolumns+7)>>3;
935    unsigned char *buf;
936    GPBuffer<unsigned char> gbuf(buf,count);
937    while(runs<runs_end)
938    {
939      rle_get_bitmap(ncolumns,runs,buf,false);
940      bs.writall(buf,count);
941    }
942  }else
943  {
944    if (!bytes)
945      uncompress();
946    const unsigned char *row = bytes + border;
947    int n = nrows - 1;
948    row += n * bytes_per_row;
949    while (n >= 0)
950    {
951      unsigned char eol='\n';
952      for (int c=0; c<ncolumns;)
953      {
954        unsigned char bit= (row[c] ? '1' : '0');
955        bs.write((void*)&bit, 1);
956        c += 1;
957        if (c==ncolumns || (c&(int)RUNMSBMASK)==0) 
958          bs.write((void*)&eol, 1);         
959       }
960      // next row
961      row -= bytes_per_row;
962      n -= 1;
963    }
964  }
965}
966
967void 
968GBitmap::save_pgm(ByteStream &bs, int raw)
969{
970  // checks
971  GMonitorLock lock(monitor());
972  if (!bytes)
973    uncompress();
974  // header
975  GUTF8String head;
976  head.format("P%c\n%d %d\n%d\n", (raw ? '5' : '2'), ncolumns, nrows, grays-1);
977  bs.writall((void*)(const char *)head, head.length());
978  // body
979  const unsigned char *row = bytes + border;
980  int n = nrows - 1;
981  row += n * bytes_per_row;
982  while (n >= 0)
983    {
984      if (raw)
985        {
986          for (int c=0; c<ncolumns; c++)
987            {
988              char x = grays - 1 - row[c];
989              bs.write((void*)&x, 1);
990            }
991        }
992      else 
993        {
994          unsigned char eol='\n';
995          for (int c=0; c<ncolumns; )
996            {
997              head.format("%d ", grays - 1 - row[c]);
998              bs.writall((void*)(const char *)head, head.length());
999              c += 1;
1000              if (c==ncolumns || (c&0x1f)==0) 
1001                bs.write((void*)&eol, 1);         
1002            }
1003        }
1004      row -= bytes_per_row;
1005      n -= 1;
1006    }
1007}
1008
1009void 
1010GBitmap::save_rle(ByteStream &bs)
1011{
1012  // checks
1013  if (ncolumns==0 || nrows==0)
1014    G_THROW( ERR_MSG("GBitmap.not_init") );
1015  GMonitorLock lock(monitor());
1016  if (grays > 2)
1017    G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
1018  // header
1019  GUTF8String head;
1020  head.format("R4\n%d %d\n", ncolumns, nrows);
1021  bs.writall((void*)(const char *)head, head.length());
1022  // body
1023  if (rle)
1024    {
1025      bs.writall((void*)rle, rlelength);
1026    }
1027  else
1028    {
1029      unsigned char *runs = 0;
1030      GPBuffer<unsigned char> gruns(runs);
1031      int size = encode(runs,gruns);
1032      bs.writall((void*)runs, size);
1033    }
1034}
1035
1036
1037// ------ runs
1038
1039
1040void
1041GBitmap::makerows(
1042  int nrows, const int ncolumns, unsigned char *runs, unsigned char *rlerows[])
1043{
1044  while (nrows-- > 0)
1045  {
1046    rlerows[nrows] = runs;
1047    int c;
1048    for(c=0;c<ncolumns;c+=GBitmap::read_run(runs))
1049      EMPTY_LOOP;
1050    if (c > ncolumns)
1051      G_THROW( ERR_MSG("GBitmap.lost_sync2") );
1052  }
1053}
1054
1055
1056void
1057GBitmap::rle_get_bitmap (
1058  const int ncolumns,
1059  const unsigned char *&runs,
1060  unsigned char *bitmap,
1061  const bool invert )
1062{
1063  const int obyte_def=invert?0xff:0;
1064  const int obyte_ndef=invert?0:0xff;
1065  int mask=0x80,obyte=0;
1066  for(int c=ncolumns;c > 0 ;)
1067  {
1068    int x=read_run(runs);
1069    c-=x;
1070    while((x--)>0)
1071    {
1072      if(!(mask>>=1))
1073      {
1074        *(bitmap++) = obyte^obyte_def;
1075        obyte=0;
1076        mask=0x80;
1077        for(;x>=8;x-=8)
1078        {
1079          *(bitmap++)=obyte_def;
1080        }
1081      }
1082    }
1083    if(c>0)
1084    {
1085      int x=read_run(runs);
1086      c-=x;
1087      while((x--)>0)
1088      {
1089        obyte|=mask;
1090        if(!(mask>>=1))
1091        {
1092          *(bitmap++)=obyte^obyte_def;
1093          obyte=0;
1094          mask=0x80;
1095          for(;(x>8);x-=8)
1096            *(bitmap++)=obyte_ndef;
1097        }
1098      }
1099    }
1100  }
1101  if(mask != 0x80)
1102  {
1103    *(bitmap++)=obyte^obyte_def;
1104  }
1105}
1106
1107int 
1108GBitmap::rle_get_bits(int rowno, unsigned char *bits) const
1109{
1110  GMonitorLock lock(monitor());
1111  if (!rle)
1112    return 0;
1113  if (rowno<0 || rowno>=nrows)
1114    return 0;
1115  if (!rlerows)
1116  {
1117    const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
1118    makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
1119  }
1120  int n = 0;
1121  int p = 0;
1122  int c = 0;
1123  unsigned char *runs = rlerows[rowno];
1124  while (c < ncolumns)
1125    {
1126      const int x=read_run(runs);
1127      if ((c+=x)>ncolumns)
1128        c = ncolumns;
1129      while (n<c)
1130        bits[n++] = p;
1131      p = 1-p;
1132    }
1133  return n;
1134}
1135
1136
1137int 
1138GBitmap::rle_get_runs(int rowno, int *rlens) const
1139{
1140  GMonitorLock lock(monitor());
1141  if (!rle)
1142    return 0;
1143  if (rowno<0 || rowno>=nrows)
1144    return 0;
1145  if (!rlerows)
1146  {
1147    const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
1148    makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
1149  }
1150  int n = 0;
1151  int d = 0;
1152  int c = 0;
1153  unsigned char *runs = rlerows[rowno];
1154  while (c < ncolumns)
1155    {
1156      const int x=read_run(runs);
1157      if (n>0 && !x)
1158        {
1159          n--;
1160          d = d-rlens[n];
1161        }
1162      else 
1163        {
1164          rlens[n++] = (c+=x)-d;
1165          d = c;
1166        }
1167    }
1168  return n;
1169}
1170
1171
1172int 
1173GBitmap::rle_get_rect(GRect &rect) const
1174{
1175  GMonitorLock lock(monitor());
1176  if (!rle) 
1177    return 0;
1178  int area = 0;
1179  unsigned char *runs = rle;
1180  rect.xmin = ncolumns;
1181  rect.ymin = nrows;
1182  rect.xmax = 0;
1183  rect.ymax = 0;
1184  int r = nrows;
1185  while (--r >= 0)
1186    {
1187      int p = 0;
1188      int c = 0;
1189      int n = 0;
1190      while (c < ncolumns)
1191        {
1192          const int x=read_run(runs);
1193          if(x)
1194            {
1195              if (p)
1196                {
1197                  if (c < rect.xmin) 
1198                    rect.xmin = c;
1199                  if ((c += x) > rect.xmax) 
1200                    rect.xmax = c-1;
1201                  n += x;
1202                }
1203              else
1204                {
1205                  c += x;
1206                }
1207            }
1208          p = 1-p;
1209        }
1210      area += n;
1211      if (n)
1212        {
1213          rect.ymin = r;
1214          if (r > rect.ymax) 
1215            rect.ymax = r;
1216        }
1217    }
1218  if (area==0)
1219    rect.clear();
1220  return area;
1221}
1222
1223
1224
1225// ------ helpers
1226
1227int
1228GBitmap::encode(unsigned char *&pruns,GPBuffer<unsigned char> &gpruns) const
1229{
1230  // uncompress rle information
1231  if (nrows==0 || ncolumns==0)
1232  {
1233    gpruns.resize(0);
1234    return 0;
1235  }
1236  if (!bytes)
1237    {
1238      unsigned char *runs;
1239      GPBuffer<unsigned char> gruns(runs,rlelength);
1240      memcpy((void*)runs, rle, rlelength);
1241      gruns.swap(gpruns);
1242      return rlelength;
1243    }
1244  gpruns.resize(0);
1245  // create run array
1246  int pos = 0;
1247  int maxpos = 1024 + ncolumns + ncolumns;
1248  unsigned char *runs;
1249  GPBuffer<unsigned char> gruns(runs,maxpos);
1250  // encode bitmap as rle
1251  const unsigned char *row = bytes + border;
1252  int n = nrows - 1;
1253  row += n * bytes_per_row;
1254  while (n >= 0)
1255    {
1256      if (maxpos < pos+ncolumns+ncolumns+2)
1257        {
1258          maxpos += 1024 + ncolumns + ncolumns;
1259          gruns.resize(maxpos);
1260        }
1261
1262      unsigned char *runs_pos=runs+pos;
1263      const unsigned char * const runs_pos_start=runs_pos;
1264      append_line(runs_pos,row,ncolumns);
1265      pos+=(size_t)runs_pos-(size_t)runs_pos_start;
1266      row -= bytes_per_row;
1267      n -= 1;
1268    }
1269  // return result
1270  gruns.resize(pos);
1271  gpruns.swap(gruns);
1272  return pos;
1273}
1274
1275void 
1276GBitmap::decode(unsigned char *runs)
1277{
1278  // initialize pixel array
1279  if (nrows==0 || ncolumns==0)
1280    G_THROW( ERR_MSG("GBitmap.not_init") );
1281  bytes_per_row = ncolumns + border;
1282  if (runs==0)
1283    G_THROW( ERR_MSG("GBitmap.null_arg") );
1284  int npixels = nrows * bytes_per_row + border;
1285  if (!bytes_data)
1286  {
1287    gbytes_data.resize(npixels);
1288    bytes = bytes_data;
1289  }
1290  gbytes_data.clear();
1291  gzerobuffer=zeroes(bytes_per_row + border);
1292  // interpret runs data
1293  int c, n;
1294  unsigned char p = 0;
1295  unsigned char *row = bytes_data + border;
1296  n = nrows - 1;
1297  row += n * bytes_per_row;
1298  c = 0;
1299  while (n >= 0)
1300    {
1301      int x = read_run(runs);
1302      if (c+x > ncolumns)
1303        G_THROW( ERR_MSG("GBitmap.lost_sync2") );
1304      while (x-- > 0)
1305        row[c++] = p;
1306      p = 1 - p;
1307      if (c >= ncolumns) 
1308        {
1309          c = 0;
1310          p = 0;
1311          row -= bytes_per_row;
1312          n -= 1; 
1313        }
1314    }
1315  // Free rle data possibly attached to this bitmap
1316  grle.resize(0);
1317  grlerows.resize(0);
1318  rlelength = 0;
1319#ifndef NDEBUG
1320  check_border();
1321#endif
1322}
1323
1324class GBitmap::ZeroBuffer : public GPEnabled
1325{
1326public:
1327  ZeroBuffer(const unsigned int zerosize);
1328  unsigned char *zerobuffer;
1329  GPBuffer<unsigned char> gzerobuffer;
1330};
1331
1332GBitmap::ZeroBuffer::ZeroBuffer(const unsigned int zerosize)
1333: gzerobuffer(zerobuffer,zerosize)
1334{
1335  gzerobuffer.clear();
1336  GBitmap::zerobuffer=zerobuffer;
1337  GBitmap::zerosize=zerosize;
1338}
1339
1340static const unsigned char static_zerobuffer[]=
1341{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 32
1342 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 64
1343 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 96
1344 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 128
1345 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 160
1346 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 192
1347 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 234
1348 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 256
1349 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 288
1350 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 320
1351 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 352
1352 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 384
1353 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 416
1354 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 448
1355 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 480
1356 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512
1357 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 544
1358 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 576
1359 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 608
1360 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 640
1361 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 672
1362 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 704
1363 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 736
1364 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768
1365 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 800
1366 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 832
1367 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 864
1368 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 896
1369 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 928
1370 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 960
1371 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 992
1372 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024
1373 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+32
1374 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+64
1375 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+96
1376 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+128
1377 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+160
1378 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+192
1379 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+234
1380 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+256
1381 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+288
1382 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+320
1383 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+352
1384 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+384
1385 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+416
1386 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+448
1387 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+480
1388 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+512
1389 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+544
1390 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+576
1391 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+608
1392 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+640
1393 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+672
1394 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+704
1395 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+736
1396 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+768
1397 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+800
1398 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+832
1399 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+864
1400 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+896
1401 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+928
1402 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+960
1403 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+992
1404 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048
1405 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+32
1406 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+64
1407 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+96
1408 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+128
1409 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+160
1410 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+192
1411 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+234
1412 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+256
1413 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+288
1414 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+320
1415 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+352
1416 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+384
1417 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+416
1418 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+448
1419 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+480
1420 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+512
1421 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+544
1422 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+576
1423 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+608
1424 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+640
1425 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+672
1426 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+704
1427 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+736
1428 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+768
1429 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+800
1430 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+832
1431 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+864
1432 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+896
1433 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+928
1434 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+960
1435 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+992
1436 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072
1437 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+32
1438 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+64
1439 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+96
1440 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+128
1441 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+160
1442 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+192
1443 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+234
1444 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+256
1445 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+288
1446 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+320
1447 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+352
1448 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+384
1449 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+416
1450 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+448
1451 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+480
1452 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+512
1453 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+544
1454 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+576
1455 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+608
1456 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+640
1457 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+672
1458 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+704
1459 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+736
1460 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+768
1461 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+800
1462 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+832
1463 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+864
1464 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+896
1465 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+928
1466 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+960
1467 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+992
1468 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // 4096
1469
1470int GBitmap::zerosize = sizeof(static_zerobuffer);
1471unsigned char *GBitmap::zerobuffer=const_cast<unsigned char *>(static_zerobuffer);
1472
1473GP<GBitmap::ZeroBuffer>
1474GBitmap::zeroes(int required)
1475{
1476  GMonitorLock lock(&monitors[0]); // any monitor would do
1477  static GP<GBitmap::ZeroBuffer> gzerobuffer;
1478  if (zerosize < required)
1479  {
1480    int z;
1481    for(z=zerosize;z<required;z <<= 1)
1482      EMPTY_LOOP;
1483    z=(z+0xfff)&(~0xfff);
1484    gzerobuffer=new GBitmap::ZeroBuffer((unsigned int)z);
1485  }
1486  return gzerobuffer;
1487}
1488
1489
1490// Fills a bitmap with the given value
1491void 
1492GBitmap::fill(unsigned char value)
1493{
1494  GMonitorLock lock(monitor());
1495  for(unsigned int y=0; y<rows(); y++)
1496    {
1497      unsigned char* bm_y = (*this)[y];
1498      for(unsigned int x=0; x<columns(); x++)
1499        bm_y[x] = value;
1500    }
1501}
1502
1503
1504void 
1505GBitmap::append_long_run(unsigned char *&data, int count)
1506{
1507  while (count > MAXRUNSIZE)
1508    {
1509      data[0] = data[1] = 0xff;
1510      data[2] = 0;
1511      data += 3;
1512      count -= MAXRUNSIZE;
1513    }
1514  if (count < RUNOVERFLOWVALUE)
1515    {
1516      data[0] = count;
1517      data += 1;
1518    }
1519  else
1520    {
1521      data[0] = (count>>8) + GBitmap::RUNOVERFLOWVALUE;
1522      data[1] = (count & 0xff);
1523      data += 2;
1524    }
1525}
1526
1527
1528void
1529GBitmap::append_line(unsigned char *&data,const unsigned char *row,
1530                     const int rowlen,bool invert)
1531{
1532  const unsigned char *rowend=row+rowlen;
1533  bool p=!invert;
1534  while(row<rowend)
1535    {
1536      int count=0;
1537      if ((p=!p)) 
1538        {
1539          if(*row)
1540            for(++count,++row;(row<rowend)&&*row;++count,++row)
1541                EMPTY_LOOP;
1542        } 
1543      else if(!*row)
1544        {
1545          for(++count,++row;(row<rowend)&&!*row;++count,++row)
1546                EMPTY_LOOP;
1547        }
1548      append_run(data,count);
1549    }
1550}
1551
1552#if 0
1553static inline int
1554GetRowTDLRNR(
1555  GBitmap &bit,const int row, const unsigned char *&startptr,
1556  const unsigned char *&stopptr)
1557{
1558  stopptr=(startptr=bit[row])+bit.columns();
1559  return 1;
1560}
1561
1562static inline int
1563GetRowTDLRNR(
1564  GBitmap &bit,const int row, const unsigned char *&startptr,
1565  const unsigned char *&stopptr)
1566{
1567  stopptr=(startptr=bit[row])+bit.columns();
1568  return 1;
1569}
1570
1571static inline int
1572GetRowTDRLNR(
1573  GBitmap &bit,const int row, const unsigned char *&startptr,
1574  const unsigned char *&stopptr)
1575{
1576  startptr=(stopptr=bit[row]-1)+bit.columns();
1577  return -1;
1578}
1579#endif // 0
1580
1581GP<GBitmap> 
1582GBitmap::rotate(int count)
1583{
1584  GP<GBitmap> newbitmap=this;
1585  count = count & 3;
1586  if(count)
1587  {
1588    if( count & 0x01 )
1589    {
1590      newbitmap = new GBitmap(ncolumns, nrows);
1591    }else
1592    {
1593      newbitmap = new GBitmap(nrows, ncolumns);
1594    }
1595    GMonitorLock lock(monitor());
1596    if (!bytes_data)
1597      uncompress();
1598    GBitmap &dbitmap = *newbitmap;
1599    dbitmap.set_grays(grays);
1600    switch(count)
1601    {
1602    case 3: // rotate 90 counter clockwise
1603      {
1604        const int lastrow = dbitmap.rows()-1;
1605        for(int y=0; y<nrows; y++)
1606        {
1607          const unsigned char *r=operator[] (y);
1608          for(int x=0,xnew=lastrow;xnew>=0; x++,xnew--)
1609          {
1610            dbitmap[xnew][y] = r[x];
1611          }
1612        }
1613      }
1614      break;
1615    case 2: // rotate 180 counter clockwise
1616      {
1617        const int lastrow = dbitmap.rows()-1;
1618        const int lastcolumn = dbitmap.columns()-1;
1619        for(int y=0,ynew=lastrow;ynew>=0; y++,ynew--)
1620        {
1621          const unsigned char *r=operator[] (y);
1622          unsigned char *d=dbitmap[ynew];
1623          for(int xnew=lastcolumn;xnew>=0; r++,--xnew)
1624          {
1625            d[xnew] = *r;
1626          }
1627        }
1628      }
1629      break;
1630    case 1: // rotate 270 counter clockwise
1631      {
1632        const int lastcolumn = dbitmap.columns()-1;
1633        for(int y=0,ynew=lastcolumn;ynew>=0;y++,ynew--)
1634        {
1635          const unsigned char *r=operator[] (y);
1636          for(int x=0; x<ncolumns; x++)
1637          {
1638            dbitmap[x][ynew] = r[x];
1639          }
1640        }
1641      }
1642      break;
1643    }
1644    if(grays == 2)
1645    {
1646      compress();
1647      dbitmap.compress();
1648    }
1649  }
1650  return newbitmap;
1651}
1652
1653#ifndef NDEBUG
1654void 
1655GBitmap::check_border() const
1656{int col ;
1657  if (bytes)
1658    {
1659      const unsigned char *p = (*this)[-1];
1660      for (col=-border; col<ncolumns+border; col++)
1661        if (p[col])
1662          G_THROW( ERR_MSG("GBitmap.zero_damaged") );
1663      for (int row=0; row<nrows; row++)
1664        {
1665          p = (*this)[row];
1666          for (col=-border; col<0; col++)
1667            if (p[col])
1668              G_THROW( ERR_MSG("GBitmap.left_damaged") );
1669          for (col=ncolumns; col<ncolumns+border; col++)
1670            if (p[col])
1671              G_THROW( ERR_MSG("GBitmap.right_damaged") );
1672        }
1673    }
1674}
1675#endif
1676
1677
1678#ifdef HAVE_NAMESPACES
1679}
1680# ifndef NOT_USING_DJVU_NAMESPACE
1681using namespace DJVU;
1682# endif
1683#endif
1684
Note: See TracBrowser for help on using the repository browser.