|
|
|
//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
|
|
|
|
|