|
|
| version 1.6, 2001/09/18 16:05:42 | version 1.30.2.4.2.2, 2003/03/24 09:39:55 |
|---|---|
| Line 1 | Line 1 |
| /** @file | /** @file |
| Parser: image manipulations impl1. | Parser: image manipulations impl1. |
| Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf) | Copyright (c) 2001-2003 ArtLebedev Group (http://www.artlebedev.com) |
| Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru) | |
| $Id$ | based on: gd |
| Written by Tom Boutell, 5/94. | |
| Copyright 1994, Cold Spring Harbor Labs. | |
| Permission granted to use this code in any fashion provided | |
| that this notice is retained and any alterations are | |
| labeled as such. It is requested, but not required, that | |
| you share extensions to this module with us so that we | |
| can incorporate them into new versions. | |
| */ | */ |
| static const char* IDENT_GIF_C="$Date$"; | |
| #include "gif.h" | #include "gif.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 19 void gdImage::Create(int asx, int asy) { | Line 32 void gdImage::Create(int asx, int asy) { |
| pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx); | pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx); |
| polyInts = 0; | polyInts = 0; |
| polyAllocated = 0; | polyAllocated = 0; |
| lineWidth = 1; lineStyle=0; | lineWidth = 1; |
| for (i=0; (i<asx); i++) | for (i=0; (i<asx); i++) |
| pixels[i] = (unsigned char *) calloc(asy); | pixels[i] = (unsigned char *) malloc_atomic(asy); |
| colorsTotal = 0; | colorsTotal = 0; |
| transparent = (-1); | transparent = (-1); |
| 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 42 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 258 void gdImage::Line(int x1, int y1, int x | Line 271 void gdImage::Line(int x1, int y1, int x |
| at least for me) and there are other inefficiencies (small circles | at least for me) and there are other inefficiencies (small circles |
| do far too much work). */ | do far too much work). */ |
| void gdImage::Arc(int cx, int cy, int w, int h, int s, int e, int color) | |
| { | |
| #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 lx = 0, ly = 0; | |
| int w2, h2; | |
| w2 = w/2; | |
| h2 = h/2; | |
| while (e < s) 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++) { | |
| int x, y; | |
| x = ((long)cost[i] * (long)w2 / costScale) + cx; | |
| y = ((long)sint[i] * (long)h2 / sintScale) + cy; | |
| if (i != s) { | |
| Line(lx, ly, x, y, color); | |
| } | |
| lx = x; | |
| ly = y; | |
| } | |
| #if 0 | |
| } | |
| #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) | |
| { | |
| int i; | |
| int lx = 0, ly = 0; | |
| int w2, h2; | |
| w2 = w/2; | |
| h2 = h/2; | |
| while (e < s) 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++) { | |
| int x, y; | |
| x = ((long)cost[i] * (long)w2 / costScale) + cx; | |
| y = ((long)sint[i] * (long)h2 / sintScale) + cy; | |
| if(i==s || i==e) | |
| Line(cx, cy, x, y, color); | |
| if (i != s) { | |
| Line(lx, ly, x, y, color); | |
| } | |
| lx = x; | |
| ly = y; | |
| } | |
| } | |
| void gdImage::FillToBorder(int x, int y, int border, int color) | void gdImage::FillToBorder(int x, int y, int border, int color) |
| { | { |
| if(!BoundsSafe(x, y)) //PAF | if(!BoundsSafe(x, y)) //PAF |
| Line 408 void gdImage::Rectangle(int x1, int y1, | Line 577 void gdImage::Rectangle(int x1, int y1, |
| void gdImage::FilledRectangle(int x1, int y1, int x2, int y2, int color) | void gdImage::FilledRectangle(int x1, int y1, int x2, int y2, int color) |
| { | { |
| if(x1>x2) { | |
| int t=x1; | |
| x1=x2; | |
| x2=t; | |
| } | |
| if(y1>y2) { | |
| int t=y1; | |
| y1=y2; | |
| y2=t; | |
| } | |
| int x, y; | int x, y; |
| for (y=y1; (y<=y2); y++) | for (y=y1; (y<=y2); y++) |
| for (x=x1; (x<=x2); x++) | for (x=x1; (x<=x2); x++) |
| SetPixel(x, y, color); | SetPixel(x, y, color); |
| Line 468 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; | |
| int srcTransparent=src.GetTransparent(); | |
| int dstTransparent=dst.GetTransparent(); | |
| 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 */ | |
| /* fixed by paf 20030116, another fix below */ | |
| if (pd == dstTransparent) | |
| continue; | |
| double sy1, sy2, sx1, sx2; | |
| double sx, sy; | |
| double spixels = 0; | |
| double red = 0.0, green = 0.0, blue = 0.0; | |
| bool transparent=true; | |
| 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); | |
| // fix added 20020116 by paf to support transparent src | |
| if (p!=srcTransparent) { | |
| transparent = false; | |
| 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(transparent) | |
| continue; | |
| 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 645 void gdImage::LineReplaceColor(int x1, i | Line 956 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) |
| Line 777 void gdImage::SetLineWidth(int width) | Line 1089 void gdImage::SetLineWidth(int width) |
| lineWidth=width; | lineWidth=width; |
| } | } |
| void gdImage::SetLineStyle(const char *alineStyle) | void gdImage::SetLineStyle(const char* alineStyle) |
| { | { |
| lineStyle=alineStyle; | lineStyle=alineStyle; |
| } | } |