• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

GPixmap.cpp

Go to the documentation of this file.
00001 //C-  -*- C++ -*-
00002 //C- -------------------------------------------------------------------
00003 //C- DjVuLibre-3.5
00004 //C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
00005 //C- Copyright (c) 2001  AT&T
00006 //C-
00007 //C- This software is subject to, and may be distributed under, the
00008 //C- GNU General Public License, Version 2. The license should have
00009 //C- accompanied the software or you may obtain a copy of the license
00010 //C- from the Free Software Foundation at http://www.fsf.org .
00011 //C-
00012 //C- This program is distributed in the hope that it will be useful,
00013 //C- but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //C- GNU General Public License for more details.
00016 //C- 
00017 //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
00018 //C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
00019 //C- Software authorized us to replace the original DjVu(r) Reference 
00020 //C- Library notice by the following text (see doc/lizard2002.djvu):
00021 //C-
00022 //C-  ------------------------------------------------------------------
00023 //C- | DjVu (r) Reference Library (v. 3.5)
00024 //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
00025 //C- | The DjVu Reference Library is protected by U.S. Pat. No.
00026 //C- | 6,058,214 and patents pending.
00027 //C- |
00028 //C- | This software is subject to, and may be distributed under, the
00029 //C- | GNU General Public License, Version 2. The license should have
00030 //C- | accompanied the software or you may obtain a copy of the license
00031 //C- | from the Free Software Foundation at http://www.fsf.org .
00032 //C- |
00033 //C- | The computer code originally released by LizardTech under this
00034 //C- | license and unmodified by other parties is deemed "the LIZARDTECH
00035 //C- | ORIGINAL CODE."  Subject to any third party intellectual property
00036 //C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
00037 //C- | non-exclusive license to make, use, sell, or otherwise dispose of 
00038 //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
00039 //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
00040 //C- | General Public License.   This grant only confers the right to 
00041 //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
00042 //C- | the extent such infringement is reasonably necessary to enable 
00043 //C- | recipient to make, have made, practice, sell, or otherwise dispose 
00044 //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
00045 //C- | any greater extent that may be necessary to utilize further 
00046 //C- | modifications or combinations.
00047 //C- |
00048 //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
00049 //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00050 //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
00051 //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00052 //C- +------------------------------------------------------------------
00053 // 
00054 // $Id: GPixmap.cpp,v 1.12 2004/08/06 15:11:29 leonb Exp $
00055 // $Name: release_3_5_15 $
00056 
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063 
00064 // -- Implements class PIXMAP
00065 // Author: Leon Bottou 07/1997
00066 
00067 
00068 
00069 #include "GPixmap.h"
00070 
00071 #include "GString.h"
00072 #include "GException.h"
00073 #include "ByteStream.h"
00074 #include "GRect.h"
00075 #include "GBitmap.h"
00076 #include "GThreads.h"
00077 #include "Arrays.h"
00078 #include "JPEGDecoder.h"
00079 #include <stdlib.h>
00080 #include <math.h>
00081 #include <assert.h>
00082 
00083 
00084 #ifdef HAVE_NAMESPACES
00085 namespace DJVU {
00086 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00087 }
00088 #endif
00089 #endif
00090 
00091 
00092 
00094 // ------- predefined colors
00096 
00097 
00098 const GPixel GPixel::WHITE = { 255, 255, 255 };
00099 const GPixel GPixel::BLACK = {   0,   0,   0 };
00100 const GPixel GPixel::BLUE  = { 255,   0,   0 };
00101 const GPixel GPixel::GREEN = {   0, 255,   0 };
00102 const GPixel GPixel::RED   = {   0,   0, 255 };
00103 
00104 
00106 // ----- utilities
00108 
00109 
00110 static const GPixel *
00111 new_gray_ramp(int grays,GPixel *ramp)
00112 {
00113   int color = 0xff0000;
00114   int decrement = color / (grays-1);
00115   for (int i=0; i<grays; i++)
00116     {
00117       int level = color >> 16;
00118       ramp[i].b = level;
00119       ramp[i].g = level;
00120       ramp[i].r = level;
00121       color -= decrement;
00122     }
00123   return ramp;
00124 }
00125 
00126 
00127 static inline int
00128 mini(int x, int y) 
00129 { 
00130   return (x < y ? x : y);
00131 }
00132 
00133 
00134 static inline int
00135 maxi(int x, int y) 
00136 { 
00137   return (x > y ? x : y);
00138 }
00139 
00140 
00141 static inline void 
00142 euclidian_ratio(int a, int b, int &q, int &r)
00143 {
00144   q = a / b;
00145   r = a - b*q;
00146   if (r < 0)
00147   {
00148     q -= 1;
00149     r += b;
00150   }
00151 }
00152 
00153 
00155 // global lock used by some rare operations
00157 
00158 static GMonitor &pixmap_monitor() {
00159   static GMonitor xpixmap_monitor;
00160   return xpixmap_monitor;
00161 }
00162 
00163 
00165 // constructors and destructors
00167 
00168 
00169 GPixmap::~GPixmap()
00170 {
00171   delete [] pixels_data;
00172 }
00173 
00174 void
00175 GPixmap::destroy(void)
00176 {
00177   delete [] pixels_data;
00178   pixels = pixels_data = 0;
00179 }
00180 
00181 GPixmap::GPixmap()
00182 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00183 {
00184 }
00185 
00186 GPixmap::GPixmap(int nrows, int ncolumns, const GPixel *filler)
00187 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00188 {
00189   G_TRY
00190   {
00191     init(nrows, ncolumns, filler);
00192   }
00193   G_CATCH_ALL
00194   {
00195     destroy();
00196     G_RETHROW;
00197   }
00198   G_ENDCATCH;
00199 }
00200 
00201 GPixmap::GPixmap(ByteStream &bs)
00202 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00203 {
00204   G_TRY
00205   {
00206     init(bs);
00207   }
00208   G_CATCH_ALL
00209   {
00210     destroy();
00211     G_RETHROW;
00212   }
00213   G_ENDCATCH;
00214 }
00215 
00216 GPixmap::GPixmap(const GBitmap &ref)
00217 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00218 {
00219   G_TRY
00220   {
00221     init(ref, 0);
00222   }
00223   G_CATCH_ALL
00224   {
00225     destroy();
00226     G_RETHROW;
00227   }
00228   G_ENDCATCH;
00229 }
00230 
00231 GPixmap::GPixmap(const GBitmap &ref, const GRect &rect)
00232 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00233 {
00234   G_TRY
00235   {
00236     init(ref, rect, 0);
00237   }
00238   G_CATCH_ALL
00239   {
00240     destroy();
00241     G_RETHROW;
00242   }
00243   G_ENDCATCH;
00244 }
00245 
00246 GPixmap::GPixmap(const GPixmap &ref)
00247 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00248 {
00249   G_TRY
00250   {
00251     init(ref);
00252   }
00253   G_CATCH_ALL
00254   {
00255     destroy();
00256     G_RETHROW;
00257   }
00258   G_ENDCATCH;
00259 }
00260 
00261 GPixmap::GPixmap(const GPixmap &ref, const GRect &rect)
00262 : nrows(0), ncolumns(0), pixels(0), pixels_data(0)
00263 {
00264   G_TRY
00265   {
00266     init(ref, rect);
00267   }
00268   G_CATCH_ALL
00269   {
00270     destroy();
00271     G_RETHROW;
00272   }
00273   G_ENDCATCH;
00274 }
00275 
00276 
00277 
00279 // Initialization
00281 
00282 
00283 void 
00284 GPixmap::init(int arows, int acolumns, const GPixel *filler)
00285 {
00286   destroy();
00287   nrows = arows;
00288   ncolumns = acolumns;
00289   nrowsize = acolumns;
00290   int npix = nrows * nrowsize;
00291   if (npix > 0)
00292   {
00293     pixels = pixels_data = new GPixel[npix];
00294     if (filler)
00295     { 
00296       while (--npix>=0) 
00297         pixels_data[npix] = *filler;
00298     }
00299   }
00300 }
00301 
00302 
00303 void 
00304 GPixmap::init(const GBitmap &ref, const GPixel *userramp)
00305 {
00306   init(ref.rows(), ref.columns(), 0);
00307   GPixel *xramp;
00308   GPBuffer<GPixel> gxramp(xramp);
00309   if (nrows>0 && ncolumns>0)
00310   {
00311     // Create pixel ramp
00312     const GPixel *ramp = userramp;
00313     if (!userramp)
00314     {
00315           gxramp.resize(256);
00316           gxramp.clear();
00317       ramp = new_gray_ramp(ref.get_grays(),xramp);
00318     }
00319     // Copy pixels
00320     for (int y=0; y<nrows; y++)
00321     {
00322       GPixel *dst = (*this)[y];
00323       const unsigned char *src = ref[y];
00324       for (int x=0; x<ncolumns; x++)
00325         dst[x] = ramp[ src[x] ];
00326     }
00327     // Free ramp
00328 //    if (!userramp)
00329 //      delete [] (GPixel*)ramp;
00330   }
00331 }
00332 
00333 
00334 void 
00335 GPixmap::init(const GBitmap &ref, const GRect &rect, const GPixel *userramp)
00336 {
00337   init(rect.height(), rect.width(), 0);
00338   // compute destination rectangle
00339   GRect rect2(0, 0, ref.columns(), ref.rows() );
00340   rect2.intersect(rect2, rect);
00341   rect2.translate(-rect.xmin, -rect.ymin);
00342   // copy bits
00343   if (! rect2.isempty())
00344   {
00345     GPixel *xramp;
00346     GPBuffer<GPixel> gxramp(xramp);
00347     // allocate ramp
00348     const GPixel *ramp = userramp;
00349     if (!userramp)
00350     {
00351       gxramp.resize(256);
00352           gxramp.clear();
00353           ramp = new_gray_ramp(ref.get_grays(),xramp);
00354     }
00355     // copy pixels
00356     for (int y=rect2.ymin; y<rect2.ymax; y++)
00357     {
00358       GPixel *dst = (*this)[y];
00359       const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
00360       for (int x=rect2.xmin; x<rect2.xmax; x++)
00361         dst[x] = ramp[ src[x] ];
00362     }
00363     // free ramp
00364 //    if (!userramp)
00365 //      delete [] (GPixel*) ramp;
00366   }
00367 }
00368 
00369 
00370 void 
00371 GPixmap::init(const GPixmap &ref)
00372 {
00373   init(ref.rows(), ref.columns(), 0);
00374   if (nrows>0 && ncolumns>0)
00375   {
00376     for (int y=0; y<nrows; y++)
00377     {
00378       GPixel *dst = (*this)[y];
00379       const GPixel *src = ref[y];
00380       for (int x=0; x<ncolumns; x++)
00381         dst[x] = src[x];
00382     }
00383   }
00384 }
00385 
00386 
00387 void 
00388 GPixmap::init(const GPixmap &ref, const GRect &rect)
00389 {
00390   init(rect.height(), rect.width(), 0);
00391   // compute destination rectangle
00392   GRect rect2(0, 0, ref.columns(), ref.rows() );
00393   rect2.intersect(rect2, rect);
00394   rect2.translate(-rect.xmin, -rect.ymin);
00395   // copy bits
00396   if (! rect2.isempty())
00397   {
00398     for (int y=rect2.ymin; y<rect2.ymax; y++)
00399     {
00400       GPixel *dst = (*this)[y];
00401       const GPixel *src = ref[y+rect.ymin] + rect.xmin;
00402       for (int x=rect2.xmin; x<rect2.xmax; x++)
00403         dst[x] = src[x];
00404     }
00405   }
00406 }
00407 
00408 
00409 void 
00410 GPixmap::donate_data(GPixel *data, int w, int h)
00411 {
00412   destroy();
00413   nrows = h;
00414   ncolumns = w;
00415   nrowsize = w;
00416   pixels_data=pixels=data;
00417 }
00418 
00419 
00420 GPixel *
00421 GPixmap::take_data(size_t &offset)
00422 {
00423   GPixel *ret = pixels_data;
00424   pixels_data = 0;
00425   offset = 0;
00426   return ret;
00427 }
00428 
00429 
00430 
00432 // Save and load ppm files
00434 
00435 
00436 static unsigned int 
00437 read_integer(char &c, ByteStream &bs)
00438 {
00439   unsigned int x = 0;
00440   // eat blank before integer
00441   while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#') 
00442     {
00443       if (c=='#') 
00444         do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
00445       c = 0; 
00446       bs.read(&c, 1);
00447     }
00448   // check integer
00449   if (c<'0' || c>'9')
00450     G_THROW( ERR_MSG("GPixmap.no_int") );
00451   // eat integer
00452   while (c>='0' && c<='9') 
00453     {
00454       x = x*10 + c - '0';
00455       c = 0;
00456       bs.read(&c, 1);
00457     }
00458   return x;
00459 }
00460 
00461 
00462 void 
00463 GPixmap::init(ByteStream &bs)
00464 {
00465   // Read header
00466   int raw = 0;
00467   char magic[2];
00468   magic[0] = magic[1] = 0;
00469   bs.readall((void*)magic, sizeof(magic));
00470   if (magic[0]=='P' && magic[1]=='3')
00471   {
00472     raw = 0;
00473   }else if (magic[0]=='P' && magic[1]=='6')
00474   {
00475     raw = 1;
00476   }else
00477   {
00478 #ifdef NEED_JPEG_DECODER
00479     bs.seek(0L);
00480     JPEGDecoder::decode(bs,*this);
00481     return;
00482 #else // NEED_JPEG_DECODER
00483   
00484     G_THROW( ERR_MSG("GPixmap.unk_PPM") );
00485 #endif // NEED_JPEG_DECODER
00486   }
00487   // Read image size
00488   char lookahead = '\n';
00489   int acolumns = read_integer(lookahead, bs);
00490   int arows = read_integer(lookahead, bs);
00491   int maxval = read_integer(lookahead, bs);
00492   if (maxval > 255)
00493     G_THROW("Cannot read PPM with depth greater than 24 bits.");
00494   init(arows, acolumns, 0);
00495   // Read image data
00496   if (raw)
00497   {
00498     GTArray<unsigned char> line(ncolumns*3);
00499     for (int y=nrows-1; y>=0; y--) 
00500       {
00501         GPixel *p = (*this)[y];
00502         unsigned char *rgb = &line[0];
00503         if ( bs.readall((void*)rgb, ncolumns*3) < (size_t)(ncolumns*3))
00504           G_THROW( ByteStream::EndOfFile );
00505         for (int x=0; x<ncolumns; x+=1, rgb+=3)
00506           {
00507             p[x].r = rgb[0];
00508             p[x].g = rgb[1];
00509             p[x].b = rgb[2];
00510           }
00511       }
00512   }
00513   else
00514   {
00515     for (int y=nrows-1; y>=0; y--) 
00516     {
00517       GPixel *p = (*this)[y];
00518       for (int x=0; x<ncolumns; x++)
00519       {
00520         p[x].r = read_integer(lookahead, bs);
00521         p[x].g = read_integer(lookahead, bs);
00522         p[x].b = read_integer(lookahead, bs);
00523       }
00524     }
00525   }
00526   // Process small values of maxval
00527   if (maxval>0 && maxval<255)
00528   {
00529     char table[256];
00530     for (int i=0; i<256; i++)
00531       table[i] = (i<maxval ? (255*i + maxval/2) / maxval : 255);
00532     for (int y=0; y<nrows; y++)
00533     {
00534       GPixel *p = (*this)[y];
00535       for (int x=0; x<ncolumns; x++)
00536       {
00537         p[x].r = table[p[x].r];
00538         p[x].g = table[p[x].g];
00539         p[x].b = table[p[x].b];
00540       }
00541     }
00542   }
00543 }
00544 
00545 
00546 void 
00547 GPixmap::save_ppm(ByteStream &bs, int raw) const
00548 {
00549   GUTF8String head;
00550   head.format("P%c\n%d %d\n255\n", (raw ? '6' : '3'), ncolumns, nrows);
00551   bs.writall((void*)(const char *)head, head.length());
00552   if (raw)
00553     {
00554       int rowsize = ncolumns+ncolumns+ncolumns;
00555       GTArray<unsigned char> xrgb(rowsize);
00556       for (int y=nrows-1; y>=0; y--) 
00557         {
00558           const GPixel *p = (*this)[y];
00559           unsigned char *d = xrgb;
00560           for (int x=0; x<ncolumns; x++) 
00561             {
00562               *d++ = p[x].r;
00563               *d++ = p[x].g;
00564               *d++ = p[x].b;
00565             }
00566           bs.writall((void*)(unsigned char*)xrgb, ncolumns * 3);
00567         }
00568     }
00569   else
00570     {
00571       for (int y=nrows-1; y>=0; y--) 
00572         {
00573           const GPixel *p = (*this)[y];
00574           unsigned char eol='\n';
00575           for (int x=0; x<ncolumns; )
00576             {
00577               head.format("%d %d %d  ", p[x].r, p[x].g, p[x].b);
00578               bs.writall((void*)(const char *)head, head.length());
00579               x += 1;
00580               if (x==ncolumns || (x&0x7)==0) 
00581                 bs.write((void*)&eol, 1);          
00582             }
00583         }
00584     }
00585 }
00586 
00587 
00588 
00589 
00591 // Color correction
00593 
00594 
00595 static void
00596 color_correction_table(double gamma, unsigned char gtable[256] )
00597 {
00598   // Check argument
00599   if (gamma<0.1 || gamma>10.0)
00600     G_THROW( ERR_MSG("GPixmap.bad_param") );
00601   if (gamma<1.001 && gamma>0.999)
00602     {
00603       // Trivial correction
00604       for (int i=0; i<256; i++)
00605         gtable[i] = i;
00606     }
00607   else
00608     {
00609       // Must compute the correction
00610       for (int i=0; i<256; i++)
00611         {
00612           double x = (double)(i)/255.0;
00613 #ifdef BEZIERGAMMA
00614           double t = ( sqrt(1.0+(gamma*gamma-1.0)*x) - 1.0 ) / (gamma - 1.0);
00615           x = ( (1.0 - gamma)*t + 2.0 * gamma ) * t / (gamma + 1.0);
00616 #else
00617           x = pow(x, 1.0/gamma);        
00618 #endif
00619           gtable[i] = (int) floor(255.0 * x + 0.5);
00620         }
00621       // Make sure that min and max values are exactly black or white
00622       gtable[0] = 0;
00623       gtable[255] = 255;
00624     }
00625 }
00626 
00627 static void
00628 color_correction_table_cache(double gamma, unsigned char gtable[256] )
00629 {
00630   // Compute color correction table
00631   if (gamma<1.001 && gamma>0.999)
00632     {
00633       color_correction_table(gamma, gtable);
00634     }
00635   else
00636     {
00637       static double lgamma = -1.0;
00638       static unsigned char ctable[256];
00639       GMonitorLock lock(&pixmap_monitor());
00640       if (gamma != lgamma)
00641         {
00642           color_correction_table(gamma, ctable);
00643           lgamma = gamma;
00644         }
00645       memcpy(gtable, ctable, 256*sizeof(unsigned char));
00646     }
00647 }
00648 
00649 void 
00650 GPixmap::color_correct(double gamma_correction)
00651 {
00652   // Trivial corrections
00653   if (gamma_correction>0.999 && gamma_correction<1.001)
00654     return;
00655   // Compute correction table
00656   unsigned char gtable[256];
00657   color_correction_table_cache(gamma_correction, gtable);
00658   // Perform correction
00659   for (int y=0; y<nrows; y++)
00660   {
00661     GPixel *pix = (*this)[y];
00662     for (int x=0; x<ncolumns; x++, pix++)
00663     {
00664       pix->r = gtable[ pix->r ];
00665       pix->g = gtable[ pix->g ];
00666       pix->b = gtable[ pix->b ];
00667     }
00668   }
00669 }
00670 
00671 
00672 void 
00673 GPixmap::color_correct(double gamma_correction, GPixel *pix, int npixels)
00674 {
00675   // Trivial corrections
00676   if (gamma_correction>0.999 && gamma_correction<1.001)
00677     return;
00678   // Compute correction table
00679   unsigned char gtable[256];
00680   color_correction_table_cache(gamma_correction, gtable);
00681   // Perform correction
00682   while (--npixels>=0)
00683     {
00684       pix->r = gtable[pix->r];
00685       pix->g = gtable[pix->g];
00686       pix->b = gtable[pix->b];
00687       pix++;
00688     }
00689 }
00690 
00691 
00692 
00694 // Dithering
00696 
00697 
00698 void
00699 GPixmap::ordered_666_dither(int xmin, int ymin)
00700 {
00701   static unsigned char quantize[256+0x33+0x33];
00702   static unsigned char *quant = quantize + 0x33;
00703   static char  dither_ok = 0;
00704   static short dither[16][16] = 
00705   {
00706     {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
00707     { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
00708     {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
00709     { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
00710     {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
00711     { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
00712     {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
00713     { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
00714     {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
00715     { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
00716     {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
00717     { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
00718     {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
00719     { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
00720     {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
00721     { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
00722   };
00723   // Prepare tables
00724   if (!dither_ok)
00725   {
00726     int i, j;
00727     for (i=0; i<16; i++)
00728       for (j=0; j<16; j++)
00729         dither[i][j] = ((255 - 2*dither[i][j]) * 0x33) / 512;    
00730     j = -0x33;
00731     for (i=0x19; i<256; i+=0x33)
00732       while (j <= i)
00733         quant[j++] = i-0x19;
00734     assert(i-0x19 == 0xff);
00735     while (j< 256+0x33)
00736       quant[j++] = i-0x19;
00737     dither_ok = 1;
00738   }
00739   // Go dithering
00740   for (int y=0; y<nrows; y++)
00741   {
00742     GPixel *pix = (*this)[y];
00743     for (int x=0; x<ncolumns; x++, pix++)
00744     {
00745       pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
00746       pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
00747       pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
00748     }
00749   }
00750 }
00751 
00752 void
00753 GPixmap::ordered_32k_dither(int xmin, int ymin)
00754 {
00755   static unsigned char quantize[256+8+8];
00756   static unsigned char *quant = quantize + 8;
00757   static char  dither_ok = 0;
00758   static short dither[16][16] = 
00759   {
00760     {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 },
00761     { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
00762     {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
00763     { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
00764     {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 },
00765     { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
00766     {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
00767     { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
00768     {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 },
00769     { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
00770     {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
00771     { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
00772     {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 },
00773     { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
00774     {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
00775     { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
00776   };
00777   // Prepare tables
00778   if (!dither_ok)
00779   {
00780     int i, j;
00781     for (i=0; i<16; i++)
00782       for (j=0; j<16; j++)
00783         dither[i][j] = ((255 - 2*dither[i][j]) * 8) / 512;    
00784     j = -8;
00785     for (i=3; i<256; i+=8)
00786       while (j <= i)
00787         quant[j++] = i;
00788     while (j<256+8)
00789       quant[j++] = 0xff;
00790     dither_ok = 1;
00791   }
00792   // Go dithering
00793   for (int y=0; y<nrows; y++)
00794   {
00795     GPixel *pix = (*this)[y];
00796     for (int x=0; x<ncolumns; x++, pix++)
00797     {
00798       pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
00799       pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
00800       pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
00801     }
00802   }
00803 }
00804 
00805 
00807 // Upsample Downsample
00809 
00810 
00811 void  
00812 GPixmap::downsample(const GPixmap *src, int factor, const GRect *pdr)
00813 {
00814   // check arguments
00815   GRect rect(0, 0, (src->columns()+factor-1)/factor, (src->rows()+factor-1)/factor);
00816   if (pdr != 0)
00817   {
00818     if (pdr->xmin < rect.xmin || 
00819         pdr->ymin < rect.ymin || 
00820         pdr->xmax > rect.xmax || 
00821         pdr->ymax > rect.ymax  )
00822       G_THROW( ERR_MSG("GPixmap.overflow1") );
00823     rect = *pdr;
00824   }
00825 
00826   // precompute inverse map
00827   static int invmap[256];
00828   static int invmapok = 0;
00829   if (! invmapok)
00830   {
00831     invmapok = 1;
00832     for (int i=1; i<(int)(sizeof(invmap)/sizeof(int)); i++)
00833       invmap[i] = 0x10000 / i;
00834   }
00835   
00836   // initialise pixmap
00837   init(rect.height(), rect.width(), 0);
00838 
00839   // determine starting and ending points in source rectangle
00840   int sy = rect.ymin * factor;
00841   int sxz = rect.xmin * factor;
00842 
00843 
00844   // loop over source rows
00845   const GPixel *sptr = (*src)[sy];
00846   GPixel *dptr = (*this)[0];
00847   for (int y=0; y<nrows; y++)
00848   {
00849     int sx = sxz;
00850     // loop over source columns
00851     for (int x=0; x<ncolumns; x++)
00852     {
00853       int r=0, g=0, b=0, s=0;
00854       // compute average bounds
00855       const GPixel *ksptr = sptr;
00856       int lsy = sy + factor;
00857       if (lsy > (int)src->rows())
00858         lsy = (int)src->rows();
00859       int lsx = sx + factor;
00860       if (lsx > (int)src->columns())
00861         lsx = (int)src->columns();
00862       // compute average
00863       for (int rsy=sy; rsy<lsy; rsy++)
00864       {
00865         for (int rsx = sx; rsx<lsx; rsx++)
00866         {
00867           r += ksptr[rsx].r;
00868           g += ksptr[rsx].g;
00869           b += ksptr[rsx].b;
00870           s += 1;
00871         }
00872         ksptr += src->rowsize();
00873       }
00874       // set pixel color
00875       if (s >= (int)(sizeof(invmap)/sizeof(int)))
00876       {
00877         dptr[x].r = r / s;
00878         dptr[x].g = g / s;
00879         dptr[x].b = b / s;
00880       }
00881       else
00882       {
00883         dptr[x].r = (r*invmap[s] + 0x8000) >> 16;
00884         dptr[x].g = (g*invmap[s] + 0x8000) >> 16;
00885         dptr[x].b = (b*invmap[s] + 0x8000) >> 16;
00886       }
00887       // next column
00888       sx = sx + factor;
00889     }
00890     // next row
00891     sy = sy + factor;
00892     sptr = sptr + factor * src->rowsize();
00893     dptr = dptr + rowsize();
00894   }
00895 }
00896 
00897 void  
00898 GPixmap::upsample(const GPixmap *src, int factor, const GRect *pdr)
00899 {
00900   // check arguments
00901   GRect rect(0, 0, src->columns()*factor, src->rows()*factor);
00902   if (pdr != 0)
00903   {
00904     if (pdr->xmin < rect.xmin || 
00905         pdr->ymin < rect.ymin || 
00906         pdr->xmax > rect.xmax || 
00907         pdr->ymax > rect.ymax  )
00908       G_THROW( ERR_MSG("GPixmap.overflow2") );
00909     rect = *pdr;
00910   }
00911   // initialise pixmap
00912   init(rect.height(), rect.width(), 0);
00913   // compute starting point in source rectangle
00914   int sy, sy1, sxz, sx1z;
00915   euclidian_ratio(rect.ymin, factor, sy, sy1);
00916   euclidian_ratio(rect.xmin, factor, sxz, sx1z);
00917   // loop over rows
00918   const GPixel *sptr = (*src)[sy];
00919   GPixel *dptr = (*this)[0];
00920   for (int y=0; y<nrows; y++)
00921   {
00922     // loop over columns
00923     int sx = sxz;
00924     int sx1 = sx1z;
00925     for (int x=0; x<ncolumns; x++)
00926     {
00927       dptr[x] = sptr[sx];
00928       // next column
00929       if (++sx1 >= factor)
00930       {
00931         sx1 = 0;
00932         sx += 1;
00933       }
00934     }
00935     // next row
00936     dptr += rowsize();
00937     if (++sy1 >= factor)
00938     {
00939       sy1 = 0;
00940       sptr += src->rowsize();
00941     }
00942   }
00943 }
00944 
00945 
00946 static inline void
00947 downsample_4x4_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
00948 {
00949   const GPixel *x = s;
00950   const GPixel *y = x + sadd;
00951   d[0].b = ( 11*x[0].b + 2*(x[1].b + y[0].b ) + y[1].b  + 8) >> 4;
00952   d[0].g = ( 11*x[0].g + 2*(x[1].g + y[0].g ) + y[1].g  + 8) >> 4;
00953   d[0].r = ( 11*x[0].r + 2*(x[1].r + y[0].r ) + y[1].r  + 8) >> 4;
00954   d[1].b = ( 7*(x[1].b + x[2].b) + y[1].b + y[2].b + 8 )     >> 4;
00955   d[1].g = ( 7*(x[1].g + x[2].g) + y[1].g + y[2].g + 8 )     >> 4;
00956   d[1].r = ( 7*(x[1].r + x[2].r) + y[1].r + y[2].r + 8 )     >> 4;
00957   d[2].b = ( 11*x[3].b + 2*(x[2].b + y[3].b ) + y[2].b  + 8) >> 4;
00958   d[2].g = ( 11*x[3].g + 2*(x[2].g + y[3].g ) + y[2].g  + 8) >> 4;
00959   d[2].r = ( 11*x[3].r + 2*(x[2].r + y[3].r ) + y[2].r  + 8) >> 4;
00960   d = d + dadd;
00961   x = x + sadd + sadd;
00962   d[0].b = ( 7*(x[0].b + y[0].b) + x[1].b + y[1].b + 8 )     >> 4;
00963   d[0].g = ( 7*(x[0].g + y[0].g) + x[1].g + y[1].g + 8 )     >> 4;
00964   d[0].r = ( 7*(x[0].r + y[0].r) + x[1].r + y[1].r + 8 )     >> 4;
00965   d[1].b = ( x[2].b + y[2].b + x[1].b + y[1].b + 2 )         >> 2;
00966   d[1].g = ( x[2].g + y[2].g + x[1].g + y[1].g + 2 )         >> 2;
00967   d[1].r = ( x[2].r + y[2].r + x[1].r + y[1].r + 2 )         >> 2;
00968   d[2].b = ( 7*(x[3].b + y[3].b) + x[2].b + y[2].b + 8 )     >> 4;
00969   d[2].g = ( 7*(x[3].g + y[3].g) + x[2].g + y[2].g + 8 )     >> 4;
00970   d[2].r = ( 7*(x[3].r + y[3].r) + x[2].r + y[2].r + 8 )     >> 4;
00971   d = d + dadd;
00972   y = y + sadd + sadd;
00973   d[0].b = ( 11*y[0].b + 2*(y[1].b + x[0].b ) + x[1].b  + 8) >> 4;
00974   d[0].g = ( 11*y[0].g + 2*(y[1].g + x[0].g ) + x[1].g  + 8) >> 4;
00975   d[0].r = ( 11*y[0].r + 2*(y[1].r + x[0].r ) + x[1].r  + 8) >> 4;
00976   d[1].b = ( 7*(y[1].b + y[2].b) + x[1].b + x[2].b + 8 )     >> 4;
00977   d[1].g = ( 7*(y[1].g + y[2].g) + x[1].g + x[2].g + 8 )     >> 4;
00978   d[1].r = ( 7*(y[1].r + y[2].r) + x[1].r + x[2].r + 8 )     >> 4;
00979   d[2].b = ( 11*y[3].b + 2*(y[2].b + x[3].b ) + x[2].b  + 8) >> 4;
00980   d[2].g = ( 11*y[3].g + 2*(y[2].g + x[3].g ) + x[2].g  + 8) >> 4;
00981   d[2].r = ( 11*y[3].r + 2*(y[2].r + x[3].r ) + x[2].r  + 8) >> 4;
00982 }
00983 
00984 
00985 static inline void
00986 upsample_2x2_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
00987 {
00988   const GPixel *x = s;
00989   const GPixel *y = x + sadd;
00990   d[0] = x[0];
00991   d[1].b = (x[0].b + x[1].b + 1) >> 1;
00992   d[1].g = (x[0].g + x[1].g + 1) >> 1;
00993   d[1].r = (x[0].r + x[1].r + 1) >> 1;
00994   d[2] = x[1];
00995   d = d + dadd;
00996   d[0].b = (x[0].b + y[0].b + 1) >> 1;
00997   d[0].g = (x[0].g + y[0].g + 1) >> 1;
00998   d[0].r = (x[0].r + y[0].r + 1) >> 1;
00999   d[1].b = (x[0].b + y[0].b + x[1].b + y[1].b + 2) >> 2;
01000   d[1].g = (x[0].g + y[0].g + x[1].g + y[1].g + 2) >> 2;
01001   d[1].r = (x[0].r + y[0].r + x[1].r + y[1].r + 2) >> 2;
01002   d[2].b = (x[1].b + y[1].b + 1) >> 1;
01003   d[2].g = (x[1].g + y[1].g + 1) >> 1;
01004   d[2].r = (x[1].r + y[1].r + 1) >> 1;
01005   d = d + dadd;
01006   d[0] = y[0];
01007   d[1].b = (y[0].b + y[1].b + 1) >> 1;
01008   d[1].g = (y[0].g + y[1].g + 1) >> 1;
01009   d[1].r = (y[0].r + y[1].r + 1) >> 1;
01010   d[2] = y[1];
01011 }
01012 
01013 
01014 static inline void
01015 copy_to_partial(int w, int h,
01016                 const GPixel *s, int sadd,
01017                 GPixel *d, int dadd, int xmin, int xmax, int ymin, int ymax)
01018 {
01019   int y = 0;
01020   while (y<ymin  && y<h)
01021     {
01022       y += 1;
01023       s += sadd;
01024       d += dadd;
01025     }
01026   while (y<ymax && y<h)
01027     {
01028       int x = (xmin>0 ? xmin : 0);
01029       while (x<w && x<xmax)
01030         {
01031           d[x] = s[x];
01032           x++;
01033         }
01034       y += 1;
01035       s += sadd;
01036       d += dadd;
01037     }
01038 }
01039 
01040 
01041 static inline void
01042 copy_line(const GPixel *s, int smin, int smax,
01043           GPixel *d, int dmin, int dmax)
01044 {
01045   int x = dmin;
01046   while (x < smin) 
01047   { 
01048     d[x] = s[smin]; 
01049     x++; 
01050   }
01051   while (x < dmax && x < smax)  
01052   { 
01053     d[x] = s[x]; 
01054     x++; 
01055   }
01056   while (x < dmax)              
01057   {
01058     d[x] = s[smax]; 
01059     x++; 
01060   }
01061 }
01062 
01063 
01064 static inline void
01065 copy_from_partial(int w, int h,
01066                   const GPixel *s, int sadd, int xmin, int xmax, int ymin, int ymax,
01067                   GPixel *d, int dadd)
01068 {
01069   int y = 0;
01070   s += (ymin>0 ? sadd * ymin : 0);
01071   while (y<ymin  && y<h)
01072     {
01073       copy_line(s, xmin, xmax, d, 0, w);
01074       y += 1;
01075       d += dadd;
01076     }
01077   while (y<ymax && y<h)
01078     {
01079       copy_line(s, xmin, xmax, d, 0, w);
01080       y += 1;
01081       s += sadd;
01082       d += dadd;
01083     }
01084   s -= sadd;
01085   while (y < h)
01086     {
01087       copy_line(s, xmin, xmax, d, 0, w);
01088       y += 1;
01089       d += dadd;
01090     }
01091 }
01092 
01093 
01094 
01095 
01096 
01097 void  
01098 GPixmap::downsample43(const GPixmap *src, const GRect *pdr)
01099 {
01100   // check arguments
01101   int srcwidth = src->columns();
01102   int srcheight = src->rows();
01103   int destwidth = (srcwidth * 3 + 3 ) / 4;
01104   int destheight = (srcheight * 3 + 3) / 4;
01105   GRect rect(0, 0, destwidth, destheight);
01106   if (pdr != 0)
01107   {
01108     if (pdr->xmin < rect.xmin || 
01109         pdr->ymin < rect.ymin || 
01110         pdr->xmax > rect.xmax || 
01111         pdr->ymax > rect.ymax  )
01112       G_THROW( ERR_MSG("GPixmap.overflow3") );
01113     rect = *pdr;
01114     destwidth = rect.width();
01115     destheight = rect.height();
01116   }
01117   // initialize pixmap
01118   init(destheight, destwidth, 0);
01119 
01120   // compute bounds
01121   int dxz, dy;   // location of bottomleft block in destination image
01122   int sxz, sy;   // location of bottomleft block in source image
01123   euclidian_ratio(rect.ymin, 3, sy, dy);
01124   euclidian_ratio(rect.xmin, 3, sxz, dxz);
01125   sxz = 4 * sxz;   
01126   sy  = 4 * sy;
01127   dxz = - dxz;
01128   dy  = - dy;
01129 
01130   // prepare variables
01131   int sadd = src->rowsize();
01132   int dadd = this->rowsize();
01133   const GPixel *sptr = (*src)[0]  + sy * sadd;
01134   GPixel *dptr = (*this)[0] + dy * dadd;
01135   int s4add = 4 * sadd;
01136   int d3add = 3 * dadd;
01137 
01138   // iterate over row blocks
01139   while (dy < destheight)
01140   {
01141     int sx = sxz;
01142     int dx = dxz;
01143     // iterate over column blocks
01144     while (dx < destwidth)
01145     {
01146       GPixel xin[16], xout[9];
01147 
01148       if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
01149         {
01150           if (sx+4<=srcwidth && sy+4<=srcheight)
01151             {
01152               downsample_4x4_to_3x3(sptr+sx, sadd, dptr+dx, dadd);
01153             }
01154           else
01155             {
01156               copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
01157               downsample_4x4_to_3x3(xin, 4, dptr+dx, dadd);
01158             }
01159         }
01160       else
01161         {
01162           if (sx+4<=srcwidth && sy+4<=srcheight)
01163             {
01164               downsample_4x4_to_3x3(sptr+sx, sadd, xout, 3);  
01165               copy_to_partial(3,3, xout, 3, dptr+dx, dadd,-dx,destwidth-dx,-dy,destheight-dy);
01166             }
01167           else
01168             {
01169               copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
01170               downsample_4x4_to_3x3(xin, 4, xout, 3);  
01171               copy_to_partial(3,3, xout,3, dptr+dx,dadd,-dx,destwidth-dx,-dy,destheight-dy);
01172             }
01173         }
01174       // next column
01175       dx += 3;
01176       sx += 4;
01177     }
01178     // next row
01179     dy += 3;
01180     dptr += d3add;
01181     sy += 4;
01182     sptr += s4add;
01183   }
01184 }
01185 
01186 
01187 void  
01188 GPixmap::upsample23(const GPixmap *src, const GRect *pdr)
01189 {
01190   // check arguments
01191   int srcwidth = src->columns();
01192   int srcheight = src->rows();
01193   int destwidth = (srcwidth * 3 + 1 ) / 2;
01194   int destheight = (srcheight * 3 + 1) / 2;
01195   GRect rect(0, 0, destwidth, destheight);
01196   if (pdr != 0)
01197   {
01198     if (pdr->xmin < rect.xmin || 
01199         pdr->ymin < rect.ymin || 
01200         pdr->xmax > rect.xmax || 
01201         pdr->ymax > rect.ymax  )
01202       G_THROW( ERR_MSG("GPixmap.overflow4") );
01203     rect = *pdr;
01204     destwidth = rect.width();
01205     destheight = rect.height();
01206   }
01207   // initialize pixmap
01208   init(destheight, destwidth, 0);
01209 
01210   // compute bounds
01211   int dxz, dy;   // location of bottomleft block in destination image
01212   int sxz, sy;   // location of bottomleft block in source image
01213   euclidian_ratio(rect.ymin, 3, sy, dy);
01214   euclidian_ratio(rect.xmin, 3, sxz, dxz);
01215   sxz = 2 * sxz;   
01216   sy  = 2 * sy;
01217   dxz = - dxz;
01218   dy  = - dy;
01219 
01220   // prepare variables
01221   int sadd = src->rowsize();
01222   int dadd = this->rowsize();
01223   const GPixel *sptr = (*src)[0]  + sy * sadd;
01224   GPixel *dptr = (*this)[0] + dy * dadd;
01225   int s2add = 2 * sadd;
01226   int d3add = 3 * dadd;
01227 
01228   // iterate over row blocks
01229   while (dy < destheight)
01230   {
01231     int sx = sxz;
01232     int dx = dxz;
01233     // iterate over column blocks
01234     while (dx < destwidth)
01235     {
01236       GPixel xin[4], xout[9];
01237 
01238       if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
01239       {
01240         if (sx+2<=srcwidth && sy+2<=srcheight)
01241         {
01242           upsample_2x2_to_3x3( sptr+sx, sadd, dptr+dx, dadd);
01243         }
01244         else
01245         {
01246           copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
01247           upsample_2x2_to_3x3(xin, 2, dptr+dx, dadd);
01248         }
01249       }
01250       else
01251       {
01252         if (sx+2<=srcwidth && sy+2<=srcheight)
01253         {
01254           upsample_2x2_to_3x3( sptr+sx, sadd, xout, 3);  
01255           copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
01256         }
01257         else
01258         {
01259           copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
01260           upsample_2x2_to_3x3(xin, 2, xout, 3);  
01261           copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
01262         }
01263       }
01264       // next column
01265       dx += 3;
01266       sx += 2;
01267     }
01268     // next row
01269     dy += 3;
01270     dptr += d3add;
01271     sy += 2;
01272     sptr += s2add;
01273   }
01274 }
01275 
01276 
01278 // Blitting and attenuating
01280 
01281 
01282 static unsigned char clip[512];
01283 static bool clipok = false;
01284 
01285 static void
01286 compute_clip()
01287 {
01288   clipok = true;
01289   for (unsigned int i=0; i<sizeof(clip); i++)
01290     clip[i] = (i<256 ? i : 255);
01291 }
01292 
01293 
01294 void 
01295 GPixmap::attenuate(const GBitmap *bm, int xpos, int ypos)
01296 {
01297   // Check
01298   if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01299   // Compute number of rows and columns
01300   int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
01301     xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
01302   if(xrows <= 0 || xcolumns <= 0)
01303     return;
01304   // Precompute multiplier map
01305   unsigned int multiplier[256];
01306   unsigned int maxgray = bm->get_grays() - 1;
01307   for (unsigned int i=0; i<maxgray ; i++)
01308     multiplier[i] = 0x10000 * i / maxgray;
01309   // Compute starting point
01310   const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
01311   GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
01312   // Loop over rows
01313   for (int y=0; y<xrows; y++)
01314     {
01315       // Loop over columns
01316       for (int x=0; x<xcolumns; x++)
01317         {
01318           unsigned char srcpix = src[x];
01319           // Perform pixel operation
01320           if (srcpix > 0)
01321             {
01322               if (srcpix >= maxgray)
01323                 {
01324                   dst[x].b = 0;
01325                   dst[x].g = 0;
01326                   dst[x].r = 0;
01327                 }
01328               else
01329                 {
01330                   unsigned int level = multiplier[srcpix];
01331                   dst[x].b -=  (dst[x].b * level) >> 16;
01332                   dst[x].g -=  (dst[x].g * level) >> 16;
01333                   dst[x].r -=  (dst[x].r * level) >> 16;
01334                 }
01335             }
01336         }
01337       // Next line
01338       dst += rowsize();
01339       src += bm->rowsize();
01340     }
01341 }
01342 
01343 
01344 void 
01345 GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixel *color)
01346 {
01347   // Check
01348   if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01349   if (!clipok) compute_clip();
01350   if (!color) return;
01351   // Compute number of rows and columns
01352   int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
01353     xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
01354   if(xrows <= 0 || xcolumns <= 0)
01355     return;
01356   // Precompute multiplier map
01357   unsigned int multiplier[256];
01358   unsigned int maxgray = bm->get_grays() - 1;
01359   for (unsigned int i=1; i<maxgray ; i++)
01360     multiplier[i] = 0x10000 * i / maxgray;
01361   // Cache target color
01362   unsigned char gr = color->r;
01363   unsigned char gg = color->g;
01364   unsigned char gb = color->b;
01365   // Compute starting point
01366   const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
01367   GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
01368   // Loop over rows
01369   for (int y=0; y<xrows; y++)
01370     {
01371       // Loop over columns
01372       for (int x=0; x<xcolumns; x++)
01373         {
01374           unsigned char srcpix = src[x];
01375           // Perform pixel operation
01376           if (srcpix > 0)
01377             {
01378               if (srcpix >= maxgray)
01379                 {
01380                   dst[x].b = clip[dst[x].b + gb];
01381                   dst[x].g = clip[dst[x].g + gg];
01382                   dst[x].r = clip[dst[x].r + gr];
01383                 }
01384               else
01385                 {
01386                   unsigned int level = multiplier[srcpix];
01387                   dst[x].b = clip[dst[x].b + ((gb * level) >> 16)];
01388                   dst[x].g = clip[dst[x].g + ((gg * level) >> 16)];
01389                   dst[x].r = clip[dst[x].r + ((gr * level) >> 16)];
01390                 }
01391             }
01392         }
01393       // Next line
01394       dst += rowsize();
01395       src += bm->rowsize();
01396     }
01397 }
01398 
01399 
01400 void 
01401 GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
01402 {
01403   // Check
01404   if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01405   if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
01406   if (!clipok) compute_clip();
01407   if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
01408     G_THROW( ERR_MSG("GPixmap.diff_size") );
01409   // Compute number of rows and columns
01410   int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
01411       xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
01412   if(xrows <= 0 || xcolumns <= 0)
01413     return;
01414   // Precompute multiplier map
01415   unsigned int multiplier[256];
01416   unsigned int maxgray = bm->get_grays() - 1;
01417   for (unsigned int i=1; i<maxgray ; i++)
01418     multiplier[i] = 0x10000 * i / maxgray;
01419   // Cache target color
01420   // Compute starting point
01421   const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
01422   const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
01423   GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
01424   // Loop over rows
01425   for (int y=0; y<xrows; y++)
01426     {
01427       // Loop over columns
01428       for (int x=0; x<xcolumns; x++)
01429         {
01430           unsigned char srcpix = src[x];
01431           // Perform pixel operation
01432           if (srcpix > 0)
01433             {
01434               if (srcpix >= maxgray)
01435                 {
01436                   dst[x].b = clip[dst[x].b + src2[x].b];
01437                   dst[x].g = clip[dst[x].g + src2[x].g];
01438                   dst[x].r = clip[dst[x].r + src2[x].r];
01439                 }
01440               else
01441                 {
01442                   unsigned int level = multiplier[srcpix];
01443                   dst[x].b = clip[dst[x].b + ((src2[x].b * level) >> 16)];
01444                   dst[x].g = clip[dst[x].g + ((src2[x].g * level) >> 16)];
01445                   dst[x].r = clip[dst[x].r + ((src2[x].r * level) >> 16)];
01446                 }
01447             }
01448         }
01449       // Next line
01450       dst += rowsize();
01451       src += bm->rowsize();
01452       src2 += color->rowsize();
01453     }
01454 }
01455 
01456 
01457 
01458 void 
01459 GPixmap::blend(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
01460 {
01461   // Check
01462   if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01463   if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
01464   if (!clipok) compute_clip();
01465   if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
01466     G_THROW( ERR_MSG("GPixmap.diff_size") );
01467   // Compute number of rows and columns
01468   int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
01469       xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
01470   if(xrows <= 0 || xcolumns <= 0)
01471     return;
01472   // Precompute multiplier map
01473   unsigned int multiplier[256];
01474   unsigned int maxgray = bm->get_grays() - 1;
01475   for (unsigned int i=1; i<maxgray ; i++)
01476     multiplier[i] = 0x10000 * i / maxgray;
01477   // Cache target color
01478   // Compute starting point
01479   const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
01480   const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
01481   GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
01482   // Loop over rows
01483   for (int y=0; y<xrows; y++)
01484     {
01485       // Loop over columns
01486       for (int x=0; x<xcolumns; x++)
01487         {
01488           unsigned char srcpix = src[x];
01489           // Perform pixel operation
01490           if (srcpix > 0)
01491             {
01492               if (srcpix >= maxgray)
01493                 {
01494                   dst[x].b = src2[x].b;
01495                   dst[x].g = src2[x].g;
01496                   dst[x].r = src2[x].r;
01497                 }
01498               else
01499                 {
01500                   unsigned int level = multiplier[srcpix];
01501                   dst[x].b -= (((int)dst[x].b - (int)src2[x].b) * level) >> 16;
01502                   dst[x].g -= (((int)dst[x].g - (int)src2[x].g) * level) >> 16;
01503                   dst[x].r -= (((int)dst[x].r - (int)src2[x].r) * level) >> 16;
01504                 }
01505             }
01506         }
01507       // Next line
01508       dst += rowsize();
01509       src += bm->rowsize();
01510       src2 += color->rowsize();
01511     }
01512 }
01513 
01514 
01515 
01516 
01517 void 
01518 GPixmap::stencil(const GBitmap *bm, 
01519                 const GPixmap *pm, int pms, const GRect *pmr, 
01520                 double corr)
01521 {
01522   // Check arguments
01523   GRect rect(0, 0, pm->columns()*pms, pm->rows()*pms);
01524   if (pmr != 0)
01525     {
01526       if (pmr->xmin < rect.xmin || 
01527           pmr->ymin < rect.ymin || 
01528           pmr->xmax > rect.xmax || 
01529           pmr->ymax > rect.ymax  )
01530         G_THROW( ERR_MSG("GPixmap.overflow5") );
01531       rect = *pmr;
01532     }
01533   // Compute number of rows
01534   int xrows = nrows;
01535   if ((int)bm->rows() < xrows)
01536     xrows = bm->rows();
01537   if (rect.height() < xrows)
01538     xrows = rect.height();
01539   // Compute number of columns
01540   int xcolumns = ncolumns;
01541   if ((int)bm->columns() < xcolumns)
01542     xcolumns = bm->columns();
01543   if (rect.width() < xcolumns)
01544     xcolumns = rect.width();
01545   // Precompute multiplier map
01546   unsigned int multiplier[256];
01547   unsigned int maxgray = bm->get_grays() - 1;
01548   for (unsigned int i=1; i<maxgray ; i++)
01549     multiplier[i] = 0x10000 * i / maxgray;
01550   // Prepare color correction table
01551   unsigned char gtable[256];
01552   color_correction_table_cache(corr, gtable);
01553   // Compute starting point in blown up foreground pixmap
01554   int fgy, fgy1, fgxz, fgx1z;
01555   euclidian_ratio(rect.ymin, pms, fgy, fgy1);
01556   euclidian_ratio(rect.xmin, pms, fgxz, fgx1z);
01557   const GPixel *fg = (*pm)[fgy];
01558   const unsigned char *src = (*bm)[0];
01559   GPixel *dst = (*this)[0];
01560   // Loop over rows
01561   for (int y=0; y<xrows; y++)
01562   {
01563     // Loop over columns
01564     int fgx = fgxz;
01565     int fgx1 = fgx1z;
01566     for (int x=0; x<xcolumns; x++)
01567     {
01568       unsigned char srcpix = src[x];
01569       // Perform pixel operation
01570       if (srcpix > 0)
01571       {
01572         if (srcpix >= maxgray)
01573         {
01574           dst[x].b = gtable[fg[fgx].b];
01575           dst[x].g = gtable[fg[fgx].g];
01576           dst[x].r = gtable[fg[fgx].r];
01577         }
01578         else
01579         {
01580           unsigned int level = multiplier[srcpix];
01581           dst[x].b -= (((int)dst[x].b - (int)gtable[fg[fgx].b]) * level) >> 16;
01582           dst[x].g -= (((int)dst[x].g - (int)gtable[fg[fgx].g]) * level) >> 16;
01583           dst[x].r -= (((int)dst[x].r - (int)gtable[fg[fgx].r]) * level) >> 16;
01584         }
01585       }
01586       // Next column
01587       if (++fgx1 >= pms)
01588       {
01589         fgx1 = 0;
01590         fgx += 1;
01591       }
01592     }
01593     // Next line
01594     dst += rowsize();
01595     src += bm->rowsize();
01596     if (++fgy1 >= pms)
01597     {
01598       fgy1 = 0;
01599       fg += pm->rowsize();
01600     } 
01601   }
01602 }
01603 
01604 GP<GPixmap> GPixmap::rotate(int count)
01605 {
01606   GP<GPixmap> newpixmap(this);
01607   if((count %= 4))
01608   {
01609     if( count&0x01)
01610       newpixmap = new GPixmap(ncolumns, nrows);
01611     else
01612       newpixmap = new GPixmap(nrows, ncolumns);
01613 
01614     GPixmap &dpixmap = *newpixmap;
01615 
01616     GMonitorLock lock(&pixmap_monitor());
01617     switch(count)
01618     {
01619     case 1: 
01620         {
01621             int lastrow = dpixmap.rows()-1;
01622 
01623             for(int y=0; y<nrows; y++)
01624             {
01625                 const GPixel *r=operator [] (y);
01626                 for(int x=0,xnew=lastrow; xnew>=0; x++,xnew--)
01627                 {
01628                     dpixmap[xnew][y] = r[x];
01629                 }
01630             }
01631         }
01632         break;
01633     case 2: 
01634         {
01635             int lastrow = dpixmap.rows()-1;
01636             int lastcolumn = dpixmap.columns()-1;
01637 
01638             for(int y=0,ynew=lastrow; ynew>=0; y++,ynew--)
01639             {
01640                 const GPixel *r=operator [] (y);
01641                 GPixel *d=dpixmap[ynew];
01642                 for(int xnew=lastcolumn; xnew>=0; r++,xnew--)
01643                 {
01644                     d[xnew] = *r;
01645                 }
01646             }
01647         }
01648         break;
01649     case 3: 
01650         {
01651             int lastcolumn = dpixmap.columns()-1;
01652 
01653             for(int y=0,ynew=lastcolumn; ynew>=0; y++,ynew--)
01654             {
01655                 const GPixel *r=operator [] (y);
01656                 for(int x=0; x<ncolumns; x++)
01657                 {
01658                     dpixmap[x][ynew] = r[x];
01659                 }
01660             }
01661         }
01662         break;
01663     }
01664   }
01665   return newpixmap;
01666 }
01667 
01668 
01669 
01670 #ifdef HAVE_NAMESPACES
01671 }
01672 # ifndef NOT_USING_DJVU_NAMESPACE
01673 using namespace DJVU;
01674 # endif
01675 #endif
01676 

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal