source: trunk/libdjvu/GPixmap.cpp @ 15

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

needed libs update

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