|
Packit |
df99a1 |
//C- -*- C++ -*-
|
|
Packit |
df99a1 |
//C- -------------------------------------------------------------------
|
|
Packit |
df99a1 |
//C- DjVuLibre-3.5
|
|
Packit |
df99a1 |
//C- Copyright (c) 2002 Leon Bottou and Yann Le Cun.
|
|
Packit |
df99a1 |
//C- Copyright (c) 2001 AT&T
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
//C- GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
//C- or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
//C- accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
//C- from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- This program is distributed in the hope that it will be useful,
|
|
Packit |
df99a1 |
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
df99a1 |
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
df99a1 |
//C- GNU General Public License for more details.
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
|
|
Packit |
df99a1 |
//C- Lizardtech Software. Lizardtech Software has authorized us to
|
|
Packit |
df99a1 |
//C- replace the original DjVu(r) Reference Library notice by the following
|
|
Packit |
df99a1 |
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
|
|
Packit |
df99a1 |
//C-
|
|
Packit |
df99a1 |
//C- ------------------------------------------------------------------
|
|
Packit |
df99a1 |
//C- | DjVu (r) Reference Library (v. 3.5)
|
|
Packit |
df99a1 |
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
|
|
Packit |
df99a1 |
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
|
|
Packit |
df99a1 |
//C- | 6,058,214 and patents pending.
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | This software is subject to, and may be distributed under, the
|
|
Packit |
df99a1 |
//C- | GNU General Public License, either Version 2 of the license,
|
|
Packit |
df99a1 |
//C- | or (at your option) any later version. The license should have
|
|
Packit |
df99a1 |
//C- | accompanied the software or you may obtain a copy of the license
|
|
Packit |
df99a1 |
//C- | from the Free Software Foundation at http://www.fsf.org .
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | The computer code originally released by LizardTech under this
|
|
Packit |
df99a1 |
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
|
|
Packit |
df99a1 |
//C- | ORIGINAL CODE." Subject to any third party intellectual property
|
|
Packit |
df99a1 |
//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
|
|
Packit |
df99a1 |
//C- | non-exclusive license to make, use, sell, or otherwise dispose of
|
|
Packit |
df99a1 |
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
|
|
Packit |
df99a1 |
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
|
|
Packit |
df99a1 |
//C- | General Public License. This grant only confers the right to
|
|
Packit |
df99a1 |
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
|
|
Packit |
df99a1 |
//C- | the extent such infringement is reasonably necessary to enable
|
|
Packit |
df99a1 |
//C- | recipient to make, have made, practice, sell, or otherwise dispose
|
|
Packit |
df99a1 |
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
|
|
Packit |
df99a1 |
//C- | any greater extent that may be necessary to utilize further
|
|
Packit |
df99a1 |
//C- | modifications or combinations.
|
|
Packit |
df99a1 |
//C- |
|
|
Packit |
df99a1 |
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
|
|
Packit |
df99a1 |
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
|
Packit |
df99a1 |
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
|
|
Packit |
df99a1 |
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
df99a1 |
//C- +------------------------------------------------------------------
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
df99a1 |
# include "config.h"
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#if NEED_GNUG_PRAGMAS
|
|
Packit |
df99a1 |
# pragma implementation
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
// Rescale images with fast bilinear interpolation
|
|
Packit |
df99a1 |
// From: Leon Bottou, 1/31/2002
|
|
Packit |
df99a1 |
// Almost equal to my initial code.
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#include "GScaler.h"
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_NAMESPACES
|
|
Packit |
df99a1 |
namespace DJVU {
|
|
Packit |
df99a1 |
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// CONSTANTS
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#define FRACBITS 4
|
|
Packit |
df99a1 |
#define FRACSIZE (1<
|
|
Packit |
df99a1 |
#define FRACSIZE2 (FRACSIZE>>1)
|
|
Packit |
df99a1 |
#define FRACMASK (FRACSIZE-1)
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// UTILITIES
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static int interp_ok = 0;
|
|
Packit |
df99a1 |
static short interp[FRACSIZE][512];
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
prepare_interp()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! interp_ok)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
interp_ok = 1;
|
|
Packit |
df99a1 |
for (int i=0; i
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
short *deltas = & interp[i][256];
|
|
Packit |
df99a1 |
for (int j = -255; j <= 255; j++)
|
|
Packit |
df99a1 |
deltas[j] = ( j*i + FRACSIZE2 ) >> FRACBITS;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline int
|
|
Packit |
df99a1 |
mini(int x, int y)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return (x < y ? x : y);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static inline int
|
|
Packit |
df99a1 |
maxi(int x, int y)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
return (x > y ? x : y);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// GSCALER
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GScaler::GScaler()
|
|
Packit |
df99a1 |
: inw(0), inh(0),
|
|
Packit |
df99a1 |
xshift(0), yshift(0), redw(0), redh(0),
|
|
Packit |
df99a1 |
outw(0), outh(0),
|
|
Packit |
df99a1 |
gvcoord(vcoord,0), ghcoord(hcoord,0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GScaler::~GScaler()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::set_input_size(int w, int h)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
inw = w;
|
|
Packit |
df99a1 |
inh = h;
|
|
Packit |
df99a1 |
if (vcoord)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gvcoord.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (hcoord)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ghcoord.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::set_output_size(int w, int h)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
outw = w;
|
|
Packit |
df99a1 |
outh = h;
|
|
Packit |
df99a1 |
if (vcoord)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gvcoord.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (hcoord)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
ghcoord.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
static void
|
|
Packit |
df99a1 |
prepare_coord(int *coord, int inmax, int outmax, int in, int out)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int len = (in*FRACSIZE);
|
|
Packit |
df99a1 |
int beg = (len+out)/(2*out) - FRACSIZE2;
|
|
Packit |
df99a1 |
// Bresenham algorithm
|
|
Packit |
df99a1 |
int y = beg;
|
|
Packit |
df99a1 |
int z = out/2;
|
|
Packit |
df99a1 |
int inmaxlim = (inmax-1)*FRACSIZE;
|
|
Packit |
df99a1 |
for (int x=0; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
coord[x] = mini(y,inmaxlim);
|
|
Packit |
df99a1 |
z = z + len;
|
|
Packit |
df99a1 |
y = y + z / out;
|
|
Packit |
df99a1 |
z = z % out;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Result must fit exactly
|
|
Packit |
df99a1 |
if (out==outmax && y!=beg+len)
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.assertion") );
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::set_horz_ratio(int numer, int denom)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! (inw>0 && inh>0 && outw>0 && outh>0))
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.undef_size") );
|
|
Packit |
df99a1 |
// Implicit ratio (determined by the input/output sizes)
|
|
Packit |
df99a1 |
if (numer==0 && denom==0) {
|
|
Packit |
df99a1 |
numer = outw;
|
|
Packit |
df99a1 |
denom = inw;
|
|
Packit |
df99a1 |
} else if (numer<=0 || denom<=0)
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.ratios") );
|
|
Packit |
df99a1 |
// Compute horz reduction
|
|
Packit |
df99a1 |
xshift = 0;
|
|
Packit |
df99a1 |
redw = inw;
|
|
Packit |
df99a1 |
while (numer+numer < denom) {
|
|
Packit |
df99a1 |
xshift += 1;
|
|
Packit |
df99a1 |
redw = (redw + 1) >> 1;
|
|
Packit |
df99a1 |
numer = numer << 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Compute coordinate table
|
|
Packit |
df99a1 |
if (! hcoord)
|
|
Packit |
df99a1 |
ghcoord.resize(outw);
|
|
Packit |
df99a1 |
prepare_coord(hcoord, redw, outw, denom, numer);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::set_vert_ratio(int numer, int denom)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (! (inw>0 && inh>0 && outw>0 && outh>0))
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.undef_size") );
|
|
Packit |
df99a1 |
// Implicit ratio (determined by the input/output sizes)
|
|
Packit |
df99a1 |
if (numer==0 && denom==0) {
|
|
Packit |
df99a1 |
numer = outh;
|
|
Packit |
df99a1 |
denom = inh;
|
|
Packit |
df99a1 |
} else if (numer<=0 || denom<=0)
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.ratios") );
|
|
Packit |
df99a1 |
// Compute horz reduction
|
|
Packit |
df99a1 |
yshift = 0;
|
|
Packit |
df99a1 |
redh = inh;
|
|
Packit |
df99a1 |
while (numer+numer < denom) {
|
|
Packit |
df99a1 |
yshift += 1;
|
|
Packit |
df99a1 |
redh = (redh + 1) >> 1;
|
|
Packit |
df99a1 |
numer = numer << 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Compute coordinate table
|
|
Packit |
df99a1 |
if (! vcoord)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gvcoord.resize(outh);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
prepare_coord(vcoord, redh, outh, denom, numer);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::make_rectangles(const GRect &desired, GRect &red, GRect &inp)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Parameter validation
|
|
Packit |
df99a1 |
if (desired.xmin<0 || desired.ymin<0 ||
|
|
Packit |
df99a1 |
desired.xmax>outw || desired.ymax>outh )
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.too_big") );
|
|
Packit |
df99a1 |
// Compute ratio (if not done yet)
|
|
Packit |
df99a1 |
if (!vcoord)
|
|
Packit |
df99a1 |
set_vert_ratio(0,0);
|
|
Packit |
df99a1 |
if (!hcoord)
|
|
Packit |
df99a1 |
set_horz_ratio(0,0);
|
|
Packit |
df99a1 |
// Compute reduced bounds
|
|
Packit |
df99a1 |
red.xmin = (hcoord[desired.xmin]) >> FRACBITS;
|
|
Packit |
df99a1 |
red.ymin = (vcoord[desired.ymin]) >> FRACBITS;
|
|
Packit |
df99a1 |
red.xmax = (hcoord[desired.xmax-1]+FRACSIZE-1) >> FRACBITS;
|
|
Packit |
df99a1 |
red.ymax = (vcoord[desired.ymax-1]+FRACSIZE-1) >> FRACBITS;
|
|
Packit |
df99a1 |
// Borders
|
|
Packit |
df99a1 |
red.xmin = maxi(red.xmin, 0);
|
|
Packit |
df99a1 |
red.xmax = mini(red.xmax+1, redw);
|
|
Packit |
df99a1 |
red.ymin = maxi(red.ymin, 0);
|
|
Packit |
df99a1 |
red.ymax = mini(red.ymax+1, redh);
|
|
Packit |
df99a1 |
// Input
|
|
Packit |
df99a1 |
inp.xmin = maxi(red.xmin<
|
|
Packit |
df99a1 |
inp.xmax = mini(red.xmax<
|
|
Packit |
df99a1 |
inp.ymin = maxi(red.ymin<
|
|
Packit |
df99a1 |
inp.ymax = mini(red.ymax<
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GScaler::get_input_rect( const GRect &desired_output, GRect &required_input )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
GRect red;
|
|
Packit |
df99a1 |
make_rectangles(desired_output, red, required_input);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// GBITMAPSCALER
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GBitmapScaler::GBitmapScaler()
|
|
Packit |
df99a1 |
: glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GBitmapScaler::GBitmapScaler(int inw, int inh, int outw, int outh)
|
|
Packit |
df99a1 |
: glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
set_input_size(inw, inh);
|
|
Packit |
df99a1 |
set_output_size(outw, outh);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GBitmapScaler::~GBitmapScaler()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
unsigned char *
|
|
Packit |
df99a1 |
GBitmapScaler::get_line(int fy,
|
|
Packit |
df99a1 |
const GRect &required_red,
|
|
Packit |
df99a1 |
const GRect &provided_input,
|
|
Packit |
df99a1 |
const GBitmap &input )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (fy < required_red.ymin)
|
|
Packit |
df99a1 |
fy = required_red.ymin;
|
|
Packit |
df99a1 |
else if (fy >= required_red.ymax)
|
|
Packit |
df99a1 |
fy = required_red.ymax - 1;
|
|
Packit |
df99a1 |
// Cached line
|
|
Packit |
df99a1 |
if (fy == l2)
|
|
Packit |
df99a1 |
return p2;
|
|
Packit |
df99a1 |
if (fy == l1)
|
|
Packit |
df99a1 |
return p1;
|
|
Packit |
df99a1 |
// Shift
|
|
Packit |
df99a1 |
unsigned char *p = p1;
|
|
Packit |
df99a1 |
p1 = p2;
|
|
Packit |
df99a1 |
l1 = l2;
|
|
Packit |
df99a1 |
p2 = p;
|
|
Packit |
df99a1 |
l2 = fy;
|
|
Packit |
df99a1 |
if (xshift==0 && yshift==0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Fast mode
|
|
Packit |
df99a1 |
int dx = required_red.xmin-provided_input.xmin;
|
|
Packit |
df99a1 |
int dx1 = required_red.xmax-provided_input.xmin;
|
|
Packit |
df99a1 |
const unsigned char *inp1 = input[fy-provided_input.ymin] + dx;
|
|
Packit |
df99a1 |
while (dx++ < dx1)
|
|
Packit |
df99a1 |
*p++ = conv[*inp1++];
|
|
Packit |
df99a1 |
return p2;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Compute location of line
|
|
Packit |
df99a1 |
GRect line;
|
|
Packit |
df99a1 |
line.xmin = required_red.xmin << xshift;
|
|
Packit |
df99a1 |
line.xmax = required_red.xmax << xshift;
|
|
Packit |
df99a1 |
line.ymin = fy << yshift;
|
|
Packit |
df99a1 |
line.ymax = (fy+1) << yshift;
|
|
Packit |
df99a1 |
line.intersect(line, provided_input);
|
|
Packit |
df99a1 |
line.translate(-provided_input.xmin, -provided_input.ymin);
|
|
Packit |
df99a1 |
// Prepare variables
|
|
Packit |
df99a1 |
const unsigned char *botline = input[line.ymin];
|
|
Packit |
df99a1 |
int rowsize = input.rowsize();
|
|
Packit |
df99a1 |
int sw = 1<
|
|
Packit |
df99a1 |
int div = xshift+yshift;
|
|
Packit |
df99a1 |
int rnd = 1<<(div-1);
|
|
Packit |
df99a1 |
// Compute averages
|
|
Packit |
df99a1 |
for (int x=line.xmin; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int g=0, s=0;
|
|
Packit |
df99a1 |
const unsigned char *inp0 = botline + x;
|
|
Packit |
df99a1 |
int sy1 = mini(line.height(), (1<
|
|
Packit |
df99a1 |
for (int sy=0; sy
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const unsigned char *inp1;
|
|
Packit |
df99a1 |
const unsigned char *inp2 = inp0 + mini(x+sw, line.xmax) - x;
|
|
Packit |
df99a1 |
for (inp1=inp0; inp1
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
g += conv[*inp1];
|
|
Packit |
df99a1 |
s += 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (s == rnd+rnd)
|
|
Packit |
df99a1 |
*p = (g+rnd)>>div;
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
*p = (g+s/2)/s;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Return
|
|
Packit |
df99a1 |
return p2;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GBitmapScaler::scale( const GRect &provided_input, const GBitmap &input,
|
|
Packit |
df99a1 |
const GRect &desired_output, GBitmap &output )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Compute rectangles
|
|
Packit |
df99a1 |
GRect required_input;
|
|
Packit |
df99a1 |
GRect required_red;
|
|
Packit |
df99a1 |
make_rectangles(desired_output, required_red, required_input);
|
|
Packit |
df99a1 |
// Parameter validation
|
|
Packit |
df99a1 |
if (provided_input.width() != (int)input.columns() ||
|
|
Packit |
df99a1 |
provided_input.height() != (int)input.rows() )
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.no_match") );
|
|
Packit |
df99a1 |
if (provided_input.xmin > required_input.xmin ||
|
|
Packit |
df99a1 |
provided_input.ymin > required_input.ymin ||
|
|
Packit |
df99a1 |
provided_input.xmax < required_input.xmax ||
|
|
Packit |
df99a1 |
provided_input.ymax < required_input.ymax )
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.too_small") );
|
|
Packit |
df99a1 |
// Adjust output pixmap
|
|
Packit |
df99a1 |
if (desired_output.width() != (int)output.columns() ||
|
|
Packit |
df99a1 |
desired_output.height() != (int)output.rows() )
|
|
Packit |
df99a1 |
output.init(desired_output.height(), desired_output.width());
|
|
Packit |
df99a1 |
output.set_grays(256);
|
|
Packit |
df99a1 |
// Prepare temp stuff
|
|
Packit |
df99a1 |
gp1.resize(0);
|
|
Packit |
df99a1 |
gp2.resize(0);
|
|
Packit |
df99a1 |
glbuffer.resize(0);
|
|
Packit |
df99a1 |
prepare_interp();
|
|
Packit |
df99a1 |
const int bufw = required_red.width();
|
|
Packit |
df99a1 |
glbuffer.resize(bufw+2);
|
|
Packit |
df99a1 |
gp1.resize(bufw);
|
|
Packit |
df99a1 |
gp2.resize(bufw);
|
|
Packit |
df99a1 |
l1 = l2 = -1;
|
|
Packit |
df99a1 |
// Prepare gray conversion array (conv)
|
|
Packit |
df99a1 |
gconv.resize(0);
|
|
Packit |
df99a1 |
gconv.resize(256);
|
|
Packit |
df99a1 |
int maxgray = input.get_grays()-1;
|
|
Packit |
df99a1 |
for (int i=0; i<256; i++)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
conv[i]=(i<= maxgray)
|
|
Packit |
df99a1 |
?(((i*255) + (maxgray>>1)) / maxgray)
|
|
Packit |
df99a1 |
:255;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Loop on output lines
|
|
Packit |
df99a1 |
for (int y=desired_output.ymin; y
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Perform vertical interpolation
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int fy = vcoord[y];
|
|
Packit |
df99a1 |
int fy1 = fy>>FRACBITS;
|
|
Packit |
df99a1 |
int fy2 = fy1+1;
|
|
Packit |
df99a1 |
const unsigned char *lower, *upper;
|
|
Packit |
df99a1 |
// Obtain upper and lower line in reduced image
|
|
Packit |
df99a1 |
lower = get_line(fy1, required_red, provided_input, input);
|
|
Packit |
df99a1 |
upper = get_line(fy2, required_red, provided_input, input);
|
|
Packit |
df99a1 |
// Compute line
|
|
Packit |
df99a1 |
unsigned char *dest = lbuffer+1;
|
|
Packit |
df99a1 |
const short *deltas = & interp[fy&FRACMASK][256];
|
|
Packit |
df99a1 |
for(unsigned char const * const edest=(unsigned char const *)dest+bufw;
|
|
Packit |
df99a1 |
dest
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const int l = *lower;
|
|
Packit |
df99a1 |
const int u = *upper;
|
|
Packit |
df99a1 |
*dest = l + deltas[u-l];
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Perform horizontal interpolation
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Prepare for side effects
|
|
Packit |
df99a1 |
lbuffer[0] = lbuffer[1];
|
|
Packit |
df99a1 |
lbuffer[bufw+1] = lbuffer[bufw];
|
|
Packit |
df99a1 |
unsigned char *line = lbuffer+1-required_red.xmin;
|
|
Packit |
df99a1 |
unsigned char *dest = output[y-desired_output.ymin];
|
|
Packit |
df99a1 |
// Loop horizontally
|
|
Packit |
df99a1 |
for (int x=desired_output.xmin; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int n = hcoord[x];
|
|
Packit |
df99a1 |
const unsigned char *lower = line + (n>>FRACBITS);
|
|
Packit |
df99a1 |
const short *deltas = &interp[n&FRACMASK][256];
|
|
Packit |
df99a1 |
int l = lower[0];
|
|
Packit |
df99a1 |
int u = lower[1];
|
|
Packit |
df99a1 |
*dest = l + deltas[u-l];
|
|
Packit |
df99a1 |
dest++;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Free temporaries
|
|
Packit |
df99a1 |
gp1.resize(0);
|
|
Packit |
df99a1 |
gp2.resize(0);
|
|
Packit |
df99a1 |
glbuffer.resize(0);
|
|
Packit |
df99a1 |
gconv.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
////////////////////////////////////////
|
|
Packit |
df99a1 |
// GPIXMAPSCALER
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GPixmapScaler::GPixmapScaler()
|
|
Packit |
df99a1 |
: glbuffer(lbuffer,0),
|
|
Packit |
df99a1 |
gp1(p1,0),
|
|
Packit |
df99a1 |
gp2(p2,0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GPixmapScaler::GPixmapScaler(int inw, int inh, int outw, int outh)
|
|
Packit |
df99a1 |
: glbuffer(lbuffer,0),
|
|
Packit |
df99a1 |
gp1(p1,0),
|
|
Packit |
df99a1 |
gp2(p2,0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
set_input_size(inw, inh);
|
|
Packit |
df99a1 |
set_output_size(outw, outh);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GPixmapScaler::~GPixmapScaler()
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
GPixel *
|
|
Packit |
df99a1 |
GPixmapScaler::get_line(int fy,
|
|
Packit |
df99a1 |
const GRect &required_red,
|
|
Packit |
df99a1 |
const GRect &provided_input,
|
|
Packit |
df99a1 |
const GPixmap &input )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
if (fy < required_red.ymin)
|
|
Packit |
df99a1 |
fy = required_red.ymin;
|
|
Packit |
df99a1 |
else if (fy >= required_red.ymax)
|
|
Packit |
df99a1 |
fy = required_red.ymax - 1;
|
|
Packit |
df99a1 |
// Cached line
|
|
Packit |
df99a1 |
if (fy == l2)
|
|
Packit |
df99a1 |
return p2;
|
|
Packit |
df99a1 |
if (fy == l1)
|
|
Packit |
df99a1 |
return p1;
|
|
Packit |
df99a1 |
// Shift
|
|
Packit |
df99a1 |
GPixel *p=p1;
|
|
Packit |
df99a1 |
p1 = p2;
|
|
Packit |
df99a1 |
l1 = l2;
|
|
Packit |
df99a1 |
p2 = p;
|
|
Packit |
df99a1 |
l2 = fy;
|
|
Packit |
df99a1 |
// Compute location of line
|
|
Packit |
df99a1 |
GRect line;
|
|
Packit |
df99a1 |
line.xmin = required_red.xmin << xshift;
|
|
Packit |
df99a1 |
line.xmax = required_red.xmax << xshift;
|
|
Packit |
df99a1 |
line.ymin = fy << yshift;
|
|
Packit |
df99a1 |
line.ymax = (fy+1) << yshift;
|
|
Packit |
df99a1 |
line.intersect(line, provided_input);
|
|
Packit |
df99a1 |
line.translate(-provided_input.xmin, -provided_input.ymin);
|
|
Packit |
df99a1 |
// Prepare variables
|
|
Packit |
df99a1 |
const GPixel *botline = input[line.ymin];
|
|
Packit |
df99a1 |
int rowsize = input.rowsize();
|
|
Packit |
df99a1 |
int sw = 1<
|
|
Packit |
df99a1 |
int div = xshift+yshift;
|
|
Packit |
df99a1 |
int rnd = 1<<(div-1);
|
|
Packit |
df99a1 |
// Compute averages
|
|
Packit |
df99a1 |
for (int x=line.xmin; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int r=0, g=0, b=0, s=0;
|
|
Packit |
df99a1 |
const GPixel *inp0 = botline + x;
|
|
Packit |
df99a1 |
int sy1 = mini(line.height(), (1<
|
|
Packit |
df99a1 |
for (int sy=0; sy
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const GPixel *inp1;
|
|
Packit |
df99a1 |
const GPixel *inp2 = inp0 + mini(x+sw, line.xmax) - x;
|
|
Packit |
df99a1 |
for (inp1 = inp0; inp1
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
r += inp1->r;
|
|
Packit |
df99a1 |
g += inp1->g;
|
|
Packit |
df99a1 |
b += inp1->b;
|
|
Packit |
df99a1 |
s += 1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
if (s == rnd+rnd)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
p->r = (r+rnd) >> div;
|
|
Packit |
df99a1 |
p->g = (g+rnd) >> div;
|
|
Packit |
df99a1 |
p->b = (b+rnd) >> div;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
p->r = (r+s/2)/s;
|
|
Packit |
df99a1 |
p->g = (g+s/2)/s;
|
|
Packit |
df99a1 |
p->b = (b+s/2)/s;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Return
|
|
Packit |
df99a1 |
return (GPixel *)p2;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
void
|
|
Packit |
df99a1 |
GPixmapScaler::scale( const GRect &provided_input, const GPixmap &input,
|
|
Packit |
df99a1 |
const GRect &desired_output, GPixmap &output )
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Compute rectangles
|
|
Packit |
df99a1 |
GRect required_input;
|
|
Packit |
df99a1 |
GRect required_red;
|
|
Packit |
df99a1 |
make_rectangles(desired_output, required_red, required_input);
|
|
Packit |
df99a1 |
// Parameter validation
|
|
Packit |
df99a1 |
if (provided_input.width() != (int)input.columns() ||
|
|
Packit |
df99a1 |
provided_input.height() != (int)input.rows() )
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.no_match") );
|
|
Packit |
df99a1 |
if (provided_input.xmin > required_input.xmin ||
|
|
Packit |
df99a1 |
provided_input.ymin > required_input.ymin ||
|
|
Packit |
df99a1 |
provided_input.xmax < required_input.xmax ||
|
|
Packit |
df99a1 |
provided_input.ymax < required_input.ymax )
|
|
Packit |
df99a1 |
G_THROW( ERR_MSG("GScaler.too_small") );
|
|
Packit |
df99a1 |
// Adjust output pixmap
|
|
Packit |
df99a1 |
if (desired_output.width() != (int)output.columns() ||
|
|
Packit |
df99a1 |
desired_output.height() != (int)output.rows() )
|
|
Packit |
df99a1 |
output.init(desired_output.height(), desired_output.width());
|
|
Packit |
df99a1 |
// Prepare temp stuff
|
|
Packit |
df99a1 |
gp1.resize(0);
|
|
Packit |
df99a1 |
gp2.resize(0);
|
|
Packit |
df99a1 |
glbuffer.resize(0);
|
|
Packit |
df99a1 |
prepare_interp();
|
|
Packit |
df99a1 |
const int bufw = required_red.width();
|
|
Packit |
df99a1 |
glbuffer.resize(bufw+2);
|
|
Packit |
df99a1 |
if (xshift>0 || yshift>0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
gp1.resize(bufw);
|
|
Packit |
df99a1 |
gp2.resize(bufw);
|
|
Packit |
df99a1 |
l1 = l2 = -1;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Loop on output lines
|
|
Packit |
df99a1 |
for (int y=desired_output.ymin; y
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Perform vertical interpolation
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int fy = vcoord[y];
|
|
Packit |
df99a1 |
int fy1 = fy>>FRACBITS;
|
|
Packit |
df99a1 |
int fy2 = fy1+1;
|
|
Packit |
df99a1 |
const GPixel *lower, *upper;
|
|
Packit |
df99a1 |
// Obtain upper and lower line in reduced image
|
|
Packit |
df99a1 |
if (xshift>0 || yshift>0)
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
lower = get_line(fy1, required_red, provided_input, input);
|
|
Packit |
df99a1 |
upper = get_line(fy2, required_red, provided_input, input);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
else
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
int dx = required_red.xmin-provided_input.xmin;
|
|
Packit |
df99a1 |
fy1 = maxi(fy1, required_red.ymin);
|
|
Packit |
df99a1 |
fy2 = mini(fy2, required_red.ymax-1);
|
|
Packit |
df99a1 |
lower = input[fy1-provided_input.ymin] + dx;
|
|
Packit |
df99a1 |
upper = input[fy2-provided_input.ymin] + dx;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Compute line
|
|
Packit |
df99a1 |
GPixel *dest = lbuffer+1;
|
|
Packit |
df99a1 |
const short *deltas = & interp[fy&FRACMASK][256];
|
|
Packit |
df99a1 |
for(GPixel const * const edest = (GPixel const *)dest+bufw;
|
|
Packit |
df99a1 |
dest
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const int lower_r = lower->r;
|
|
Packit |
df99a1 |
const int delta_r = deltas[(int)upper->r - lower_r];
|
|
Packit |
df99a1 |
dest->r = lower_r + delta_r;
|
|
Packit |
df99a1 |
const int lower_g = lower->g;
|
|
Packit |
df99a1 |
const int delta_g = deltas[(int)upper->g - lower_g];
|
|
Packit |
df99a1 |
dest->g = lower_g + delta_g;
|
|
Packit |
df99a1 |
const int lower_b = lower->b;
|
|
Packit |
df99a1 |
const int delta_b = deltas[(int)upper->b - lower_b];
|
|
Packit |
df99a1 |
dest->b = lower_b + delta_b;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Perform horizontal interpolation
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
// Prepare for side effects
|
|
Packit |
df99a1 |
lbuffer[0] = lbuffer[1];
|
|
Packit |
df99a1 |
lbuffer[bufw+1] = lbuffer[bufw];
|
|
Packit |
df99a1 |
GPixel *line = lbuffer+1-required_red.xmin;
|
|
Packit |
df99a1 |
GPixel *dest = output[y-desired_output.ymin];
|
|
Packit |
df99a1 |
// Loop horizontally
|
|
Packit |
df99a1 |
for (int x=desired_output.xmin; x
|
|
Packit |
df99a1 |
{
|
|
Packit |
df99a1 |
const int n = hcoord[x];
|
|
Packit |
df99a1 |
const GPixel *lower = line + (n>>FRACBITS);
|
|
Packit |
df99a1 |
const short *deltas = &interp[n&FRACMASK][256];
|
|
Packit |
df99a1 |
const int lower_r = lower[0].r;
|
|
Packit |
df99a1 |
const int delta_r = deltas[(int)lower[1].r - lower_r];
|
|
Packit |
df99a1 |
dest->r = lower_r + delta_r;
|
|
Packit |
df99a1 |
const int lower_g = lower[0].g;
|
|
Packit |
df99a1 |
const int delta_g = deltas[(int)lower[1].g - lower_g];
|
|
Packit |
df99a1 |
dest->g = lower_g + delta_g;
|
|
Packit |
df99a1 |
const int lower_b = lower[0].b;
|
|
Packit |
df99a1 |
const int delta_b = deltas[(int)lower[1].b - lower_b];
|
|
Packit |
df99a1 |
dest->b = lower_b + delta_b;
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
// Free temporaries
|
|
Packit |
df99a1 |
gp1.resize(0);
|
|
Packit |
df99a1 |
gp2.resize(0);
|
|
Packit |
df99a1 |
glbuffer.resize(0);
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
|
|
Packit |
df99a1 |
#ifdef HAVE_NAMESPACES
|
|
Packit |
df99a1 |
}
|
|
Packit |
df99a1 |
# ifndef NOT_USING_DJVU_NAMESPACE
|
|
Packit |
df99a1 |
using namespace DJVU;
|
|
Packit |
df99a1 |
# endif
|
|
Packit |
df99a1 |
#endif
|
|
Packit |
df99a1 |
|