source: trunk/libdjvu/GPixmap.cpp @ 206

Last change on this file since 206 was 206, checked in by Eugene Romanenko, 14 years ago

DJVU plugin: djvulibre updated to version 3.5.19

File size: 44.8 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: GPixmap.cpp,v 1.16 2007/03/25 20:48:32 leonb Exp $
57// $Name: release_3_5_19 $
58
59#ifdef HAVE_CONFIG_H
60# include "config.h"
61#endif
62#if NEED_GNUG_PRAGMAS
63# pragma implementation
64#endif
65
66// -- Implements class PIXMAP
67// Author: Leon Bottou 07/1997
68
69
70
71#include "GPixmap.h"
72
73#include "GString.h"
74#include "GException.h"
75#include "ByteStream.h"
76#include "GRect.h"
77#include "GBitmap.h"
78#include "GThreads.h"
79#include "Arrays.h"
80#include "JPEGDecoder.h"
81#include <stdlib.h>
82#include <math.h>
83#include <assert.h>
84
85
86#ifdef HAVE_NAMESPACES
87namespace DJVU {
88# ifdef NOT_DEFINED // Just to fool emacs c++ mode
89}
90#endif
91#endif
92
93
94
95//////////////////////////////////////////////////
96// ------- predefined colors
97//////////////////////////////////////////////////
98
99
100const GPixel GPixel::WHITE = { 255, 255, 255 };
101const GPixel GPixel::BLACK = {   0,   0,   0 };
102const GPixel GPixel::BLUE  = { 255,   0,   0 };
103const GPixel GPixel::GREEN = {   0, 255,   0 };
104const GPixel GPixel::RED   = {   0,   0, 255 };
105
106
107//////////////////////////////////////////////////
108// ----- utilities
109//////////////////////////////////////////////////
110
111
112static const GPixel *
113new_gray_ramp(int grays,GPixel *ramp)
114{
115  int color = 0xff0000;
116  int decrement = color / (grays-1);
117  for (int i=0; i<grays; i++)
118    {
119      int level = color >> 16;
120      ramp[i].b = level;
121      ramp[i].g = level;
122      ramp[i].r = level;
123      color -= decrement;
124    }
125  return ramp;
126}
127
128
129static inline int
130mini(int x, int y) 
131{ 
132  return (x < y ? x : y);
133}
134
135
136static inline int
137maxi(int x, int y) 
138{ 
139  return (x > y ? x : y);
140}
141
142
143static inline void 
144euclidian_ratio(int a, int b, int &q, int &r)
145{
146  q = a / b;
147  r = a - b*q;
148  if (r < 0)
149  {
150    q -= 1;
151    r += b;
152  }
153}
154
155
156//////////////////////////////////////////////////
157// global lock used by some rare operations
158//////////////////////////////////////////////////
159
160static GMonitor &pixmap_monitor() {
161  static GMonitor xpixmap_monitor;
162  return xpixmap_monitor;
163}
164
165
166//////////////////////////////////////////////////
167// constructors and destructors
168//////////////////////////////////////////////////
169
170
171GPixmap::~GPixmap()
172{
173  delete [] pixels_data;
174}
175
176void
177GPixmap::destroy(void)
178{
179  delete [] pixels_data;
180  pixels = pixels_data = 0;
181}
182
183GPixmap::GPixmap()
184: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
185{
186}
187
188GPixmap::GPixmap(int nrows, int ncolumns, const GPixel *filler)
189: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
190{
191  G_TRY
192  {
193    init(nrows, ncolumns, filler);
194  }
195  G_CATCH_ALL
196  {
197        destroy();
198        G_RETHROW;
199  }
200  G_ENDCATCH;
201}
202
203GPixmap::GPixmap(ByteStream &bs)
204: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
205{
206  G_TRY
207  {
208        init(bs);
209  }
210  G_CATCH_ALL
211  {
212        destroy();
213        G_RETHROW;
214  }
215  G_ENDCATCH;
216}
217
218GPixmap::GPixmap(const GBitmap &ref)
219: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
220{
221  G_TRY
222  {
223        init(ref, 0);
224  }
225  G_CATCH_ALL
226  {
227        destroy();
228        G_RETHROW;
229  }
230  G_ENDCATCH;
231}
232
233GPixmap::GPixmap(const GBitmap &ref, const GRect &rect)
234: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
235{
236  G_TRY
237  {
238    init(ref, rect, 0);
239  }
240  G_CATCH_ALL
241  {
242        destroy();
243        G_RETHROW;
244  }
245  G_ENDCATCH;
246}
247
248GPixmap::GPixmap(const GPixmap &ref)
249: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
250{
251  G_TRY
252  {
253    init(ref);
254  }
255  G_CATCH_ALL
256  {
257        destroy();
258        G_RETHROW;
259  }
260  G_ENDCATCH;
261}
262
263GPixmap::GPixmap(const GPixmap &ref, const GRect &rect)
264: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
265{
266  G_TRY
267  {
268        init(ref, rect);
269  }
270  G_CATCH_ALL
271  {
272        destroy();
273        G_RETHROW;
274  }
275  G_ENDCATCH;
276}
277
278
279
280//////////////////////////////////////////////////
281// Initialization
282//////////////////////////////////////////////////
283
284
285void 
286GPixmap::init(int arows, int acolumns, const GPixel *filler)
287{
288  destroy();
289  nrows = arows;
290  ncolumns = acolumns;
291  nrowsize = acolumns;
292  int npix = nrows * nrowsize;
293  if (npix > 0)
294  {
295    pixels = pixels_data = new GPixel[npix];
296    if (filler)
297    { 
298      while (--npix>=0) 
299        pixels_data[npix] = *filler;
300    }
301  }
302}
303
304
305void 
306GPixmap::init(const GBitmap &ref, const GPixel *userramp)
307{
308  init(ref.rows(), ref.columns(), 0);
309  GPixel *xramp;
310  GPBuffer<GPixel> gxramp(xramp);
311  if (nrows>0 && ncolumns>0)
312  {
313    // Create pixel ramp
314    const GPixel *ramp = userramp;
315    if (!userramp)
316        {
317          gxramp.resize(256);
318          gxramp.clear();
319          ramp = new_gray_ramp(ref.get_grays(),xramp);
320        }
321    // Copy pixels
322    for (int y=0; y<nrows; y++)
323    {
324      GPixel *dst = (*this)[y];
325      const unsigned char *src = ref[y];
326      for (int x=0; x<ncolumns; x++)
327        dst[x] = ramp[ src[x] ];
328    }
329    // Free ramp
330//    if (!userramp)
331//      delete [] (GPixel*)ramp;
332  }
333}
334
335
336void 
337GPixmap::init(const GBitmap &ref, const GRect &rect, const GPixel *userramp)
338{
339  init(rect.height(), rect.width(), 0);
340  // compute destination rectangle
341  GRect rect2(0, 0, ref.columns(), ref.rows() );
342  rect2.intersect(rect2, rect);
343  rect2.translate(-rect.xmin, -rect.ymin);
344  // copy bits
345  if (! rect2.isempty())
346  {
347    GPixel *xramp;
348    GPBuffer<GPixel> gxramp(xramp);
349    // allocate ramp
350    const GPixel *ramp = userramp;
351    if (!userramp)
352        {
353          gxramp.resize(256);
354          gxramp.clear();
355          ramp = new_gray_ramp(ref.get_grays(),xramp);
356        }
357    // copy pixels
358    for (int y=rect2.ymin; y<rect2.ymax; y++)
359    {
360      GPixel *dst = (*this)[y];
361      const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
362      for (int x=rect2.xmin; x<rect2.xmax; x++)
363        dst[x] = ramp[ src[x] ];
364    }
365    // free ramp
366//    if (!userramp)
367//      delete [] (GPixel*) ramp;
368  }
369}
370
371
372void 
373GPixmap::init(const GPixmap &ref)
374{
375  init(ref.rows(), ref.columns(), 0);
376  if (nrows>0 && ncolumns>0)
377  {
378    for (int y=0; y<nrows; y++)
379    {
380      GPixel *dst = (*this)[y];
381      const GPixel *src = ref[y];
382      for (int x=0; x<ncolumns; x++)
383        dst[x] = src[x];
384    }
385  }
386}
387
388
389void 
390GPixmap::init(const GPixmap &ref, const GRect &rect)
391{
392  init(rect.height(), rect.width(), 0);
393  // compute destination rectangle
394  GRect rect2(0, 0, ref.columns(), ref.rows() );
395  rect2.intersect(rect2, rect);
396  rect2.translate(-rect.xmin, -rect.ymin);
397  // copy bits
398  if (! rect2.isempty())
399  {
400    for (int y=rect2.ymin; y<rect2.ymax; y++)
401    {
402      GPixel *dst = (*this)[y];
403      const GPixel *src = ref[y+rect.ymin] + rect.xmin;
404      for (int x=rect2.xmin; x<rect2.xmax; x++)
405        dst[x] = src[x];
406    }
407  }
408}
409
410
411void 
412GPixmap::donate_data(GPixel *data, int w, int h)
413{
414  destroy();
415  nrows = h;
416  ncolumns = w;
417  nrowsize = w;
418  pixels_data=pixels=data;
419}
420
421
422GPixel *
423GPixmap::take_data(size_t &offset)
424{
425  GPixel *ret = pixels_data;
426  pixels_data = 0;
427  offset = 0;
428  return ret;
429}
430
431
432
433//////////////////////////////////////////////////
434// Save and load ppm files
435//////////////////////////////////////////////////
436
437
438static unsigned int 
439read_integer(char &c, ByteStream &bs)
440{
441  unsigned int x = 0;
442  // eat blank before integer
443  while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#') 
444    {
445      if (c=='#') 
446        do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
447      c = 0; 
448      bs.read(&c, 1);
449    }
450  // check integer
451  if (c<'0' || c>'9')
452    G_THROW( ERR_MSG("GPixmap.no_int") );
453  // eat integer
454  while (c>='0' && c<='9') 
455    {
456      x = x*10 + c - '0';
457      c = 0;
458      bs.read(&c, 1);
459    }
460  return x;
461}
462
463
464void 
465GPixmap::init(ByteStream &bs)
466{
467  // Read header
468  bool raw = false;
469  bool grey = false;
470  int magic = bs.read16();
471  switch (magic)
472    {
473    case ('P'<<8)+'2':
474      grey = true;
475      break;
476    case ('P'<<8)+'3':
477      break;
478    case ('P'<<8)+'5':
479      raw = grey = true;
480    case ('P'<<8)+'6':
481      raw = true;
482      break;
483    default:
484#ifdef NEED_JPEG_DECODER
485      bs.seek(0L);
486      JPEGDecoder::decode(bs,*this);
487      return;
488#else
489     
490      G_THROW( ERR_MSG("GPixmap.unk_PPM") );
491#endif
492    }
493  // Read image size
494  char lookahead = '\n';
495  int bytesperrow = 0;
496  int bytespercomp = 1;
497  int acolumns = read_integer(lookahead, bs);
498  int arows = read_integer(lookahead, bs);
499  int maxval = read_integer(lookahead, bs);
500  if (maxval > 65535)
501    G_THROW("Cannot read PPM with depth greater than 48 bits.");
502  if (maxval > 255)
503    bytespercomp = 2;
504  init(arows, acolumns, 0);
505  // Prepare ramp
506  GTArray<unsigned char> ramp;
507  int maxbin = 1 << (8 * bytespercomp);
508  ramp.resize(0, maxbin-1);
509  for (int i=0; i<maxbin; i++)
510    ramp[i] = (i<maxval ? (255*i + maxval/2) / maxval : 255);
511  unsigned char *bramp = ramp;
512  // Read image data
513  if (raw && grey)
514    {
515      bytesperrow = ncolumns * bytespercomp;
516      GTArray<unsigned char> line(bytesperrow);
517      for (int y=nrows-1; y>=0; y--) 
518        {
519          GPixel *p = (*this)[y];
520          unsigned char *g = &line[0];
521          if ( bs.readall((void*)g, bytesperrow) < (size_t)bytesperrow)
522            G_THROW( ByteStream::EndOfFile );
523          if (bytespercomp <= 1)
524            {
525              for (int x=0; x<ncolumns; x+=1, g+=1)
526                p[x].r = p[x].g = p[x].b = bramp[g[0]];
527            }
528          else
529            {
530              for (int x=0; x<ncolumns; x+=1, g+=2)
531                p[x].r = p[x].g = p[x].b = bramp[g[0]*256+g[1]];
532            }
533        }
534    }
535  else if (raw)
536    {
537      bytesperrow = ncolumns * bytespercomp * 3;
538      GTArray<unsigned char> line(bytesperrow);
539      for (int y=nrows-1; y>=0; y--) 
540        {
541          GPixel *p = (*this)[y];
542          unsigned char *rgb = &line[0];
543          if ( bs.readall((void*)rgb, bytesperrow) < (size_t)bytesperrow)
544            G_THROW( ByteStream::EndOfFile );
545          if (bytespercomp <= 1)
546            {
547              for (int x=0; x<ncolumns; x+=1, rgb+=3)
548                {
549                  p[x].r = bramp[rgb[0]];
550                  p[x].g = bramp[rgb[1]];
551                  p[x].b = bramp[rgb[2]];
552                }
553            }
554          else
555            for (int x=0; x<ncolumns; x+=1, rgb+=6)
556              {
557                p[x].r = bramp[rgb[0]*256+rgb[1]];
558                p[x].g = bramp[rgb[2]*256+rgb[3]];
559                p[x].b = bramp[rgb[4]*256+rgb[5]];
560              }
561        }
562    }
563  else
564    {
565      for (int y=nrows-1; y>=0; y--) 
566        {
567          GPixel *p = (*this)[y];
568          for (int x=0; x<ncolumns; x++)
569            if (grey)
570              {
571                p[x].g = p[x].b = p[x].r = ramp[read_integer(lookahead, bs)];
572              }
573            else
574              {
575                p[x].r = ramp[read_integer(lookahead, bs)];
576                p[x].g = ramp[read_integer(lookahead, bs)];
577                p[x].b = ramp[read_integer(lookahead, bs)];
578              }
579        }
580    }
581}
582
583
584void 
585GPixmap::save_ppm(ByteStream &bs, int raw) const
586{
587  GUTF8String head;
588  head.format("P%c\n%d %d\n255\n", (raw ? '6' : '3'), ncolumns, nrows);
589  bs.writall((void*)(const char *)head, head.length());
590  if (raw)
591    {
592      int rowsize = ncolumns+ncolumns+ncolumns;
593      GTArray<unsigned char> xrgb(rowsize);
594      for (int y=nrows-1; y>=0; y--) 
595        {
596          const GPixel *p = (*this)[y];
597          unsigned char *d = xrgb;
598          for (int x=0; x<ncolumns; x++) 
599            {
600              *d++ = p[x].r;
601              *d++ = p[x].g;
602              *d++ = p[x].b;
603            }
604          bs.writall((void*)(unsigned char*)xrgb, ncolumns * 3);
605        }
606    }
607  else
608    {
609      for (int y=nrows-1; y>=0; y--) 
610        {
611          const GPixel *p = (*this)[y];
612          unsigned char eol='\n';
613          for (int x=0; x<ncolumns; )
614            {
615              head.format("%d %d %d  ", p[x].r, p[x].g, p[x].b);
616              bs.writall((void*)(const char *)head, head.length());
617              x += 1;
618              if (x==ncolumns || (x&0x7)==0) 
619                bs.write((void*)&eol, 1);         
620            }
621        }
622    }
623}
624
625
626
627
628//////////////////////////////////////////////////
629// Color correction
630//////////////////////////////////////////////////
631
632
633static void
634color_correction_table(double gamma, unsigned char gtable[256] )
635{
636  // Check argument
637  if (gamma<0.1 || gamma>10.0)
638    G_THROW( ERR_MSG("GPixmap.bad_param") );
639  if (gamma<1.001 && gamma>0.999)
640    {
641      // Trivial correction
642      for (int i=0; i<256; i++)
643        gtable[i] = i;
644    }
645  else
646    {
647      // Must compute the correction
648      for (int i=0; i<256; i++)
649        {
650          double x = (double)(i)/255.0;
651#ifdef BEZIERGAMMA
652          double t = ( sqrt(1.0+(gamma*gamma-1.0)*x) - 1.0 ) / (gamma - 1.0);
653          x = ( (1.0 - gamma)*t + 2.0 * gamma ) * t / (gamma + 1.0);
654#else
655          x = pow(x, 1.0/gamma);       
656#endif
657          gtable[i] = (int) floor(255.0 * x + 0.5);
658        }
659      // Make sure that min and max values are exactly black or white
660      gtable[0] = 0;
661      gtable[255] = 255;
662    }
663}
664
665static void
666color_correction_table_cache(double gamma, unsigned char gtable[256] )
667{
668  // Compute color correction table
669  if (gamma<1.001 && gamma>0.999)
670    {
671      color_correction_table(gamma, gtable);
672    }
673  else
674    {
675      static double lgamma = -1.0;
676      static unsigned char ctable[256];
677      GMonitorLock lock(&pixmap_monitor());
678      if (gamma != lgamma)
679        {
680          color_correction_table(gamma, ctable);
681          lgamma = gamma;
682        }
683      memcpy(gtable, ctable, 256*sizeof(unsigned char));
684    }
685}
686
687void 
688GPixmap::color_correct(double gamma_correction)
689{
690  // Trivial corrections
691  if (gamma_correction>0.999 && gamma_correction<1.001)
692    return;
693  // Compute correction table
694  unsigned char gtable[256];
695  color_correction_table_cache(gamma_correction, gtable);
696  // Perform correction
697  for (int y=0; y<nrows; y++)
698  {
699    GPixel *pix = (*this)[y];
700    for (int x=0; x<ncolumns; x++, pix++)
701    {
702      pix->r = gtable[ pix->r ];
703      pix->g = gtable[ pix->g ];
704      pix->b = gtable[ pix->b ];
705    }
706  }
707}
708
709
710void 
711GPixmap::color_correct(double gamma_correction, GPixel *pix, int npixels)
712{
713  // Trivial corrections
714  if (gamma_correction>0.999 && gamma_correction<1.001)
715    return;
716  // Compute correction table
717  unsigned char gtable[256];
718  color_correction_table_cache(gamma_correction, gtable);
719  // Perform correction
720  while (--npixels>=0)
721    {
722      pix->r = gtable[pix->r];
723      pix->g = gtable[pix->g];
724      pix->b = gtable[pix->b];
725      pix++;
726    }
727}
728
729
730
731//////////////////////////////////////////////////
732// Dithering
733//////////////////////////////////////////////////
734
735
736void
737GPixmap::ordered_666_dither(int xmin, int ymin)
738{
739  static unsigned char quantize[256+0x33+0x33];
740  static unsigned char *quant = quantize + 0x33;
741  static char  dither_ok = 0;
742  static short dither[16][16] = 
743  {
744    {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
745    { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
746    {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
747    { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
748    {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
749    { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
750    {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
751    { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
752    {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
753    { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
754    {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
755    { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
756    {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
757    { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
758    {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
759    { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
760  };
761  // Prepare tables
762  if (!dither_ok)
763  {
764    int i, j;
765    for (i=0; i<16; i++)
766      for (j=0; j<16; j++)
767        dither[i][j] = ((255 - 2*dither[i][j]) * 0x33) / 512;   
768    j = -0x33;
769    for (i=0x19; i<256; i+=0x33)
770      while (j <= i)
771        quant[j++] = i-0x19;
772    assert(i-0x19 == 0xff);
773    while (j< 256+0x33)
774      quant[j++] = i-0x19;
775    dither_ok = 1;
776  }
777  // Go dithering
778  for (int y=0; y<nrows; y++)
779  {
780    GPixel *pix = (*this)[y];
781    for (int x=0; x<ncolumns; x++, pix++)
782    {
783      pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
784      pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
785      pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
786    }
787  }
788}
789
790void
791GPixmap::ordered_32k_dither(int xmin, int ymin)
792{
793  static unsigned char quantize[256+8+8];
794  static unsigned char *quant = quantize + 8;
795  static char  dither_ok = 0;
796  static short dither[16][16] = 
797  {
798    {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
799    { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
800    {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
801    { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
802    {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
803    { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
804    {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
805    { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
806    {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
807    { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
808    {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
809    { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
810    {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
811    { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
812    {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
813    { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
814  };
815  // Prepare tables
816  if (!dither_ok)
817  {
818    int i, j;
819    for (i=0; i<16; i++)
820      for (j=0; j<16; j++)
821        dither[i][j] = ((255 - 2*dither[i][j]) * 8) / 512;   
822    j = -8;
823    for (i=3; i<256; i+=8)
824      while (j <= i)
825        quant[j++] = i;
826    while (j<256+8)
827      quant[j++] = 0xff;
828    dither_ok = 1;
829  }
830  // Go dithering
831  for (int y=0; y<nrows; y++)
832  {
833    GPixel *pix = (*this)[y];
834    for (int x=0; x<ncolumns; x++, pix++)
835    {
836      pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
837      pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
838      pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
839    }
840  }
841}
842
843
844//////////////////////////////////////////////////
845// Upsample Downsample
846//////////////////////////////////////////////////
847
848
849void 
850GPixmap::downsample(const GPixmap *src, int factor, const GRect *pdr)
851{
852  // check arguments
853  GRect rect(0, 0, (src->columns()+factor-1)/factor, (src->rows()+factor-1)/factor);
854  if (pdr != 0)
855  {
856    if (pdr->xmin < rect.xmin || 
857        pdr->ymin < rect.ymin || 
858        pdr->xmax > rect.xmax || 
859        pdr->ymax > rect.ymax  )
860      G_THROW( ERR_MSG("GPixmap.overflow1") );
861    rect = *pdr;
862  }
863
864  // precompute inverse map
865  static int invmap[256];
866  static int invmapok = 0;
867  if (! invmapok)
868  {
869    invmapok = 1;
870    for (int i=1; i<(int)(sizeof(invmap)/sizeof(int)); i++)
871      invmap[i] = 0x10000 / i;
872  }
873 
874  // initialise pixmap
875  init(rect.height(), rect.width(), 0);
876
877  // determine starting and ending points in source rectangle
878  int sy = rect.ymin * factor;
879  int sxz = rect.xmin * factor;
880
881
882  // loop over source rows
883  const GPixel *sptr = (*src)[sy];
884  GPixel *dptr = (*this)[0];
885  for (int y=0; y<nrows; y++)
886  {
887    int sx = sxz;
888    // loop over source columns
889    for (int x=0; x<ncolumns; x++)
890    {
891      int r=0, g=0, b=0, s=0;
892      // compute average bounds
893      const GPixel *ksptr = sptr;
894      int lsy = sy + factor;
895      if (lsy > (int)src->rows())
896        lsy = (int)src->rows();
897      int lsx = sx + factor;
898      if (lsx > (int)src->columns())
899        lsx = (int)src->columns();
900      // compute average
901      for (int rsy=sy; rsy<lsy; rsy++)
902      {
903        for (int rsx = sx; rsx<lsx; rsx++)
904        {
905          r += ksptr[rsx].r;
906          g += ksptr[rsx].g;
907          b += ksptr[rsx].b;
908          s += 1;
909        }
910        ksptr += src->rowsize();
911      }
912      // set pixel color
913      if (s >= (int)(sizeof(invmap)/sizeof(int)))
914      {
915        dptr[x].r = r / s;
916        dptr[x].g = g / s;
917        dptr[x].b = b / s;
918      }
919      else
920      {
921        dptr[x].r = (r*invmap[s] + 0x8000) >> 16;
922        dptr[x].g = (g*invmap[s] + 0x8000) >> 16;
923        dptr[x].b = (b*invmap[s] + 0x8000) >> 16;
924      }
925      // next column
926      sx = sx + factor;
927    }
928    // next row
929    sy = sy + factor;
930    sptr = sptr + factor * src->rowsize();
931    dptr = dptr + rowsize();
932  }
933}
934
935void 
936GPixmap::upsample(const GPixmap *src, int factor, const GRect *pdr)
937{
938  // check arguments
939  GRect rect(0, 0, src->columns()*factor, src->rows()*factor);
940  if (pdr != 0)
941  {
942    if (pdr->xmin < rect.xmin || 
943        pdr->ymin < rect.ymin || 
944        pdr->xmax > rect.xmax || 
945        pdr->ymax > rect.ymax  )
946      G_THROW( ERR_MSG("GPixmap.overflow2") );
947    rect = *pdr;
948  }
949  // initialise pixmap
950  init(rect.height(), rect.width(), 0);
951  // compute starting point in source rectangle
952  int sy, sy1, sxz, sx1z;
953  euclidian_ratio(rect.ymin, factor, sy, sy1);
954  euclidian_ratio(rect.xmin, factor, sxz, sx1z);
955  // loop over rows
956  const GPixel *sptr = (*src)[sy];
957  GPixel *dptr = (*this)[0];
958  for (int y=0; y<nrows; y++)
959  {
960    // loop over columns
961    int sx = sxz;
962    int sx1 = sx1z;
963    for (int x=0; x<ncolumns; x++)
964    {
965      dptr[x] = sptr[sx];
966      // next column
967      if (++sx1 >= factor)
968      {
969        sx1 = 0;
970        sx += 1;
971      }
972    }
973    // next row
974    dptr += rowsize();
975    if (++sy1 >= factor)
976    {
977      sy1 = 0;
978      sptr += src->rowsize();
979    }
980  }
981}
982
983
984static inline void
985downsample_4x4_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
986{
987  const GPixel *x = s;
988  const GPixel *y = x + sadd;
989  d[0].b = ( 11*x[0].b + 2*(x[1].b + y[0].b ) + y[1].+ 8) >> 4;
990  d[0].g = ( 11*x[0].g + 2*(x[1].g + y[0].g ) + y[1].+ 8) >> 4;
991  d[0].r = ( 11*x[0].r + 2*(x[1].r + y[0].r ) + y[1].+ 8) >> 4;
992  d[1].b = ( 7*(x[1].b + x[2].b) + y[1].b + y[2].b + 8 )     >> 4;
993  d[1].g = ( 7*(x[1].g + x[2].g) + y[1].g + y[2].g + 8 )     >> 4;
994  d[1].r = ( 7*(x[1].r + x[2].r) + y[1].r + y[2].r + 8 )     >> 4;
995  d[2].b = ( 11*x[3].b + 2*(x[2].b + y[3].b ) + y[2].+ 8) >> 4;
996  d[2].g = ( 11*x[3].g + 2*(x[2].g + y[3].g ) + y[2].+ 8) >> 4;
997  d[2].r = ( 11*x[3].r + 2*(x[2].r + y[3].r ) + y[2].+ 8) >> 4;
998  d = d + dadd;
999  x = x + sadd + sadd;
1000  d[0].b = ( 7*(x[0].b + y[0].b) + x[1].b + y[1].b + 8 )     >> 4;
1001  d[0].g = ( 7*(x[0].g + y[0].g) + x[1].g + y[1].g + 8 )     >> 4;
1002  d[0].r = ( 7*(x[0].r + y[0].r) + x[1].r + y[1].r + 8 )     >> 4;
1003  d[1].b = ( x[2].b + y[2].b + x[1].b + y[1].b + 2 )         >> 2;
1004  d[1].g = ( x[2].g + y[2].g + x[1].g + y[1].g + 2 )         >> 2;
1005  d[1].r = ( x[2].r + y[2].r + x[1].r + y[1].r + 2 )         >> 2;
1006  d[2].b = ( 7*(x[3].b + y[3].b) + x[2].b + y[2].b + 8 )     >> 4;
1007  d[2].g = ( 7*(x[3].g + y[3].g) + x[2].g + y[2].g + 8 )     >> 4;
1008  d[2].r = ( 7*(x[3].r + y[3].r) + x[2].r + y[2].r + 8 )     >> 4;
1009  d = d + dadd;
1010  y = y + sadd + sadd;
1011  d[0].b = ( 11*y[0].b + 2*(y[1].b + x[0].b ) + x[1].+ 8) >> 4;
1012  d[0].g = ( 11*y[0].g + 2*(y[1].g + x[0].g ) + x[1].+ 8) >> 4;
1013  d[0].r = ( 11*y[0].r + 2*(y[1].r + x[0].r ) + x[1].+ 8) >> 4;
1014  d[1].b = ( 7*(y[1].b + y[2].b) + x[1].b + x[2].b + 8 )     >> 4;
1015  d[1].g = ( 7*(y[1].g + y[2].g) + x[1].g + x[2].g + 8 )     >> 4;
1016  d[1].r = ( 7*(y[1].r + y[2].r) + x[1].r + x[2].r + 8 )     >> 4;
1017  d[2].b = ( 11*y[3].b + 2*(y[2].b + x[3].b ) + x[2].+ 8) >> 4;
1018  d[2].g = ( 11*y[3].g + 2*(y[2].g + x[3].g ) + x[2].+ 8) >> 4;
1019  d[2].r = ( 11*y[3].r + 2*(y[2].r + x[3].r ) + x[2].+ 8) >> 4;
1020}
1021
1022
1023static inline void
1024upsample_2x2_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
1025{
1026  const GPixel *x = s;
1027  const GPixel *y = x + sadd;
1028  d[0] = x[0];
1029  d[1].b = (x[0].b + x[1].b + 1) >> 1;
1030  d[1].g = (x[0].g + x[1].g + 1) >> 1;
1031  d[1].r = (x[0].r + x[1].r + 1) >> 1;
1032  d[2] = x[1];
1033  d = d + dadd;
1034  d[0].b = (x[0].b + y[0].b + 1) >> 1;
1035  d[0].g = (x[0].g + y[0].g + 1) >> 1;
1036  d[0].r = (x[0].r + y[0].r + 1) >> 1;
1037  d[1].b = (x[0].b + y[0].b + x[1].b + y[1].b + 2) >> 2;
1038  d[1].g = (x[0].g + y[0].g + x[1].g + y[1].g + 2) >> 2;
1039  d[1].r = (x[0].r + y[0].r + x[1].r + y[1].r + 2) >> 2;
1040  d[2].b = (x[1].b + y[1].b + 1) >> 1;
1041  d[2].g = (x[1].g + y[1].g + 1) >> 1;
1042  d[2].r = (x[1].r + y[1].r + 1) >> 1;
1043  d = d + dadd;
1044  d[0] = y[0];
1045  d[1].b = (y[0].b + y[1].b + 1) >> 1;
1046  d[1].g = (y[0].g + y[1].g + 1) >> 1;
1047  d[1].r = (y[0].r + y[1].r + 1) >> 1;
1048  d[2] = y[1];
1049}
1050
1051
1052static inline void
1053copy_to_partial(int w, int h,
1054                const GPixel *s, int sadd,
1055                GPixel *d, int dadd, int xmin, int xmax, int ymin, int ymax)
1056{
1057  int y = 0;
1058  while (y<ymin  && y<h)
1059    {
1060      y += 1;
1061      s += sadd;
1062      d += dadd;
1063    }
1064  while (y<ymax && y<h)
1065    {
1066      int x = (xmin>0 ? xmin : 0);
1067      while (x<w && x<xmax)
1068        {
1069          d[x] = s[x];
1070          x++;
1071        }
1072      y += 1;
1073      s += sadd;
1074      d += dadd;
1075    }
1076}
1077
1078
1079static inline void
1080copy_line(const GPixel *s, int smin, int smax,
1081          GPixel *d, int dmin, int dmax)
1082{
1083  int x = dmin;
1084  while (x < smin) 
1085  { 
1086    d[x] = s[smin]; 
1087    x++; 
1088  }
1089  while (x < dmax && x < smax) 
1090  { 
1091    d[x] = s[x]; 
1092    x++; 
1093  }
1094  while (x < dmax)             
1095  {
1096    d[x] = s[smax]; 
1097    x++; 
1098  }
1099}
1100
1101
1102static inline void
1103copy_from_partial(int w, int h,
1104                  const GPixel *s, int sadd, int xmin, int xmax, int ymin, int ymax,
1105                  GPixel *d, int dadd)
1106{
1107  int y = 0;
1108  s += (ymin>0 ? sadd * ymin : 0);
1109  while (y<ymin  && y<h)
1110    {
1111      copy_line(s, xmin, xmax, d, 0, w);
1112      y += 1;
1113      d += dadd;
1114    }
1115  while (y<ymax && y<h)
1116    {
1117      copy_line(s, xmin, xmax, d, 0, w);
1118      y += 1;
1119      s += sadd;
1120      d += dadd;
1121    }
1122  s -= sadd;
1123  while (y < h)
1124    {
1125      copy_line(s, xmin, xmax, d, 0, w);
1126      y += 1;
1127      d += dadd;
1128    }
1129}
1130
1131
1132
1133
1134
1135void 
1136GPixmap::downsample43(const GPixmap *src, const GRect *pdr)
1137{
1138  // check arguments
1139  int srcwidth = src->columns();
1140  int srcheight = src->rows();
1141  int destwidth = (srcwidth * 3 + 3 ) / 4;
1142  int destheight = (srcheight * 3 + 3) / 4;
1143  GRect rect(0, 0, destwidth, destheight);
1144  if (pdr != 0)
1145  {
1146    if (pdr->xmin < rect.xmin || 
1147        pdr->ymin < rect.ymin || 
1148        pdr->xmax > rect.xmax || 
1149        pdr->ymax > rect.ymax  )
1150      G_THROW( ERR_MSG("GPixmap.overflow3") );
1151    rect = *pdr;
1152    destwidth = rect.width();
1153    destheight = rect.height();
1154  }
1155  // initialize pixmap
1156  init(destheight, destwidth, 0);
1157
1158  // compute bounds
1159  int dxz, dy;   // location of bottomleft block in destination image
1160  int sxz, sy;   // location of bottomleft block in source image
1161  euclidian_ratio(rect.ymin, 3, sy, dy);
1162  euclidian_ratio(rect.xmin, 3, sxz, dxz);
1163  sxz = 4 * sxz;   
1164  sy  = 4 * sy;
1165  dxz = - dxz;
1166  dy  = - dy;
1167
1168  // prepare variables
1169  int sadd = src->rowsize();
1170  int dadd = this->rowsize();
1171  const GPixel *sptr = (*src)[0]  + sy * sadd;
1172  GPixel *dptr = (*this)[0] + dy * dadd;
1173  int s4add = 4 * sadd;
1174  int d3add = 3 * dadd;
1175
1176  // iterate over row blocks
1177  while (dy < destheight)
1178  {
1179    int sx = sxz;
1180    int dx = dxz;
1181    // iterate over column blocks
1182    while (dx < destwidth)
1183    {
1184      GPixel xin[16], xout[9];
1185
1186      if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
1187        {
1188          if (sx+4<=srcwidth && sy+4<=srcheight)
1189            {
1190              downsample_4x4_to_3x3(sptr+sx, sadd, dptr+dx, dadd);
1191            }
1192          else
1193            {
1194              copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
1195              downsample_4x4_to_3x3(xin, 4, dptr+dx, dadd);
1196            }
1197        }
1198      else
1199        {
1200          if (sx+4<=srcwidth && sy+4<=srcheight)
1201            {
1202              downsample_4x4_to_3x3(sptr+sx, sadd, xout, 3); 
1203              copy_to_partial(3,3, xout, 3, dptr+dx, dadd,-dx,destwidth-dx,-dy,destheight-dy);
1204            }
1205          else
1206            {
1207              copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
1208              downsample_4x4_to_3x3(xin, 4, xout, 3); 
1209              copy_to_partial(3,3, xout,3, dptr+dx,dadd,-dx,destwidth-dx,-dy,destheight-dy);
1210            }
1211        }
1212      // next column
1213      dx += 3;
1214      sx += 4;
1215    }
1216    // next row
1217    dy += 3;
1218    dptr += d3add;
1219    sy += 4;
1220    sptr += s4add;
1221  }
1222}
1223
1224
1225void 
1226GPixmap::upsample23(const GPixmap *src, const GRect *pdr)
1227{
1228  // check arguments
1229  int srcwidth = src->columns();
1230  int srcheight = src->rows();
1231  int destwidth = (srcwidth * 3 + 1 ) / 2;
1232  int destheight = (srcheight * 3 + 1) / 2;
1233  GRect rect(0, 0, destwidth, destheight);
1234  if (pdr != 0)
1235  {
1236    if (pdr->xmin < rect.xmin || 
1237        pdr->ymin < rect.ymin || 
1238        pdr->xmax > rect.xmax || 
1239        pdr->ymax > rect.ymax  )
1240      G_THROW( ERR_MSG("GPixmap.overflow4") );
1241    rect = *pdr;
1242    destwidth = rect.width();
1243    destheight = rect.height();
1244  }
1245  // initialize pixmap
1246  init(destheight, destwidth, 0);
1247
1248  // compute bounds
1249  int dxz, dy;   // location of bottomleft block in destination image
1250  int sxz, sy;   // location of bottomleft block in source image
1251  euclidian_ratio(rect.ymin, 3, sy, dy);
1252  euclidian_ratio(rect.xmin, 3, sxz, dxz);
1253  sxz = 2 * sxz;   
1254  sy  = 2 * sy;
1255  dxz = - dxz;
1256  dy  = - dy;
1257
1258  // prepare variables
1259  int sadd = src->rowsize();
1260  int dadd = this->rowsize();
1261  const GPixel *sptr = (*src)[0]  + sy * sadd;
1262  GPixel *dptr = (*this)[0] + dy * dadd;
1263  int s2add = 2 * sadd;
1264  int d3add = 3 * dadd;
1265
1266  // iterate over row blocks
1267  while (dy < destheight)
1268  {
1269    int sx = sxz;
1270    int dx = dxz;
1271    // iterate over column blocks
1272    while (dx < destwidth)
1273    {
1274      GPixel xin[4], xout[9];
1275
1276      if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
1277      {
1278        if (sx+2<=srcwidth && sy+2<=srcheight)
1279        {
1280          upsample_2x2_to_3x3( sptr+sx, sadd, dptr+dx, dadd);
1281        }
1282        else
1283        {
1284          copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
1285          upsample_2x2_to_3x3(xin, 2, dptr+dx, dadd);
1286        }
1287      }
1288      else
1289      {
1290        if (sx+2<=srcwidth && sy+2<=srcheight)
1291        {
1292          upsample_2x2_to_3x3( sptr+sx, sadd, xout, 3); 
1293          copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
1294        }
1295        else
1296        {
1297          copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
1298          upsample_2x2_to_3x3(xin, 2, xout, 3); 
1299          copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
1300        }
1301      }
1302      // next column
1303      dx += 3;
1304      sx += 2;
1305    }
1306    // next row
1307    dy += 3;
1308    dptr += d3add;
1309    sy += 2;
1310    sptr += s2add;
1311  }
1312}
1313
1314
1315//////////////////////////////////////////////////
1316// Blitting and attenuating
1317//////////////////////////////////////////////////
1318
1319
1320static unsigned char clip[512];
1321static bool clipok = false;
1322
1323static void
1324compute_clip()
1325{
1326  clipok = true;
1327  for (unsigned int i=0; i<sizeof(clip); i++)
1328    clip[i] = (i<256 ? i : 255);
1329}
1330
1331
1332void 
1333GPixmap::attenuate(const GBitmap *bm, int xpos, int ypos)
1334{
1335  // Check
1336  if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
1337  // Compute number of rows and columns
1338  int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
1339    xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
1340  if(xrows <= 0 || xcolumns <= 0)
1341    return;
1342  // Precompute multiplier map
1343  unsigned int multiplier[256];
1344  unsigned int maxgray = bm->get_grays() - 1;
1345  for (unsigned int i=0; i<maxgray ; i++)
1346    multiplier[i] = 0x10000 * i / maxgray;
1347  // Compute starting point
1348  const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
1349  GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
1350  // Loop over rows
1351  for (int y=0; y<xrows; y++)
1352    {
1353      // Loop over columns
1354      for (int x=0; x<xcolumns; x++)
1355        {
1356          unsigned char srcpix = src[x];
1357          // Perform pixel operation
1358          if (srcpix > 0)
1359            {
1360              if (srcpix >= maxgray)
1361                {
1362                  dst[x].b = 0;
1363                  dst[x].g = 0;
1364                  dst[x].r = 0;
1365                }
1366              else
1367                {
1368                  unsigned int level = multiplier[srcpix];
1369                  dst[x].b -=  (dst[x].b * level) >> 16;
1370                  dst[x].g -=  (dst[x].g * level) >> 16;
1371                  dst[x].r -=  (dst[x].r * level) >> 16;
1372                }
1373            }
1374        }
1375      // Next line
1376      dst += rowsize();
1377      src += bm->rowsize();
1378    }
1379}
1380
1381
1382void 
1383GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixel *color)
1384{
1385  // Check
1386  if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
1387  if (!clipok) compute_clip();
1388  if (!color) return;
1389  // Compute number of rows and columns
1390  int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
1391    xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
1392  if(xrows <= 0 || xcolumns <= 0)
1393    return;
1394  // Precompute multiplier map
1395  unsigned int multiplier[256];
1396  unsigned int maxgray = bm->get_grays() - 1;
1397  for (unsigned int i=1; i<maxgray ; i++)
1398    multiplier[i] = 0x10000 * i / maxgray;
1399  // Cache target color
1400  unsigned char gr = color->r;
1401  unsigned char gg = color->g;
1402  unsigned char gb = color->b;
1403  // Compute starting point
1404  const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
1405  GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
1406  // Loop over rows
1407  for (int y=0; y<xrows; y++)
1408    {
1409      // Loop over columns
1410      for (int x=0; x<xcolumns; x++)
1411        {
1412          unsigned char srcpix = src[x];
1413          // Perform pixel operation
1414          if (srcpix > 0)
1415            {
1416              if (srcpix >= maxgray)
1417                {
1418                  dst[x].b = clip[dst[x].b + gb];
1419                  dst[x].g = clip[dst[x].g + gg];
1420                  dst[x].r = clip[dst[x].r + gr];
1421                }
1422              else
1423                {
1424                  unsigned int level = multiplier[srcpix];
1425                  dst[x].b = clip[dst[x].b + ((gb * level) >> 16)];
1426                  dst[x].g = clip[dst[x].g + ((gg * level) >> 16)];
1427                  dst[x].r = clip[dst[x].r + ((gr * level) >> 16)];
1428                }
1429            }
1430        }
1431      // Next line
1432      dst += rowsize();
1433      src += bm->rowsize();
1434    }
1435}
1436
1437
1438void 
1439GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
1440{
1441  // Check
1442  if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
1443  if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
1444  if (!clipok) compute_clip();
1445  if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
1446    G_THROW( ERR_MSG("GPixmap.diff_size") );
1447  // Compute number of rows and columns
1448  int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
1449      xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
1450  if(xrows <= 0 || xcolumns <= 0)
1451    return;
1452  // Precompute multiplier map
1453  unsigned int multiplier[256];
1454  unsigned int maxgray = bm->get_grays() - 1;
1455  for (unsigned int i=1; i<maxgray ; i++)
1456    multiplier[i] = 0x10000 * i / maxgray;
1457  // Cache target color
1458  // Compute starting point
1459  const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
1460  const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
1461  GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
1462  // Loop over rows
1463  for (int y=0; y<xrows; y++)
1464    {
1465      // Loop over columns
1466      for (int x=0; x<xcolumns; x++)
1467        {
1468          unsigned char srcpix = src[x];
1469          // Perform pixel operation
1470          if (srcpix > 0)
1471            {
1472              if (srcpix >= maxgray)
1473                {
1474                  dst[x].b = clip[dst[x].b + src2[x].b];
1475                  dst[x].g = clip[dst[x].g + src2[x].g];
1476                  dst[x].r = clip[dst[x].r + src2[x].r];
1477                }
1478              else
1479                {
1480                  unsigned int level = multiplier[srcpix];
1481                  dst[x].b = clip[dst[x].b + ((src2[x].b * level) >> 16)];
1482                  dst[x].g = clip[dst[x].g + ((src2[x].g * level) >> 16)];
1483                  dst[x].r = clip[dst[x].r + ((src2[x].r * level) >> 16)];
1484                }
1485            }
1486        }
1487      // Next line
1488      dst += rowsize();
1489      src += bm->rowsize();
1490      src2 += color->rowsize();
1491    }
1492}
1493
1494
1495
1496void 
1497GPixmap::blend(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
1498{
1499  // Check
1500  if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
1501  if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
1502  if (!clipok) compute_clip();
1503  if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
1504    G_THROW( ERR_MSG("GPixmap.diff_size") );
1505  // Compute number of rows and columns
1506  int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
1507      xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
1508  if(xrows <= 0 || xcolumns <= 0)
1509    return;
1510  // Precompute multiplier map
1511  unsigned int multiplier[256];
1512  unsigned int maxgray = bm->get_grays() - 1;
1513  for (unsigned int i=1; i<maxgray ; i++)
1514    multiplier[i] = 0x10000 * i / maxgray;
1515  // Cache target color
1516  // Compute starting point
1517  const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
1518  const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
1519  GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
1520  // Loop over rows
1521  for (int y=0; y<xrows; y++)
1522    {
1523      // Loop over columns
1524      for (int x=0; x<xcolumns; x++)
1525        {
1526          unsigned char srcpix = src[x];
1527          // Perform pixel operation
1528          if (srcpix > 0)
1529            {
1530              if (srcpix >= maxgray)
1531                {
1532                  dst[x].b = src2[x].b;
1533                  dst[x].g = src2[x].g;
1534                  dst[x].r = src2[x].r;
1535                }
1536              else
1537                {
1538                  unsigned int level = multiplier[srcpix];
1539                  dst[x].b -= (((int)dst[x].b - (int)src2[x].b) * level) >> 16;
1540                  dst[x].g -= (((int)dst[x].g - (int)src2[x].g) * level) >> 16;
1541                  dst[x].r -= (((int)dst[x].r - (int)src2[x].r) * level) >> 16;
1542                }
1543            }
1544        }
1545      // Next line
1546      dst += rowsize();
1547      src += bm->rowsize();
1548      src2 += color->rowsize();
1549    }
1550}
1551
1552
1553
1554
1555void 
1556GPixmap::stencil(const GBitmap *bm, 
1557                const GPixmap *pm, int pms, const GRect *pmr, 
1558                double corr)
1559{
1560  // Check arguments
1561  GRect rect(0, 0, pm->columns()*pms, pm->rows()*pms);
1562  if (pmr != 0)
1563    {
1564      if (pmr->xmin < rect.xmin || 
1565          pmr->ymin < rect.ymin || 
1566          pmr->xmax > rect.xmax || 
1567          pmr->ymax > rect.ymax  )
1568        G_THROW( ERR_MSG("GPixmap.overflow5") );
1569      rect = *pmr;
1570    }
1571  // Compute number of rows
1572  int xrows = nrows;
1573  if ((int)bm->rows() < xrows)
1574    xrows = bm->rows();
1575  if (rect.height() < xrows)
1576    xrows = rect.height();
1577  // Compute number of columns
1578  int xcolumns = ncolumns;
1579  if ((int)bm->columns() < xcolumns)
1580    xcolumns = bm->columns();
1581  if (rect.width() < xcolumns)
1582    xcolumns = rect.width();
1583  // Precompute multiplier map
1584  unsigned int multiplier[256];
1585  unsigned int maxgray = bm->get_grays() - 1;
1586  for (unsigned int i=1; i<maxgray ; i++)
1587    multiplier[i] = 0x10000 * i / maxgray;
1588  // Prepare color correction table
1589  unsigned char gtable[256];
1590  color_correction_table_cache(corr, gtable);
1591  // Compute starting point in blown up foreground pixmap
1592  int fgy, fgy1, fgxz, fgx1z;
1593  euclidian_ratio(rect.ymin, pms, fgy, fgy1);
1594  euclidian_ratio(rect.xmin, pms, fgxz, fgx1z);
1595  const GPixel *fg = (*pm)[fgy];
1596  const unsigned char *src = (*bm)[0];
1597  GPixel *dst = (*this)[0];
1598  // Loop over rows
1599  for (int y=0; y<xrows; y++)
1600  {
1601    // Loop over columns
1602    int fgx = fgxz;
1603    int fgx1 = fgx1z;
1604    for (int x=0; x<xcolumns; x++)
1605    {
1606      unsigned char srcpix = src[x];
1607      // Perform pixel operation
1608      if (srcpix > 0)
1609      {
1610        if (srcpix >= maxgray)
1611        {
1612          dst[x].b = gtable[fg[fgx].b];
1613          dst[x].g = gtable[fg[fgx].g];
1614          dst[x].r = gtable[fg[fgx].r];
1615        }
1616        else
1617        {
1618          unsigned int level = multiplier[srcpix];
1619          dst[x].b -= (((int)dst[x].b - (int)gtable[fg[fgx].b]) * level) >> 16;
1620          dst[x].g -= (((int)dst[x].g - (int)gtable[fg[fgx].g]) * level) >> 16;
1621          dst[x].r -= (((int)dst[x].r - (int)gtable[fg[fgx].r]) * level) >> 16;
1622        }
1623      }
1624      // Next column
1625      if (++fgx1 >= pms)
1626      {
1627        fgx1 = 0;
1628        fgx += 1;
1629      }
1630    }
1631    // Next line
1632    dst += rowsize();
1633    src += bm->rowsize();
1634    if (++fgy1 >= pms)
1635    {
1636      fgy1 = 0;
1637      fg += pm->rowsize();
1638    } 
1639  }
1640}
1641
1642GP<GPixmap> GPixmap::rotate(int count)
1643{
1644  GP<GPixmap> newpixmap(this);
1645  count = count & 3;
1646  if(count)
1647  {
1648    if( count&0x01)
1649      newpixmap = new GPixmap(ncolumns, nrows);
1650    else
1651      newpixmap = new GPixmap(nrows, ncolumns);
1652
1653    GPixmap &dpixmap = *newpixmap;
1654
1655    GMonitorLock lock(&pixmap_monitor());
1656    switch(count)
1657    {
1658    case 3: //// rotate 90 counter clockwise
1659        {
1660            int lastrow = dpixmap.rows()-1;
1661
1662            for(int y=0; y<nrows; y++)
1663            {
1664                const GPixel *r=operator [] (y);
1665                for(int x=0,xnew=lastrow; xnew>=0; x++,xnew--)
1666                {
1667                    dpixmap[xnew][y] = r[x];
1668                }
1669            }
1670        }
1671        break;
1672    case 2: //// rotate 180 counter clockwise
1673        {
1674            int lastrow = dpixmap.rows()-1;
1675            int lastcolumn = dpixmap.columns()-1;
1676
1677            for(int y=0,ynew=lastrow; ynew>=0; y++,ynew--)
1678            {
1679                const GPixel *r=operator [] (y);
1680                GPixel *d=dpixmap[ynew];
1681                for(int xnew=lastcolumn; xnew>=0; r++,xnew--)
1682                {
1683                    d[xnew] = *r;
1684                }
1685            }
1686        }
1687        break;
1688    case 1: //// rotate 270 counter clockwise
1689        {
1690            int lastcolumn = dpixmap.columns()-1;
1691
1692            for(int y=0,ynew=lastcolumn; ynew>=0; y++,ynew--)
1693            {
1694                const GPixel *r=operator [] (y);
1695                for(int x=0; x<ncolumns; x++)
1696                {
1697                    dpixmap[x][ynew] = r[x];
1698                }
1699            }
1700        }
1701        break;
1702    }
1703  }
1704  return newpixmap;
1705}
1706
1707
1708
1709#ifdef HAVE_NAMESPACES
1710}
1711# ifndef NOT_USING_DJVU_NAMESPACE
1712using namespace DJVU;
1713# endif
1714#endif
1715
Note: See TracBrowser for help on using the repository browser.