00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064
00065
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
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
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
00157
00158 static GMonitor &pixmap_monitor() {
00159 static GMonitor xpixmap_monitor;
00160 return xpixmap_monitor;
00161 }
00162
00163
00165
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
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
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
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
00328
00329
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
00339 GRect rect2(0, 0, ref.columns(), ref.rows() );
00340 rect2.intersect(rect2, rect);
00341 rect2.translate(-rect.xmin, -rect.ymin);
00342
00343 if (! rect2.isempty())
00344 {
00345 GPixel *xramp;
00346 GPBuffer<GPixel> gxramp(xramp);
00347
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
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
00364
00365
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
00392 GRect rect2(0, 0, ref.columns(), ref.rows() );
00393 rect2.intersect(rect2, rect);
00394 rect2.translate(-rect.xmin, -rect.ymin);
00395
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
00434
00435
00436 static unsigned int
00437 read_integer(char &c, ByteStream &bs)
00438 {
00439 unsigned int x = 0;
00440
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
00449 if (c<'0' || c>'9')
00450 G_THROW( ERR_MSG("GPixmap.no_int") );
00451
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
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
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
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
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
00593
00594
00595 static void
00596 color_correction_table(double gamma, unsigned char gtable[256] )
00597 {
00598
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
00604 for (int i=0; i<256; i++)
00605 gtable[i] = i;
00606 }
00607 else
00608 {
00609
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
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
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
00653 if (gamma_correction>0.999 && gamma_correction<1.001)
00654 return;
00655
00656 unsigned char gtable[256];
00657 color_correction_table_cache(gamma_correction, gtable);
00658
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
00676 if (gamma_correction>0.999 && gamma_correction<1.001)
00677 return;
00678
00679 unsigned char gtable[256];
00680 color_correction_table_cache(gamma_correction, gtable);
00681
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
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
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
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
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
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
00809
00810
00811 void
00812 GPixmap::downsample(const GPixmap *src, int factor, const GRect *pdr)
00813 {
00814
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
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
00837 init(rect.height(), rect.width(), 0);
00838
00839
00840 int sy = rect.ymin * factor;
00841 int sxz = rect.xmin * factor;
00842
00843
00844
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
00851 for (int x=0; x<ncolumns; x++)
00852 {
00853 int r=0, g=0, b=0, s=0;
00854
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
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
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
00888 sx = sx + factor;
00889 }
00890
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
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
00912 init(rect.height(), rect.width(), 0);
00913
00914 int sy, sy1, sxz, sx1z;
00915 euclidian_ratio(rect.ymin, factor, sy, sy1);
00916 euclidian_ratio(rect.xmin, factor, sxz, sx1z);
00917
00918 const GPixel *sptr = (*src)[sy];
00919 GPixel *dptr = (*this)[0];
00920 for (int y=0; y<nrows; y++)
00921 {
00922
00923 int sx = sxz;
00924 int sx1 = sx1z;
00925 for (int x=0; x<ncolumns; x++)
00926 {
00927 dptr[x] = sptr[sx];
00928
00929 if (++sx1 >= factor)
00930 {
00931 sx1 = 0;
00932 sx += 1;
00933 }
00934 }
00935
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
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
01118 init(destheight, destwidth, 0);
01119
01120
01121 int dxz, dy;
01122 int sxz, sy;
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
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
01139 while (dy < destheight)
01140 {
01141 int sx = sxz;
01142 int dx = dxz;
01143
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
01175 dx += 3;
01176 sx += 4;
01177 }
01178
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
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
01208 init(destheight, destwidth, 0);
01209
01210
01211 int dxz, dy;
01212 int sxz, sy;
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
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
01229 while (dy < destheight)
01230 {
01231 int sx = sxz;
01232 int dx = dxz;
01233
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
01265 dx += 3;
01266 sx += 2;
01267 }
01268
01269 dy += 3;
01270 dptr += d3add;
01271 sy += 2;
01272 sptr += s2add;
01273 }
01274 }
01275
01276
01278
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
01298 if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01299
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
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
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
01313 for (int y=0; y<xrows; y++)
01314 {
01315
01316 for (int x=0; x<xcolumns; x++)
01317 {
01318 unsigned char srcpix = src[x];
01319
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
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
01348 if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
01349 if (!clipok) compute_clip();
01350 if (!color) return;
01351
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
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
01362 unsigned char gr = color->r;
01363 unsigned char gg = color->g;
01364 unsigned char gb = color->b;
01365
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
01369 for (int y=0; y<xrows; y++)
01370 {
01371
01372 for (int x=0; x<xcolumns; x++)
01373 {
01374 unsigned char srcpix = src[x];
01375
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
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
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
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
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
01420
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
01425 for (int y=0; y<xrows; y++)
01426 {
01427
01428 for (int x=0; x<xcolumns; x++)
01429 {
01430 unsigned char srcpix = src[x];
01431
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
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
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
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
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
01478
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
01483 for (int y=0; y<xrows; y++)
01484 {
01485
01486 for (int x=0; x<xcolumns; x++)
01487 {
01488 unsigned char srcpix = src[x];
01489
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
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
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
01534 int xrows = nrows;
01535 if ((int)bm->rows() < xrows)
01536 xrows = bm->rows();
01537 if (rect.height() < xrows)
01538 xrows = rect.height();
01539
01540 int xcolumns = ncolumns;
01541 if ((int)bm->columns() < xcolumns)
01542 xcolumns = bm->columns();
01543 if (rect.width() < xcolumns)
01544 xcolumns = rect.width();
01545
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
01551 unsigned char gtable[256];
01552 color_correction_table_cache(corr, gtable);
01553
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
01561 for (int y=0; y<xrows; y++)
01562 {
01563
01564 int fgx = fgxz;
01565 int fgx1 = fgx1z;
01566 for (int x=0; x<xcolumns; x++)
01567 {
01568 unsigned char srcpix = src[x];
01569
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
01587 if (++fgx1 >= pms)
01588 {
01589 fgx1 = 0;
01590 fgx += 1;
01591 }
01592 }
01593
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