diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvipng/color.c |
Initial commit
Diffstat (limited to 'dviware/dvipng/color.c')
-rw-r--r-- | dviware/dvipng/color.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/dviware/dvipng/color.c b/dviware/dvipng/color.c new file mode 100644 index 0000000000..63fc29c6c5 --- /dev/null +++ b/dviware/dvipng/color.c @@ -0,0 +1,440 @@ +/* color.c */ + +/************************************************************************ + + Part of the dvipng distribution + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this program. If not, see + <http://www.gnu.org/licenses/>. + + Copyright (C) 2002-2015 Jan-Åke Larsson + +************************************************************************/ + +#include "dvipng.h" + +/* + * Color. We delete and recreate the gdImage for each new page. This + * means that the stack must contain rgb value not color index. + * Besides, the current antialiasing implementation needs rgb anyway. +*/ + +struct colorname { + struct colorname *next; + char* color; + char name[1]; +} *colornamep=NULL,*xcp=NULL; + +const char *colordef[]={"xcolor.sty","dvipsnam.def", + "svgnam.def","x11nam.def",NULL}; +char *xcpname=NULL; + +void initcolor(void) +{ + csp = 1; + cstack[0].red=255; + cstack[0].green=255; + cstack[0].blue=255; + cstack[1].red=0; + cstack[1].green=0; + cstack[1].blue=0; +} + +static struct colorname * NewColor(const char* prefix, int nprefix, + char* name, int nname, + char* model, int nmodel, + char* values, int nvalues) +{ + struct colorname *tmp; + if ((tmp=malloc(sizeof(struct colorname)+3+nprefix+nname+nmodel+nvalues))==NULL) + Fatal("Cannot malloc space for color name"); + tmp->color=tmp->name+nprefix+nname+1; + strncpy(tmp->name,prefix,nprefix); + strncpy(tmp->name+nprefix,name,nname); + tmp->name[nprefix+nname]='\0'; + strncpy(tmp->color,model,nmodel); + tmp->color[nmodel]=' '; + strncpy(tmp->color+nmodel+1,values,nvalues); + tmp->color[nmodel+nvalues+1]='\0'; + model=tmp->color; + while(*model!='\0') { + if (*model==',') + *model=' '; + model++; + } + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR NAME:\t'%s' '%s'", + tmp->name,tmp->color)); + return(tmp); +} + +#define FINDWORD(s) while(s<max && \ + (*s=='{'||*s==' '||*s=='%'||*s==';'||*s=='\r'||*s=='\n')) s++ +#define FINDARG(s) while(s<max && *s!='{') s++; FINDWORD(s) +#define FINDMODELEND(s,n) n=0; while(s<max && *s!='}' && *s!='/') { s++; n++; } +#define FINDNAMEEND(s,n) n=0; while(s<max && *s!='}' && *s!=',') { s++; n++; } +#define FINDVALEND(s,n) n=0; while(s<max && *s!='}' && *s!='/' && *s!=';') { s++; n++; } +#define FINDLASTVALEND(s) while(s<max && *s!='}' && *s!=';') s++ +#define FINDPSNAMEEND(s,n) n=0; while(s<max && *s!='{') { s++; n++; } +#define BLANKCOMMAS(s) + +static struct colorname* LoadColornameFile(const char* filename) +{ + struct colorname *list=NULL,*tmp=NULL; + char *filepath,*pos,*max; + const char *prefix=""; + char *name,*values,*model; + int nprefix=0,nname,nvalues,nmodel; + struct filemmap fmmap; + boolean mmapfailed; + + filepath=kpse_find_file(filename,kpse_tex_format,false); + if (filepath == NULL) + return NULL; + DEBUG_PRINT(DEBUG_COLOR,("\n OPEN COLOR NAMES:\t'%s'", filepath)); + mmapfailed=MmapFile(filepath,&fmmap); + free(filepath); + if (mmapfailed) + return NULL; + pos=fmmap.data; + max=fmmap.data+fmmap.size; + while (pos<max && *pos!='\\') pos++; + while(pos+9<max && strncmp(pos,"\\endinput",9)!=0) { + if ((pos+20<max && strncmp(pos,"\\def\\colornameprefix",20)==0) + || (pos+32<max + && strncmp(pos,"\\providecommand*\\colornameprefix",32)==0)) { + DEBUG_PRINT(DEBUG_COLOR,("\n \t'%.20s'", pos)); + FINDARG(pos); + prefix=pos; + FINDNAMEEND(pos,nprefix); + DEBUG_PRINT(DEBUG_COLOR,("\n \tCOLOR PREFIX '%.*s'",nprefix,prefix)); + } else if (pos+17<max && strncmp(pos,"\\DefineNamedColor",17)==0) { + DEBUG_PRINT(DEBUG_COLOR,("\n \t'%.17s'", pos)); + model=NULL; + nname=nmodel=nvalues=0; + FINDARG(pos); /* skip first argument */ + FINDARG(pos); /* find second argument: color name */ + name=pos; + FINDNAMEEND(pos,nname); + FINDARG(pos); /* find third argument: color model */ + model=pos; + FINDMODELEND(pos,nmodel); + FINDARG(pos); /* find fourth argument: color values */ + values=pos; + FINDVALEND(pos,nvalues); + tmp=NewColor(prefix,nprefix,name,nname,model,nmodel,values,nvalues); + tmp->next=list; + list=tmp; + } else if ((pos+15<max && strncmp(pos,"\\definecolorset",15)==0) + || (pos+16<max && strncmp(pos,"\\preparecolorset",16)==0)) { + char *model; + DEBUG_PRINT(DEBUG_COLOR,("\n \t'%.15s'", pos)); + FINDARG(pos); /* find first argument: color model */ + model=pos; + FINDMODELEND(pos,nmodel); + FINDARG(pos); /* skip second argument */ + FINDARG(pos); /* skip third argument */ + FINDARG(pos); /* find fourth argument: names, values */ + while(pos<max && *pos!='}'){ + name=pos; + FINDNAMEEND(pos,nname); + pos++; + values=pos; + FINDVALEND(pos,nvalues); + FINDLASTVALEND(pos); + tmp=NewColor(prefix,nprefix,name,nname,model,nmodel,values,nvalues); + tmp->next=list; + list=tmp; + FINDWORD(pos); + } + } else { + pos++; + while (pos<max && *pos!='\\') pos++; + } + } + UnMmapFile(&fmmap); + return(list); +} + +static void ClearXColorPrologue(void) +{ + struct colorname *next; + while (xcp) { + next=xcp->next; + free(xcp); + xcp=next; + } + if (xcpname!=NULL) { + free(xcpname); + xcpname=NULL; + } +} + +void ClearColorNames(void) +{ + struct colorname *next; + while (colornamep) { + next=colornamep->next; + free(colornamep); + colornamep=next; + } + ClearXColorPrologue(); +} + +void InitXColorPrologue(const char* name) +{ + ClearXColorPrologue(); + if ((xcpname=malloc(strlen(name)+1))==NULL) + Fatal("cannot malloc memory for xcolor prologue name"); + strcpy(xcpname,name); +} + +static struct colorname* LoadXColorPrologue(void) +{ + struct colorname *list=NULL,*tmp=NULL; + char *filepath,*pos,*max; + const char *prefix=""; + char *name,*values,*model; + int nprefix=0,nname,nvalues,nmodel; + struct filemmap fmmap; + boolean mmapfailed; + + filepath=kpse_find_file(xcpname,kpse_program_text_format,false); + if (filepath == NULL) + return NULL; + DEBUG_PRINT(DEBUG_COLOR,("\n OPEN XCOLOR PROLOGUE:\t'%s'", filepath)); + mmapfailed = MmapFile(filepath,&fmmap); + free(filepath); + if (mmapfailed) + return NULL; + pos=fmmap.data; + max=fmmap.data+fmmap.size; + while(pos<max) { + while (pos<max && *pos!='/') pos++; + if (*pos=='/') { + nname=nmodel=nvalues=0; + name=++pos; /* first argument: color name */ + FINDPSNAMEEND(pos,nname); + values=++pos; /* second argument: color values */ + FINDVALEND(pos,nvalues); + model=pos+3; /* third argument: color model, prefixed by 'XC' */ + while(pos<max && *pos!=' ' && *pos!='\r' && *pos!='\n') pos++; + nmodel=pos-model; + tmp=NewColor(prefix,nprefix,name,nname,model,nmodel,values,nvalues); + tmp->next=list; + list=tmp; + } + } + UnMmapFile(&fmmap); + return(list); +} + +#define FTO255(a) ((int) (255*a+0.5)) +#define WARN_IF_FAILED(a,b) if (a==b) { page_flags |= PAGE_GAVE_WARN; \ + Warning("missing color-specification value, treated as zero"); } + +#define SKIPSPACES(s) while(s && *s==' ' && *s!='\0') s++ +#define NEXTFLOAT255(c) FTO255(strtod(c,&end)); WARN_IF_FAILED(c,end); c=end +#define NEXTFLOAT(c) strtod(c,&end); WARN_IF_FAILED(c,end); c=end +#define NEXTINT(c) strtol(c,&end,10); WARN_IF_FAILED(c,end); c=end +#define NEXTHEX(c) strtol(c,&end,16); WARN_IF_FAILED(c,end); c=end + +void stringrgb(const char* color,int *r,int *g,int *b) +{ + char* end; + static int unloaded=0; + + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR SPEC:\t'%s' (",color)); + SKIPSPACES(color); + if (strcmp(color,"Black")==0) { + *r = *g = *b = 0; + } else if (strcmp(color,"White")==0) { + *r = *g = *b = 255; + } else if (strncmp(color,"gray ",5)==0) { + color+=5; + *r = *g = *b = NEXTFLOAT255(color); + } else if (strncmp(color,"rgb ",4)==0) { + color+=4; + *r = NEXTFLOAT255(color); + *g = NEXTFLOAT255(color); + *b = NEXTFLOAT255(color); + } else if (strncmp(color,"Gray ",5)==0) { + color+=5; + *r = *g = *b = NEXTINT(color); + } else if (strncmp(color,"RGB ",4)==0) { + color+=4; + *r = NEXTINT(color); + *g = NEXTINT(color); + *b = NEXTINT(color); + } else if (strncmp(color,"HTML ",5)==0) { + color+=5; + *b = NEXTHEX(color); + *r = *b/65536; + *g = *b/256; + *b -= *g*256; + *g -= *r*256; + } else if (strncmp(color,"cmy ",4)==0 + || strncmp(color,"cmyk ",5)==0) { + int c,m,y,k; + color+=3; + k=(*color=='k'); + if (k) + color++; + c = NEXTFLOAT255(color); + m = NEXTFLOAT255(color); + y = NEXTFLOAT255(color); + if (k) + k = NEXTFLOAT255(color); + *r = c+k<255 ? 255-(c+k) : 0; + *g = m+k<255 ? 255-(m+k) : 0; + *b = y+k<255 ? 255-(y+k) : 0; + } else if (strncmp(color,"hsb ",4)==0 + || strncmp(color,"HSB ",4)==0) { + /* The hsb and HSB models really need more presicion. + Use double and convert back*/ + double hu,sa,br,f,R,G,B; + int i; + if (*color=='h') { + color+=4; + hu = NEXTFLOAT(color); + sa = NEXTFLOAT(color); + br = NEXTFLOAT(color); + } else { + color+=4; + hu = (float)NEXTINT(color); hu /= 255; + sa = (float)NEXTINT(color); sa /= 255; + br = (float)NEXTINT(color); br /= 255; + } + i=6*hu; + f=6*hu-i; + switch(i) { + case 0: + R = br*(1-sa*0); G = br*(1-sa*(1-f)); B = br*(1-sa*1); break; + case 1: + R = br*(1-sa*f); G = br*(1-sa*0); B = br*(1-sa*1); break; + case 2: + R = br*(1-sa*1); G = br*(1-sa*0); B = br*(1-sa*(1-f)); break; + case 3: + R = br*(1-sa*1); G = br*(1-sa*f); B = br*(1-sa*0); break; + case 4: + R = br*(1-sa*(1-f)); G = br*(1-sa*1); B = br*(1-sa*0); break; + case 5: + R = br*(1-sa*0); G = br*(1-sa*1); B = br*(1-sa*f); break; + default: + R = br*(1-sa*0); G = br*(1-sa*1); B = br*(1-sa*1); + } + *r=FTO255(R); + *g=FTO255(G); + *b=FTO255(B); + } else { + /* Model not found, probably a color name */ + struct colorname *tmp; + + if (xcp==NULL && xcpname!=NULL) + xcp=LoadXColorPrologue(); + tmp=xcp; + while(tmp!=NULL && strcmp(color,tmp->name)!=0) + tmp=tmp->next; + if (tmp==NULL) { + while (colornamep==NULL && colordef[unloaded]!=NULL) + colornamep=LoadColornameFile(colordef[unloaded++]); + tmp=colornamep; + while(tmp!=NULL && strcmp(color,tmp->name)!=0) { + while (tmp->next==NULL && colordef[unloaded]!=NULL) + tmp->next=LoadColornameFile(colordef[unloaded++]); + tmp=tmp->next; + } + } + if (strcmp(color,tmp->name)==0) { + /* Found: one-level recursion */ + DEBUG_PRINT(DEBUG_COLOR,("\n ---RECURSION--- ")) + stringrgb(tmp->color,r,g,b); + } else { + /* Not found, warn */ + page_flags |= PAGE_GAVE_WARN; + Warning("unimplemented color specification '%s'",color); + } + } + DEBUG_PRINT(DEBUG_COLOR,("%d %d %d) ",*r,*g,*b)) +} + +void background(const char* p) +{ + stringrgb(p, &cstack[0].red, &cstack[0].green, &cstack[0].blue); + DEBUG_PRINT(DEBUG_COLOR,("\n BACKGROUND:\t(%d %d %d) ", + cstack[0].red, cstack[0].green, cstack[0].blue)); +} + +void pushcolor(const char * p) +{ + if ( ++csp == STACK_SIZE ) + Fatal("out of color stack space") ; + stringrgb(p, &cstack[csp].red, &cstack[csp].green, &cstack[csp].blue); + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR PUSH:\t(%d %d %d) ", + cstack[csp].red, cstack[csp].green, cstack[csp].blue)) +} + +void popcolor(void) +{ + if (csp > 1) csp--; /* Last color is global */ + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR POP\t")) +} + +void resetcolorstack(const char * p) +{ + if ( csp > 1 ) + Warning("global color change within nested colors"); + csp=0; + pushcolor(p) ; + DEBUG_PRINT(DEBUG_COLOR,("\n RESET COLOR:\tbottom of stack:")) +} + +void StoreColorStack(struct page_list *tpagep) +{ + int i=0; + + DEBUG_PRINT(DEBUG_COLOR,("\n STORE COLOR STACK:\t %d ", csp)); + tpagep->csp=csp; + while ( i <= csp ) { + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR STACK:\t %d (%d %d %d) ",i, + cstack[i].red, cstack[i].green, cstack[i].blue)); + tpagep->cstack[i].red = cstack[i].red; + tpagep->cstack[i].green = cstack[i].green; + tpagep->cstack[i].blue = cstack[i].blue; + i++; + } +} + +void ReadColorStack(struct page_list *tpagep) +{ + int i=0; + + DEBUG_PRINT(DEBUG_COLOR,("\n READ COLOR STACK:\t %d ", tpagep->csp)); + csp=tpagep->csp; + while ( i <= tpagep->csp ) { + DEBUG_PRINT(DEBUG_COLOR,("\n COLOR STACK:\t %d (%d %d %d) ",i, + cstack[i].red, cstack[i].green, cstack[i].blue)); + cstack[i].red = tpagep->cstack[i].red; + cstack[i].green = tpagep->cstack[i].green; + cstack[i].blue = tpagep->cstack[i].blue; + i++; + } +} + +void StoreBackgroundColor(struct page_list *tpagep) +{ + /* Background color changes affect the _whole_ page */ + tpagep->cstack[0].red = cstack[0].red; + tpagep->cstack[0].green = cstack[0].green; + tpagep->cstack[0].blue = cstack[0].blue; +} |