Blame libdjvu/GScaler.cpp

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