diff options
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/GBitmap.cpp')
-rw-r--r-- | kviewshell/plugins/djvu/libdjvu/GBitmap.cpp | 1658 |
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 + |