|
|
| version 1.16, 2001/10/16 07:47:16 | version 1.33, 2003/11/20 17:07:44 |
|---|---|
| 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-2003 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 * const 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 32 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 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 337 void gdImage::Arc(int cx, int cy, int w, | Line 337 void gdImage::Arc(int cx, int cy, int w, |
| 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); |
| } | } |
| Line 402 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 642 void gdImage::Copy(gdImage& dst, int dst | Line 648 void gdImage::Copy(gdImage& dst, int dst |
| } | } |
| } | } |
| void gdImage::CopyResized(gdImage& dst, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) | 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; | gdImage& src=*this; |
| int c; | |
| int x, y; | int x, y; |
| int tox, toy; | int srcTransparent=src.GetTransparent(); |
| int ydest; | int dstTransparent=dst.GetTransparent(); |
| int i; | for (y = dstY; (y < dstY + dstH); y++) { |
| int colorMap[gdMaxColors]; | for (x = dstX; (x < dstX + dstW); x++) { |
| /* Stretch vectors */ | int pd = dst.GetPixel (x, y); |
| int *stx; | /* Added 7/24/95: support transparent copies */ |
| int *sty; | /* fixed by paf 20030116, another fix below */ |
| /* We only need to use floating point to determine the correct | if (pd == dstTransparent) |
| stretch vector for one line's worth. */ | continue; |
| double accum; | |
| stx = (int *) malloc(sizeof(int) * srcW); | double sy1, sy2, sx1, sx2; |
| sty = (int *) malloc(sizeof(int) * srcH); | double sx, sy; |
| accum = 0; | double spixels = 0; |
| for (i=0; (i < srcW); i++) { | double red = 0.0, green = 0.0, blue = 0.0; |
| int got; | bool transparent=true; |
| accum += (double)dstW/(double)srcW; | sy1 = ((double) y - (double) dstY) * (double) srcH / |
| got = floor(accum); | (double) dstH; |
| stx[i] = got; | sy2 = ((double) (y + 1) - (double) dstY) * (double) srcH / |
| accum -= got; | (double) dstH; |
| } | sy = sy1; |
| accum = 0; | do |
| for (i=0; (i < srcH); i++) { | { |
| int got; | double yportion; |
| accum += (double)dstH/(double)srcH; | if (floor (sy) == floor (sy1)) |
| got = floor(accum); | { |
| sty[i] = got; | yportion = 1.0 - (sy - floor (sy)); |
| accum -= got; | if (yportion > sy2 - sy1) |
| } | { |
| for (i=0; (i<gdMaxColors); i++) { | yportion = sy2 - sy1; |
| colorMap[i] = (-1); | } |
| } | sy = floor (sy); |
| toy = dstY; | |
| for (y=srcY; (y < (srcY + srcH)); y++) { | |
| for (ydest=0; (ydest < sty[y-srcY]); ydest++) { | |
| tox = dstX; | |
| for (x=srcX; (x < (srcX + srcW)); x++) { | |
| int nc; | |
| if (!stx[x - srcX]) { | |
| continue; | |
| } | } |
| c = src.GetPixel(x, y); | else if (sy == floor (sy2)) |
| /* Added 7/24/95: support transparent copies */ | { |
| if (src.GetTransparent() == c) { | yportion = sy2 - floor (sy2); |
| tox += stx[x-srcX]; | |
| continue; | |
| } | } |
| /* Have we established a mapping for this color? */ | else |
| if (colorMap[c] == (-1)) { | { |
| /* If it's the same image, mapping is trivial */ | yportion = 1.0; |
| if (&dst == &src) { | } |
| nc = c; | sx1 = ((double) x - (double) dstX) * (double) srcW / |
| } else { | dstW; |
| /* First look for an exact match */ | sx2 = ((double) (x + 1) - (double) dstX) * (double) srcW / |
| nc = dst.ColorExact( | dstW; |
| src.red[c], src.green[c], | sx = sx1; |
| src.blue[c]); | do |
| } | { |
| if (nc == (-1)) { | double xportion; |
| /* No, so try to allocate it */ | double pcontribution; |
| nc = dst.ColorAllocate( | int p; |
| src.red[c], src.green[c], | if (floor (sx) == floor (sx1)) |
| src.blue[c]); | { |
| /* If we're out of colors, go for the | xportion = 1.0 - (sx - floor (sx)); |
| closest color */ | if (xportion > sx2 - sx1) |
| if (nc == (-1)) { | { |
| nc = dst.ColorClosest( | xportion = sx2 - sx1; |
| src.red[c], src.green[c], | |
| src.blue[c]); | |
| } | } |
| sx = floor (sx); | |
| } | } |
| colorMap[c] = nc; | else if (sx == floor (sx2)) |
| } | { |
| for (i=0; (i < stx[x - srcX]); i++) { | xportion = sx2 - floor (sx2); |
| dst.SetPixel(tox, toy, colorMap[c]); | } |
| tox++; | else |
| } | { |
| } | xportion = 1.0; |
| toy++; | } |
| } | pcontribution = xportion * yportion; |
| } | p = src.GetPixel ( |
| free(stx); | (int) sx, |
| free(sty); | (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); | |
| static int gdGetWord(int *result, FILE *in) | if(transparent) |
| { | continue; |
| int r; | |
| r = getc(in); | |
| if (r == EOF) { | |
| return 0; | |
| } | |
| *result = r << 8; | |
| r = getc(in); | |
| if (r == EOF) { | |
| return 0; | |
| } | |
| *result += r; | |
| return 1; | |
| } | |
| static void gdPutWord(int w, FILE *out) | if (spixels != 0.0) { |
| { | red /= spixels; |
| putc((unsigned char)(w >> 8), out); | green /= spixels; |
| putc((unsigned char)(w & 0xFF), out); | 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); | |
| static int gdGetByte(int *result, FILE *in) | /* If we're out of colors, go for the closest color */ |
| { | if (nc == (-1)) |
| int r; | nc = dst.ColorClosest((int)red, (int)green, (int)blue); |
| r = getc(in); | } |
| if (r == EOF) { | } |
| return 0; | dst.SetPixel(x, y, nc); |
| } | } |
| *result = r; | } |
| return 1; | |
| } | } |
| void gdImage::Polygon(Point *p, int n, int c, bool closed) | void gdImage::Polygon(Point *p, int n, int c, bool closed) |
| Line 908 void gdImage::LineReplaceColor(int x1, i | Line 923 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 1040 void gdImage::SetLineWidth(int width) | Line 1056 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; |
| } | } |