|
|
| version 1.13, 2001/10/08 16:06:49 | version 1.28, 2002/08/01 11:41:13 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: image manipulations impl1. | Parser: image manipulations impl1. |
| Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) | Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) |
| $Id$ | |
| based on: gd | based on: gd |
| Written by Tom Boutell, 5/94. | Written by Tom Boutell, 5/94. |
| Line 17 | Line 14 |
| can incorporate them into new versions. | can incorporate them into new versions. |
| */ | */ |
| static const char* IDENT_GIF_C="$Date$"; | |
| #include "gif.h" | #include "gif.h" |
| #include "mtables.h" | #include "mtables.h" |
| #include "pa_common.h" | |
| //static void BrushApply(int x, int y); | //static void BrushApply(int x, int y); |
| //static void TileApply(int x, int y); | //static void TileApply(int x, int y); |
| Line 40 void gdImage::Create(int asx, int asy) { | Line 40 void gdImage::Create(int asx, int asy) { |
| interlace = 0; | interlace = 0; |
| } | } |
| int gdImage::ColorClosest(int r, int g, int b) | int gdImage::ColorClosest(int r, int g, int b, int tolerance) |
| { | { |
| int i; | int i; |
| long rd, gd, bd; | long rd, gd, bd; |
| Line 55 int gdImage::ColorClosest(int r, int g, | Line 55 int gdImage::ColorClosest(int r, int g, |
| gd = (green[i] - g); | gd = (green[i] - g); |
| bd = (blue[i] - b); | bd = (blue[i] - b); |
| dist = rd * rd + gd * gd + bd * bd; | dist = rd * rd + gd * gd + bd * bd; |
| if ((i == 0) || (dist < mindist)) { | if ((i == 0) || (dist < mindist+tolerance)) { |
| mindist = dist; | mindist = dist; |
| ct = i; | ct = i; |
| } | } |
| } | } |
| return ct; | return mindist<tolerance?ct:-1; |
| } | } |
| int gdImage::ColorExact(int r, int g, int b) | int gdImage::ColorExact(int r, int g, int b) |
| Line 273 void gdImage::Line(int x1, int y1, int x | Line 273 void gdImage::Line(int x1, int y1, int x |
| void gdImage::Arc(int cx, int cy, int w, int h, int s, int e, int color) | void gdImage::Arc(int cx, int cy, int w, int h, int s, int e, int color) |
| { | { |
| if(w!=h) { | #if 0 |
| if(s==0 && e==360) { // full | |
| if(w==h) { // circle? | |
| /* Bresenham octant code, which I should use eventually */ | |
| int x, y, d; | |
| x = 0; | |
| y = w/2; | |
| d = 3-w; | |
| while (x <= y) { | |
| SetPixel(cx+x, cy+y, color); | |
| SetPixel(cx+x, cy-y, color); | |
| SetPixel(cx-x, cy+y, color); | |
| SetPixel(cx-x, cy-y, color); | |
| SetPixel(cx+y, cy+x, color); | |
| SetPixel(cx+y, cy-x, color); | |
| SetPixel(cx-y, cy+x, color); | |
| SetPixel(cx-y, cy-x, color); | |
| if (d < 0) { | |
| d += 4 * x + 6; | |
| } else { | |
| d += 4 * (x - y) + 10; | |
| y--; | |
| } | |
| x++; | |
| } | |
| } else { // full ellipse | |
| w/=2; | |
| h/=2; | |
| int elx, ely; | |
| long aa, aa2, bb, bb2, d, dx, dy; | |
| elx = 0; ely = h; aa = (long)w * w; aa2 = 2 * aa; | |
| bb = (long)h * h; bb2 = 2 * bb; | |
| d = bb - aa * h + aa/4; dx = 0; dy = aa2 * h; | |
| SetPixel(cx, cy - ely, color); SetPixel(cx, cy + ely, color); | |
| SetPixel(cx - w, cy, color); SetPixel(cx + w, cy, color); | |
| while (dx < dy) | |
| { | |
| if (d > 0) { ely--; dy-=aa2; d-=dy;} | |
| elx++; dx+=bb2; d+=bb+dx; | |
| SetPixel(cx + elx, cy + ely, color); | |
| SetPixel(cx - elx, cy + ely, color); | |
| SetPixel(cx + elx, cy - ely, color); | |
| SetPixel(cx - elx, cy - ely, color); | |
| }; | |
| d+=(3 * (aa - bb)/2 - (dx + dy))/2; | |
| while (ely > 0) | |
| { | |
| if (d < 0) {elx++; dx+=bb2; d+=bb + dx;} | |
| ely--; dy-=aa2; d+=aa - dy; | |
| SetPixel(cx + elx, cy + ely, color); | |
| SetPixel(cx - elx, cy + ely, color); | |
| SetPixel(cx + elx, cy - ely, color); | |
| SetPixel(cx - elx, cy - ely, color); | |
| }; | |
| } | |
| } else { | |
| #endif | |
| int i; | int i; |
| int lx = 0, ly = 0; | int lx = 0, ly = 0; |
| int w2, h2; | int w2, h2; |
| w2 = w/2; | w2 = w/2; |
| h2 = h/2; | h2 = h/2; |
| while (e < s) { | while (e < s) e += 360; |
| e += 360; | // paf |
| } | while(s<0) s+=360; |
| while(s>360) s-=360; | |
| while(e<0) e+=360; | |
| while(e>360) e-=360; | |
| for (i=s; (i <= e); i++) { | for (i=s; (i <= e); i++) { |
| int x, y; | int x, y; |
| x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; | x = ((long)cost[i] * (long)w2 / costScale) + cx; |
| y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy; | y = ((long)sint[i] * (long)h2 / sintScale) + cy; |
| if (i != s) { | if (i != s) { |
| Line(lx, ly, x, y, color); | Line(lx, ly, x, y, color); |
| } | } |
| lx = x; | lx = x; |
| ly = y; | ly = y; |
| } | } |
| } else { | #if 0 |
| /* Bresenham octant code, which I should use eventually */ | |
| int x, y, d; | |
| x = 0; | |
| y = w/2; | |
| d = 3-w; | |
| while (x <= y) { | |
| SetPixel(cx+x, cy+y, color); | |
| SetPixel(cx+x, cy-y, color); | |
| SetPixel(cx-x, cy+y, color); | |
| SetPixel(cx-x, cy-y, color); | |
| SetPixel(cx+y, cy+x, color); | |
| SetPixel(cx+y, cy-x, color); | |
| SetPixel(cx-y, cy+x, color); | |
| SetPixel(cx-y, cy-x, color); | |
| if (d < 0) { | |
| d += 4 * x + 6; | |
| } else { | |
| d += 4 * (x - y) + 10; | |
| y--; | |
| } | |
| x++; | |
| } | |
| } | } |
| #endif | |
| } | } |
| /* | |
| // http://firststeps.narod.ru/cgi/18.html | |
| int CGIScreen::Ellipse(int exc, int eyc, int ea, int eb , unsigned char Color) | |
| { | |
| int elx, ely; | |
| long aa, aa2, bb, bb2, d, dx, dy; | |
| elx = 0; ely = eb; aa = (long)ea * ea; aa2 = 2 * aa; | |
| bb = (long)eb * eb; bb2 = 2 * bb; | |
| d = bb - aa * eb + aa/4; dx = 0; dy = aa2 * eb; | |
| PutPixel(exc, eyc - ely, Color); PutPixel(exc, eyc + ely, Color); | |
| PutPixel(exc - ea, eyc, Color); PutPixel(exc + ea, eyc, Color); | |
| while (dx < dy) | |
| { | |
| if (d > 0) { ely--; dy-=aa2; d-=dy;} | |
| elx++; dx+=bb2; d+=bb+dx; | |
| PutPixel(exc + elx, eyc + ely, Color); | |
| PutPixel(exc - elx, eyc + ely, Color); | |
| PutPixel(exc + elx, eyc - ely, Color); | |
| PutPixel(exc - elx, eyc - ely, Color); | |
| }; | |
| d+=(3 * (aa - bb)/2 - (dx + dy))/2; | |
| while (ely > 0) | |
| { | |
| if (d < 0) {elx++; dx+=bb2; d+=bb + dx;} | |
| ely--; dy-=aa2; d+=aa - dy; | |
| PutPixel(exc + elx, eyc + ely, Color); | |
| PutPixel(exc - elx, eyc + ely, Color); | |
| PutPixel(exc + elx, eyc - ely, Color); | |
| PutPixel(exc - elx, eyc - ely, Color); | |
| }; | |
| return 0; | |
| }; | |
| */ | |
| void gdImage::Sector(int cx, int cy, int w, int h, int s, int e, int color) | void gdImage::Sector(int cx, int cy, int w, int h, int s, int e, int color) |
| { | { |
| Line 326 void gdImage::Sector(int cx, int cy, int | Line 405 void gdImage::Sector(int cx, int cy, int |
| int w2, h2; | int w2, h2; |
| w2 = w/2; | w2 = w/2; |
| h2 = h/2; | h2 = h/2; |
| while (e < s) { | while (e < s) e += 360; |
| e += 360; | // paf |
| } | while(s<0) s+=360; |
| while(s>360) s-=360; | |
| while(e<0) e+=360; | |
| while(e>360) e-=360; | |
| for (i=s; (i <= e); i++) { | for (i=s; (i <= e); i++) { |
| int x, y; | int x, y; |
| x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; | x = ((long)cost[i] * (long)w2 / costScale) + cx; |
| y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy; | y = ((long)sint[i] * (long)h2 / sintScale) + cy; |
| if(i==s || i==e) | if(i==s || i==e) |
| Line(cx, cy, x, y, color); | Line(cx, cy, x, y, color); |
| if (i != s) { | if (i != s) { |
| Line 566 void gdImage::Copy(gdImage& dst, int dst | Line 648 void gdImage::Copy(gdImage& dst, int dst |
| } | } |
| } | } |
| void gdImage::CopyResampled(gdImage& dst, | |
| int dstX, int dstY, | |
| int srcX, int srcY, | |
| int dstW, int dstH, | |
| int srcW, int srcH, | |
| int tolerance) | |
| { | |
| gdImage& src=*this; | |
| int x, y; | |
| for (y = dstY; (y < dstY + dstH); y++) { | |
| for (x = dstX; (x < dstX + dstW); x++) { | |
| int pd = dst.GetPixel (x, y); | |
| /* Added 7/24/95: support transparent copies */ | |
| if (src.GetTransparent() == pd) | |
| continue; | |
| double sy1, sy2, sx1, sx2; | |
| double sx, sy; | |
| double spixels = 0; | |
| double red = 0.0, green = 0.0, blue = 0.0; | |
| sy1 = ((double) y - (double) dstY) * (double) srcH / | |
| (double) dstH; | |
| sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / | |
| (double) dstH; | |
| sy = sy1; | |
| do | |
| { | |
| double yportion; | |
| if (floor (sy) == floor (sy1)) | |
| { | |
| yportion = 1.0 - (sy - floor (sy)); | |
| if (yportion > sy2 - sy1) | |
| { | |
| yportion = sy2 - sy1; | |
| } | |
| sy = floor (sy); | |
| } | |
| else if (sy == floor (sy2)) | |
| { | |
| yportion = sy2 - floor (sy2); | |
| } | |
| else | |
| { | |
| yportion = 1.0; | |
| } | |
| sx1 = ((double) x - (double) dstX) * (double) srcW / | |
| dstW; | |
| sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / | |
| dstW; | |
| sx = sx1; | |
| do | |
| { | |
| double xportion; | |
| double pcontribution; | |
| int p; | |
| if (floor (sx) == floor (sx1)) | |
| { | |
| xportion = 1.0 - (sx - floor (sx)); | |
| if (xportion > sx2 - sx1) | |
| { | |
| xportion = sx2 - sx1; | |
| } | |
| sx = floor (sx); | |
| } | |
| else if (sx == floor (sx2)) | |
| { | |
| xportion = sx2 - floor (sx2); | |
| } | |
| else | |
| { | |
| xportion = 1.0; | |
| } | |
| pcontribution = xportion * yportion; | |
| p = src.GetPixel ( | |
| (int) sx, | |
| (int) sy); | |
| red += Red (p) * pcontribution; | |
| green += Green (p) * pcontribution; | |
| blue += Blue (p) * pcontribution; | |
| spixels += xportion * yportion; | |
| sx += 1.0; | |
| } while (sx < sx2); | |
| sy += 1.0; | |
| } while (sy < sy2); | |
| if (spixels != 0.0) { | |
| red /= spixels; | |
| green /= spixels; | |
| blue /= spixels; | |
| } | |
| /* Clamping to allow for rounding errors above */ | |
| if (red > 255.0) | |
| red = 255.0; | |
| if (green > 255.0) | |
| green = 255.0; | |
| if (blue > 255.0) | |
| blue = 255.0; | |
| red=round(red); | |
| green=round(green); | |
| blue=round(blue); | |
| /* First look for an exact match */ | |
| int nc = dst.ColorExact((int)red, (int)green, (int)blue); | |
| if (nc == (-1)) { | |
| /* No, so go for the closest color with high tolerance */ | |
| nc = dst.ColorClosest((int)red, (int)green, (int)blue, tolerance); | |
| if (nc == (-1)) { | |
| /* Not found with even high tolerance, so try to allocate it */ | |
| nc = dst.ColorAllocate((int)red, (int)green, (int)blue); | |
| /* If we're out of colors, go for the closest color */ | |
| if (nc == (-1)) | |
| nc = dst.ColorClosest((int)red, (int)green, (int)blue); | |
| } | |
| } | |
| dst.SetPixel(x, y, nc); | |
| } | |
| } | |
| } | |
| static int gdGetWord(int *result, FILE *in) | static int gdGetWord(int *result, FILE *in) |
| { | { |
| int r; | int r; |
| Line 743 void gdImage::LineReplaceColor(int x1, i | Line 944 void gdImage::LineReplaceColor(int x1, i |
| if(y1!=y2) | if(y1!=y2) |
| return; | return; |
| for(int x=x1; x<=x2; x++) { | for(int x=x1; x<=x2; x++) |
| unsigned char *pixel=&pixels[x][y1]; | if(BoundsSafe(x, y1)) { |
| if(*pixel==a) | unsigned char *pixel=&pixels[x][y1]; |
| *pixel=b; | if(*pixel==a) |
| } | *pixel=b; |
| } | |
| } | } |
| void gdImage::FilledPolygonReplaceColor(Point *p, int n, int a, int b) | void gdImage::FilledPolygonReplaceColor(Point *p, int n, int a, int b) |