source: trunk/libdjvu/GBitmap.cpp @ 199

Last change on this file since 199 was 17, checked in by Eugene Romanenko, 16 years ago

update makefiles, remove absolute paths, update djvulibre to version 3.5.17

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