summaryrefslogtreecommitdiffstats
path: root/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/GBitmap.cpp')
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GBitmap.cpp1658
1 files changed, 1658 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp b/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp
new file mode 100644
index 00000000..696367e7
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp
@@ -0,0 +1,1658 @@
+//C- -*- C++ -*-
+//C- -------------------------------------------------------------------
+//C- DjVuLibre-3.5
+//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
+//C- Copyright (c) 2001 AT&T
+//C-
+//C- This software is subject to, and may be distributed under, the
+//C- GNU General Public License, Version 2. The license should have
+//C- accompanied the software or you may obtain a copy of the license
+//C- from the Free Software Foundation at http://www.fsf.org .
+//C-
+//C- This program is distributed in the hope that it will be useful,
+//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
+//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//C- GNU General Public License for more details.
+//C-
+//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
+//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech
+//C- Software authorized us to replace the original DjVu(r) Reference
+//C- Library notice by the following text (see doc/lizard2002.djvu):
+//C-
+//C- ------------------------------------------------------------------
+//C- | DjVu (r) Reference Library (v. 3.5)
+//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
+//C- | The DjVu Reference Library is protected by U.S. Pat. No.
+//C- | 6,058,214 and patents pending.
+//C- |
+//C- | This software is subject to, and may be distributed under, the
+//C- | GNU General Public License, Version 2. The license should have
+//C- | accompanied the software or you may obtain a copy of the license
+//C- | from the Free Software Foundation at http://www.fsf.org .
+//C- |
+//C- | The computer code originally released by LizardTech under this
+//C- | license and unmodified by other parties is deemed "the LIZARDTECH
+//C- | ORIGINAL CODE." Subject to any third party intellectual property
+//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
+//C- | non-exclusive license to make, use, sell, or otherwise dispose of
+//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
+//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
+//C- | General Public License. This grant only confers the right to
+//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
+//C- | the extent such infringement is reasonably necessary to enable
+//C- | recipient to make, have made, practice, sell, or otherwise dispose
+//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
+//C- | any greater extent that may be necessary to utilize further
+//C- | modifications or combinations.
+//C- |
+//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
+//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
+//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+//C- +------------------------------------------------------------------
+//
+// $Id: GBitmap.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GBitmap.h"
+#include "ByteStream.h"
+#include "GRect.h"
+#include "GString.h"
+#include "GThreads.h"
+#include "GException.h"
+#include <string.h>
+
+// File "$Id: GBitmap.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $"
+// - Author: Leon Bottou, 05/1997
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+// ----- constructor and destructor
+
+GBitmap::~GBitmap()
+{
+}
+
+void
+GBitmap::destroy(void)
+{
+ gbytes_data.resize(0);
+ bytes = 0;
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = 0;
+}
+
+GBitmap::GBitmap()
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+}
+
+GBitmap::GBitmap(int nrows, int ncolumns, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(nrows, ncolumns, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(ByteStream &ref, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(const GBitmap &ref)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, ref.border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(const GBitmap &ref, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+
+GBitmap::GBitmap(const GBitmap &ref, const GRect &rect, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, rect, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+
+
+
+
+
+// ----- initialization
+
+void
+GBitmap::init(int arows, int acolumns, int aborder)
+{
+ GMonitorLock lock(monitor());
+ destroy();
+ grays = 2;
+ nrows = arows;
+ ncolumns = acolumns;
+ border = aborder;
+ bytes_per_row = ncolumns + border;
+ int npixels = nrows * bytes_per_row + border;
+ gzerobuffer=zeroes(bytes_per_row + border);
+ if (npixels > 0)
+ {
+ gbytes_data.resize(npixels);
+ gbytes_data.clear();
+ bytes = bytes_data;
+ }
+}
+
+
+void
+GBitmap::init(const GBitmap &ref, int aborder)
+{
+ GMonitorLock lock(monitor());
+ if (this != &ref)
+ {
+ GMonitorLock lock(ref.monitor());
+ init(ref.nrows, ref.ncolumns, aborder);
+ grays = ref.grays;
+ unsigned char *row = bytes_data+border;
+ for (int n=0; n<nrows; n++, row+=bytes_per_row)
+ memcpy( (void*)row, (void*)ref[n], ncolumns );
+ }
+ else if (aborder > border)
+ {
+ minborder(aborder);
+ }
+}
+
+
+void
+GBitmap::init(const GBitmap &ref, const GRect &rect, int border)
+{
+ GMonitorLock lock(monitor());
+ // test bitmap physical equality
+ if (this == &ref)
+ {
+ GBitmap tmp;
+ tmp.grays = grays;
+ tmp.border = border;
+ tmp.bytes_per_row = bytes_per_row;
+ tmp.ncolumns = ncolumns;
+ tmp.nrows = nrows;
+ tmp.bytes = bytes;
+ tmp.gbytes_data.swap(gbytes_data);
+ tmp.grle.swap(grle);
+ bytes = 0 ;
+ init(tmp, rect, border);
+ }
+ else
+ {
+ GMonitorLock lock(ref.monitor());
+ // create empty bitmap
+ init(rect.height(), rect.width(), border);
+ grays = ref.grays;
+ // compute destination rectangle
+ GRect rect2(0, 0, ref.columns(), ref.rows() );
+ rect2.intersect(rect2, rect);
+ rect2.translate(-rect.xmin, -rect.ymin);
+ // copy bits
+ if (! rect2.isempty())
+ {
+ for (int y=rect2.ymin; y<rect2.ymax; y++)
+ {
+ unsigned char *dst = (*this)[y];
+ const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
+ for (int x=rect2.xmin; x<rect2.xmax; x++)
+ dst[x] = src[x];
+ }
+ }
+ }
+}
+
+
+void
+GBitmap::init(ByteStream &ref, int aborder)
+{
+ GMonitorLock lock(monitor());
+ // Get magic number
+ char magic[2];
+ magic[0] = magic[1] = 0;
+ ref.readall((void*)magic, sizeof(magic));
+ char lookahead = '\n';
+ int acolumns = read_integer(lookahead, ref);
+ int arows = read_integer(lookahead, ref);
+ init(arows, acolumns, aborder);
+ // go reading file
+ if (magic[0]=='P')
+ {
+ switch(magic[1])
+ {
+ case '1':
+ grays = 2;
+ read_pbm_text(ref);
+ return;
+ case '2':
+ grays = 1 + read_integer(lookahead, ref);
+ if (grays > 256)
+ G_THROW("Cannot read PGM with depth greater than 8 bits.");
+ read_pgm_text(ref);
+ return;
+ case '4':
+ grays = 2;
+ read_pbm_raw(ref);
+ return;
+ case '5':
+ grays = 1 + read_integer(lookahead, ref);
+ if (grays > 256)
+ grays = 256;
+ read_pgm_raw(ref);
+ return;
+ }
+ }
+ else if (magic[0]=='R')
+ {
+ switch(magic[1])
+ {
+ case '4':
+ grays = 2;
+ read_rle_raw(ref);
+ return;
+ }
+ }
+ G_THROW( ERR_MSG("GBitmap.bad_format") );
+}
+
+void
+GBitmap::donate_data(unsigned char *data, int w, int h)
+{
+ destroy();
+ grays = 2;
+ nrows = h;
+ ncolumns = w;
+ border = 0;
+ bytes_per_row = w;
+ gbytes_data.replace(data,w*h);
+ bytes = bytes_data;
+ rlelength = 0;
+}
+
+void
+GBitmap::donate_rle(unsigned char *rledata, unsigned int rledatalen, int w, int h)
+{
+ destroy();
+ grays = 2;
+ nrows = h;
+ ncolumns = w;
+ border = 0;
+ bytes_per_row = w;
+// rle = rledata;
+ grle.replace(rledata,rledatalen);
+ rlelength = rledatalen;
+}
+
+
+unsigned char *
+GBitmap::take_data(size_t &offset)
+{
+ GMonitorLock lock(monitor());
+ unsigned char *ret = bytes_data;
+ if (ret) offset = (size_t)border;
+ bytes_data=0;
+ return ret;
+}
+
+const unsigned char *
+GBitmap::get_rle(unsigned int &rle_length)
+{
+ if(!rle)
+ compress();
+ rle_length=rlelength;
+ return rle;
+}
+
+// ----- compression
+
+
+void
+GBitmap::compress()
+{
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_compress") );
+ GMonitorLock lock(monitor());
+ if (bytes)
+ {
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = encode(rle,grle);
+ if (rlelength)
+ {
+ gbytes_data.resize(0);
+ bytes = 0;
+ }
+ }
+}
+
+void
+GBitmap::uncompress()
+{
+ GMonitorLock lock(monitor());
+ if (!bytes && rle)
+ decode(rle);
+}
+
+
+
+unsigned int
+GBitmap::get_memory_usage() const
+{
+ unsigned long usage = sizeof(GBitmap);
+ if (bytes)
+ usage += nrows * bytes_per_row + border;
+ if (rle)
+ usage += rlelength;
+ return usage;
+}
+
+
+void
+GBitmap::minborder(int minimum)
+{
+ if (border < minimum)
+ {
+ GMonitorLock lock(monitor());
+ if (border < minimum)
+ {
+ if (bytes)
+ {
+ GBitmap tmp(*this, minimum);
+ bytes_per_row = tmp.bytes_per_row;
+ tmp.gbytes_data.swap(gbytes_data);
+ bytes = bytes_data;
+ tmp.bytes = 0;
+ }
+ border = minimum;
+ gzerobuffer=zeroes(border + ncolumns + border);
+ }
+ }
+}
+
+
+#define NMONITORS 8
+static GMonitor monitors[NMONITORS];
+
+void
+GBitmap::share()
+{
+ if (!monitorptr)
+ {
+ unsigned long x = (unsigned long)this;
+ monitorptr = &monitors[(x^(x>>5)) % NMONITORS];
+ }
+}
+
+
+// ----- gray levels
+
+void
+GBitmap::set_grays(int ngrays)
+{
+ if (ngrays<2 || ngrays>256)
+ G_THROW( ERR_MSG("GBitmap.bad_levels") );
+ // set gray levels
+ GMonitorLock lock(monitor());
+ grays = ngrays;
+ if (ngrays>2 && !bytes)
+ uncompress();
+}
+
+void
+GBitmap::change_grays(int ngrays)
+{
+ GMonitorLock lock(monitor());
+ // set number of grays
+ int ng = ngrays - 1;
+ int og = grays - 1;
+ set_grays(ngrays);
+ // setup conversion table
+ unsigned char conv[256];
+ for (int i=0; i<256; i++)
+ {
+ if (i > og)
+ conv[i] = ng;
+ else
+ conv[i] = (i*ng+og/2)/og;
+ }
+ // perform conversion
+ for (int row=0; row<nrows; row++)
+ {
+ unsigned char *p = (*this)[row];
+ for (int n=0; n<ncolumns; n++)
+ p[n] = conv[ p[n] ];
+ }
+}
+
+void
+GBitmap::binarize_grays(int threshold)
+{
+ GMonitorLock lock(monitor());
+ if (bytes)
+ for (int row=0; row<nrows; row++)
+ {
+ unsigned char *p = (*this)[row];
+ for(unsigned char const * const pend=p+ncolumns;p<pend;++p)
+ {
+ *p = (*p>threshold) ? 1 : 0;
+ }
+ }
+ grays = 2;
+}
+
+
+// ----- additive blitting
+
+#undef min
+#undef max
+
+static inline int
+min(int x, int y)
+{
+ return (x < y ? x : y);
+}
+
+static inline int
+max(int x, int y)
+{
+ return (x > y ? x : y);
+}
+
+void
+GBitmap::blit(const GBitmap *bm, int x, int y)
+{
+ // Check boundaries
+ if ((x >= ncolumns) ||
+ (y >= nrows) ||
+ (x + (int)bm->columns() < 0) ||
+ (y + (int)bm->rows() < 0) )
+ return;
+
+ // Perform blit
+ GMonitorLock lock1(monitor());
+ GMonitorLock lock2(bm->monitor());
+ if (bm->bytes)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from bitmap
+ const unsigned char *srow = bm->bytes + bm->border;
+ unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
+ for (int sr = 0; sr < bm->nrows; sr++)
+ {
+ if (sr+y>=0 && sr+y<nrows)
+ {
+ int sc = max(0, -x);
+ int sc1 = min(bm->ncolumns, ncolumns-x);
+ while (sc < sc1)
+ {
+ drow[sc] += srow[sc];
+ sc += 1;
+ }
+ }
+ srow += bm->bytes_per_row;
+ drow += bytes_per_row;
+ }
+ }
+ else if (bm->rle)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from rle
+ const unsigned char *runs = bm->rle;
+ unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
+ int sr = bm->nrows - 1;
+ drow += sr * bytes_per_row;
+ int sc = 0;
+ char p = 0;
+ while (sr >= 0)
+ {
+ const int z = read_run(runs);
+ if (sc+z > bm->ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ int nc = sc + z;
+ if (p && sr+y>=0 && sr+y<nrows)
+ {
+ if (sc + x < 0)
+ sc = min(-x, nc);
+ while (sc < nc && sc + x<ncolumns)
+ drow[sc++] += 1;
+ }
+ sc = nc;
+ p = 1 - p;
+ if (sc >= bm->ncolumns)
+ {
+ p = 0;
+ sc = 0;
+ drow -= bytes_per_row;
+ sr -= 1;
+ }
+ }
+ }
+}
+
+
+
+void
+GBitmap::blit(const GBitmap *bm, int xh, int yh, int subsample)
+{
+ // Use code when no subsampling is necessary
+ if (subsample == 1)
+ {
+ blit(bm, xh, yh);
+ return;
+ }
+
+ // Check boundaries
+ if ((xh >= ncolumns * subsample) ||
+ (yh >= nrows * subsample) ||
+ (xh + (int)bm->columns() < 0) ||
+ (yh + (int)bm->rows() < 0) )
+ return;
+
+ // Perform subsampling blit
+ GMonitorLock lock1(monitor());
+ GMonitorLock lock2(bm->monitor());
+ if (bm->bytes)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from bitmap
+ int dr, dr1, zdc, zdc1;
+ euclidian_ratio(yh, subsample, dr, dr1);
+ euclidian_ratio(xh, subsample, zdc, zdc1);
+ const unsigned char *srow = bm->bytes + bm->border;
+ unsigned char *drow = bytes_data + border + dr*bytes_per_row;
+ for (int sr = 0; sr < bm->nrows; sr++)
+ {
+ if (dr>=0 && dr<nrows)
+ {
+ int dc = zdc;
+ int dc1 = zdc1;
+ for (int sc=0; sc < bm->ncolumns; sc++)
+ {
+ if (dc>=0 && dc<ncolumns)
+ drow[dc] += srow[sc];
+ if (++dc1 >= subsample)
+ {
+ dc1 = 0;
+ dc += 1;
+ }
+ }
+ }
+ // next line in source
+ srow += bm->bytes_per_row;
+ // next line fraction in destination
+ if (++dr1 >= subsample)
+ {
+ dr1 = 0;
+ dr += 1;
+ drow += bytes_per_row;
+ }
+ }
+ }
+ else if (bm->rle)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from rle
+ int dr, dr1, zdc, zdc1;
+ euclidian_ratio(yh+bm->nrows-1, subsample, dr, dr1);
+ euclidian_ratio(xh, subsample, zdc, zdc1);
+ const unsigned char *runs = bm->rle;
+ unsigned char *drow = bytes_data + border + dr*bytes_per_row;
+ int sr = bm->nrows -1;
+ int sc = 0;
+ char p = 0;
+ int dc = zdc;
+ int dc1 = zdc1;
+ while (sr >= 0)
+ {
+ int z = read_run(runs);
+ if (sc+z > bm->ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ int nc = sc + z;
+
+ if (dr>=0 && dr<nrows)
+ while (z>0 && dc<ncolumns)
+ {
+ int zd = subsample - dc1;
+ if (zd > z)
+ zd = z;
+ if (p && dc>=0)
+ drow[dc] += zd;
+ z -= zd;
+ dc1 += zd;
+ if (dc1 >= subsample)
+ {
+ dc1 = 0;
+ dc += 1;
+ }
+ }
+ // next fractional row
+ sc = nc;
+ p = 1 - p;
+ if (sc >= bm->ncolumns)
+ {
+ sc = 0;
+ dc = zdc;
+ dc1 = zdc1;
+ p = 0;
+ sr -= 1;
+ if (--dr1 < 0)
+ {
+ dr1 = subsample - 1;
+ dr -= 1;
+ drow -= bytes_per_row;
+ }
+ }
+ }
+ }
+}
+
+
+
+// ------ load bitmaps
+
+
+unsigned int
+GBitmap::read_integer(char &c, ByteStream &bs)
+{
+ unsigned int x = 0;
+ // eat blank before integer
+ while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#')
+ {
+ if (c=='#')
+ do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
+ c = 0;
+ bs.read(&c, 1);
+ }
+ // check integer
+ if (c<'0' || c>'9')
+ G_THROW( ERR_MSG("GBitmap.not_int") );
+ // eat integer
+ while (c>='0' && c<='9')
+ {
+ x = x*10 + c - '0';
+ c = 0;
+ bs.read(&c, 1);
+ }
+ return x;
+}
+
+
+void
+GBitmap::read_pbm_text(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ {
+ char bit = 0;
+ bs.read(&bit,1);
+ while (bit==' ' || bit=='\t' || bit=='\r' || bit=='\n')
+ {
+ bit=0;
+ bs.read(&bit,1);
+ }
+ if (bit=='1')
+ row[c] = 1;
+ else if (bit=='0')
+ row[c] = 0;
+ else
+ G_THROW( ERR_MSG("GBitmap.bad_PBM") );
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pgm_text(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ char lookahead = '\n';
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ row[c] = grays - 1 - read_integer(lookahead, bs);
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pbm_raw(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ unsigned char acc = 0;
+ unsigned char mask = 0;
+ for (int c = 0; c<ncolumns; c++)
+ {
+ if (!mask)
+ {
+ bs.read(&acc, 1);
+ mask = (unsigned char)0x80;
+ }
+ if (acc & mask)
+ row[c] = 1;
+ else
+ row[c] = 0;
+ mask >>= 1;
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pgm_raw(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ {
+ unsigned char x;
+ bs.read((void*)&x, 1);
+ row[c] = grays - 1 - x;
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_rle_raw(ByteStream &bs)
+{
+ // interpret runs data
+ unsigned char h;
+ unsigned char p = 0;
+ unsigned char *row = bytes_data + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ int c = 0;
+ while (n >= 0)
+ {
+ bs.read(&h, 1);
+ int x = h;
+ if (x >= (int)RUNOVERFLOWVALUE)
+ {
+ bs.read(&h, 1);
+ x = h + ((x - (int)RUNOVERFLOWVALUE) << 8);
+ }
+ if (c+x > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ while (x-- > 0)
+ row[c++] = p;
+ p = 1 - p;
+ if (c >= ncolumns)
+ {
+ c = 0;
+ p = 0;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+}
+
+
+// ------ save bitmaps
+
+void
+GBitmap::save_pbm(ByteStream &bs, int raw)
+{
+ // check arguments
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
+ GMonitorLock lock(monitor());
+ // header
+ {
+ GUTF8String head;
+ head.format("P%c\n%d %d\n", (raw ? '4' : '1'), ncolumns, nrows);
+ bs.writall((void*)(const char *)head, head.length());
+ }
+ // body
+ if(raw)
+ {
+ if(!rle)
+ compress();
+ const unsigned char *runs=rle;
+ const unsigned char * const runs_end=rle+rlelength;
+ const int count=(ncolumns+7)>>3;
+ unsigned char *buf;
+ GPBuffer<unsigned char> gbuf(buf,count);
+ while(runs<runs_end)
+ {
+ rle_get_bitmap(ncolumns,runs,buf,false);
+ bs.writall(buf,count);
+ }
+ }else
+ {
+ if (!bytes)
+ uncompress();
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ unsigned char eol='\n';
+ for (int c=0; c<ncolumns;)
+ {
+ unsigned char bit= (row[c] ? '1' : '0');
+ bs.write((void*)&bit, 1);
+ c += 1;
+ if (c==ncolumns || (c&(int)RUNMSBMASK)==0)
+ bs.write((void*)&eol, 1);
+ }
+ // next row
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+}
+
+void
+GBitmap::save_pgm(ByteStream &bs, int raw)
+{
+ // checks
+ GMonitorLock lock(monitor());
+ if (!bytes)
+ uncompress();
+ // header
+ GUTF8String head;
+ head.format("P%c\n%d %d\n%d\n", (raw ? '5' : '2'), ncolumns, nrows, grays-1);
+ bs.writall((void*)(const char *)head, head.length());
+ // body
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ if (raw)
+ {
+ for (int c=0; c<ncolumns; c++)
+ {
+ char x = grays - 1 - row[c];
+ bs.write((void*)&x, 1);
+ }
+ }
+ else
+ {
+ unsigned char eol='\n';
+ for (int c=0; c<ncolumns; )
+ {
+ head.format("%d ", grays - 1 - row[c]);
+ bs.writall((void*)(const char *)head, head.length());
+ c += 1;
+ if (c==ncolumns || (c&0x1f)==0)
+ bs.write((void*)&eol, 1);
+ }
+ }
+ row -= bytes_per_row;
+ n -= 1;
+ }
+}
+
+void
+GBitmap::save_rle(ByteStream &bs)
+{
+ // checks
+ if (ncolumns==0 || nrows==0)
+ G_THROW( ERR_MSG("GBitmap.not_init") );
+ GMonitorLock lock(monitor());
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
+ // header
+ GUTF8String head;
+ head.format("R4\n%d %d\n", ncolumns, nrows);
+ bs.writall((void*)(const char *)head, head.length());
+ // body
+ if (rle)
+ {
+ bs.writall((void*)rle, rlelength);
+ }
+ else
+ {
+ unsigned char *runs = 0;
+ GPBuffer<unsigned char> gruns(runs);
+ int size = encode(runs,gruns);
+ bs.writall((void*)runs, size);
+ }
+}
+
+
+// ------ runs
+
+
+void
+GBitmap::makerows(
+ int nrows, const int ncolumns, unsigned char *runs, unsigned char *rlerows[])
+{
+ while (nrows-- > 0)
+ {
+ rlerows[nrows] = runs;
+ int c;
+ for(c=0;c<ncolumns;c+=GBitmap::read_run(runs))
+ EMPTY_LOOP;
+ if (c > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync2") );
+ }
+}
+
+
+void
+GBitmap::rle_get_bitmap (
+ const int ncolumns,
+ const unsigned char *&runs,
+ unsigned char *bitmap,
+ const bool invert )
+{
+ const int obyte_def=invert?0xff:0;
+ const int obyte_ndef=invert?0:0xff;
+ int mask=0x80,obyte=0;
+ for(int c=ncolumns;c > 0 ;)
+ {
+ int x=read_run(runs);
+ c-=x;
+ while((x--)>0)
+ {
+ if(!(mask>>=1))
+ {
+ *(bitmap++) = obyte^obyte_def;
+ obyte=0;
+ mask=0x80;
+ for(;x>=8;x-=8)
+ {
+ *(bitmap++)=obyte_def;
+ }
+ }
+ }
+ if(c>0)
+ {
+ int x=read_run(runs);
+ c-=x;
+ while((x--)>0)
+ {
+ obyte|=mask;
+ if(!(mask>>=1))
+ {
+ *(bitmap++)=obyte^obyte_def;
+ obyte=0;
+ mask=0x80;
+ for(;(x>8);x-=8)
+ *(bitmap++)=obyte_ndef;
+ }
+ }
+ }
+ }
+ if(mask != 0x80)
+ {
+ *(bitmap++)=obyte^obyte_def;
+ }
+}
+
+int
+GBitmap::rle_get_bits(int rowno, unsigned char *bits) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ if (rowno<0 || rowno>=nrows)
+ return 0;
+ if (!rlerows)
+ {
+ const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
+ makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
+ }
+ int n = 0;
+ int p = 0;
+ int c = 0;
+ unsigned char *runs = rlerows[rowno];
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if ((c+=x)>ncolumns)
+ c = ncolumns;
+ while (n<c)
+ bits[n++] = p;
+ p = 1-p;
+ }
+ return n;
+}
+
+
+int
+GBitmap::rle_get_runs(int rowno, int *rlens) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ if (rowno<0 || rowno>=nrows)
+ return 0;
+ if (!rlerows)
+ {
+ const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
+ makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
+ }
+ int n = 0;
+ int d = 0;
+ int c = 0;
+ unsigned char *runs = rlerows[rowno];
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if (n>0 && !x)
+ {
+ n--;
+ d = d-rlens[n];
+ }
+ else
+ {
+ rlens[n++] = (c+=x)-d;
+ d = c;
+ }
+ }
+ return n;
+}
+
+
+int
+GBitmap::rle_get_rect(GRect &rect) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ int area = 0;
+ unsigned char *runs = rle;
+ rect.xmin = ncolumns;
+ rect.ymin = nrows;
+ rect.xmax = 0;
+ rect.ymax = 0;
+ int r = nrows;
+ while (--r >= 0)
+ {
+ int p = 0;
+ int c = 0;
+ int n = 0;
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if(x)
+ {
+ if (p)
+ {
+ if (c < rect.xmin)
+ rect.xmin = c;
+ if ((c += x) > rect.xmax)
+ rect.xmax = c-1;
+ n += x;
+ }
+ else
+ {
+ c += x;
+ }
+ }
+ p = 1-p;
+ }
+ area += n;
+ if (n)
+ {
+ rect.ymin = r;
+ if (r > rect.ymax)
+ rect.ymax = r;
+ }
+ }
+ if (area==0)
+ rect.clear();
+ return area;
+}
+
+
+
+// ------ helpers
+
+int
+GBitmap::encode(unsigned char *&pruns,GPBuffer<unsigned char> &gpruns) const
+{
+ // uncompress rle information
+ if (nrows==0 || ncolumns==0)
+ {
+ gpruns.resize(0);
+ return 0;
+ }
+ if (!bytes)
+ {
+ unsigned char *runs;
+ GPBuffer<unsigned char> gruns(runs,rlelength);
+ memcpy((void*)runs, rle, rlelength);
+ gruns.swap(gpruns);
+ return rlelength;
+ }
+ gpruns.resize(0);
+ // create run array
+ int pos = 0;
+ int maxpos = 1024 + ncolumns + ncolumns;
+ unsigned char *runs;
+ GPBuffer<unsigned char> gruns(runs,maxpos);
+ // encode bitmap as rle
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ if (maxpos < pos+ncolumns+ncolumns+2)
+ {
+ maxpos += 1024 + ncolumns + ncolumns;
+ gruns.resize(maxpos);
+ }
+
+ unsigned char *runs_pos=runs+pos;
+ const unsigned char * const runs_pos_start=runs_pos;
+ append_line(runs_pos,row,ncolumns);
+ pos+=(size_t)runs_pos-(size_t)runs_pos_start;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ // return result
+ gruns.resize(pos);
+ gpruns.swap(gruns);
+ return pos;
+}
+
+void
+GBitmap::decode(unsigned char *runs)
+{
+ // initialize pixel array
+ if (nrows==0 || ncolumns==0)
+ G_THROW( ERR_MSG("GBitmap.not_init") );
+ bytes_per_row = ncolumns + border;
+ if (runs==0)
+ G_THROW( ERR_MSG("GBitmap.null_arg") );
+ int npixels = nrows * bytes_per_row + border;
+ if (!bytes_data)
+ {
+ gbytes_data.resize(npixels);
+ bytes = bytes_data;
+ }
+ gbytes_data.clear();
+ gzerobuffer=zeroes(bytes_per_row + border);
+ // interpret runs data
+ int c, n;
+ unsigned char p = 0;
+ unsigned char *row = bytes_data + border;
+ n = nrows - 1;
+ row += n * bytes_per_row;
+ c = 0;
+ while (n >= 0)
+ {
+ int x = read_run(runs);
+ if (c+x > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync2") );
+ while (x-- > 0)
+ row[c++] = p;
+ p = 1 - p;
+ if (c >= ncolumns)
+ {
+ c = 0;
+ p = 0;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+ // Free rle data possibly attached to this bitmap
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = 0;
+#ifndef NDEBUG
+ check_border();
+#endif
+}
+
+class GBitmap::ZeroBuffer : public GPEnabled
+{
+public:
+ ZeroBuffer(const unsigned int zerosize);
+ unsigned char *zerobuffer;
+ GPBuffer<unsigned char> gzerobuffer;
+};
+
+GBitmap::ZeroBuffer::ZeroBuffer(const unsigned int zerosize)
+: gzerobuffer(zerobuffer,zerosize)
+{
+ gzerobuffer.clear();
+ GBitmap::zerobuffer=zerobuffer;
+ GBitmap::zerosize=zerosize;
+}
+
+static const unsigned char static_zerobuffer[]=
+{0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+ 0,0,0,0,0,0,0,0,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
+
+int GBitmap::zerosize = sizeof(static_zerobuffer);
+unsigned char *GBitmap::zerobuffer=const_cast<unsigned char *>(static_zerobuffer);
+
+GP<GBitmap::ZeroBuffer>
+GBitmap::zeroes(int required)
+{
+ GMonitorLock lock(&monitors[0]); // any monitor would do
+ static GP<GBitmap::ZeroBuffer> gzerobuffer;
+ if (zerosize < required)
+ {
+ int z;
+ for(z=zerosize;z<required;z <<= 1)
+ EMPTY_LOOP;
+ z=(z+0xfff)&(~0xfff);
+ gzerobuffer=new GBitmap::ZeroBuffer((unsigned int)z);
+ }
+ return gzerobuffer;
+}
+
+
+// Fills a bitmap with the given value
+void
+GBitmap::fill(unsigned char value)
+{
+ GMonitorLock lock(monitor());
+ for(unsigned int y=0; y<rows(); y++)
+ {
+ unsigned char* bm_y = (*this)[y];
+ for(unsigned int x=0; x<columns(); x++)
+ bm_y[x] = value;
+ }
+}
+
+
+void
+GBitmap::append_long_run(unsigned char *&data, int count)
+{
+ while (count > MAXRUNSIZE)
+ {
+ data[0] = data[1] = 0xff;
+ data[2] = 0;
+ data += 3;
+ count -= MAXRUNSIZE;
+ }
+ if (count < RUNOVERFLOWVALUE)
+ {
+ data[0] = count;
+ data += 1;
+ }
+ else
+ {
+ data[0] = (count>>8) + GBitmap::RUNOVERFLOWVALUE;
+ data[1] = (count & 0xff);
+ data += 2;
+ }
+}
+
+
+void
+GBitmap::append_line(unsigned char *&data,const unsigned char *row,
+ const int rowlen,bool invert)
+{
+ const unsigned char *rowend=row+rowlen;
+ bool p=!invert;
+ while(row<rowend)
+ {
+ int count=0;
+ if ((p=!p))
+ {
+ if(*row)
+ for(++count,++row;(row<rowend)&&*row;++count,++row)
+ EMPTY_LOOP;
+ }
+ else if(!*row)
+ {
+ for(++count,++row;(row<rowend)&&!*row;++count,++row)
+ EMPTY_LOOP;
+ }
+ append_run(data,count);
+ }
+}
+
+#if 0
+static inline int
+GetRowTDLRNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ stopptr=(startptr=bit[row])+bit.columns();
+ return 1;
+}
+
+static inline int
+GetRowTDLRNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ stopptr=(startptr=bit[row])+bit.columns();
+ return 1;
+}
+
+static inline int
+GetRowTDRLNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ startptr=(stopptr=bit[row]-1)+bit.columns();
+ return -1;
+}
+#endif // 0
+
+GP<GBitmap>
+GBitmap::rotate(int count)
+{
+ GP<GBitmap> newbitmap=this;
+ if((count%=4))
+ {
+ if( count & 0x01 )
+ {
+ newbitmap = new GBitmap(ncolumns, nrows);
+ }else
+ {
+ newbitmap = new GBitmap(nrows, ncolumns);
+ }
+ GMonitorLock lock(monitor());
+ if (!bytes_data)
+ uncompress();
+ GBitmap &dbitmap = *newbitmap;
+ dbitmap.set_grays(grays);
+ switch(count)
+ {
+ case 1: // rotate 90 counter clockwise
+ {
+ const int lastrow = dbitmap.rows()-1;
+ for(int y=0; y<nrows; y++)
+ {
+ const unsigned char *r=operator[] (y);
+ for(int x=0,xnew=lastrow;xnew>=0; x++,xnew--)
+ {
+ dbitmap[xnew][y] = r[x];
+ }
+ }
+ }
+ break;
+ case 2: // rotate 180 counter clockwise
+ {
+ const int lastrow = dbitmap.rows()-1;
+ const int lastcolumn = dbitmap.columns()-1;
+ for(int y=0,ynew=lastrow;ynew>=0; y++,ynew--)
+ {
+ const unsigned char *r=operator[] (y);
+ unsigned char *d=dbitmap[ynew];
+ for(int xnew=lastcolumn;xnew>=0; r++,--xnew)
+ {
+ d[xnew] = *r;
+ }
+ }
+ }
+ break;
+ case 3: // rotate 270 counter clockwise
+ {
+ const int lastcolumn = dbitmap.columns()-1;
+ for(int y=0,ynew=lastcolumn;ynew>=0;y++,ynew--)
+ {
+ const unsigned char *r=operator[] (y);
+ for(int x=0; x<ncolumns; x++)
+ {
+ dbitmap[x][ynew] = r[x];
+ }
+ }
+ }
+ break;
+ }
+ if(grays == 2)
+ {
+ compress();
+ dbitmap.compress();
+ }
+ }
+ return newbitmap;
+}
+
+#ifndef NDEBUG
+void
+GBitmap::check_border() const
+{int col ;
+ if (bytes)
+ {
+ const unsigned char *p = (*this)[-1];
+ for (col=-border; col<ncolumns+border; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.zero_damaged") );
+ for (int row=0; row<nrows; row++)
+ {
+ p = (*this)[row];
+ for (col=-border; col<0; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.left_damaged") );
+ for (col=ncolumns; col<ncolumns+border; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.right_damaged") );
+ }
+ }
+}
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+