summaryrefslogtreecommitdiff
path: root/dviware/dvipng/color.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/dvipng/color.c')
-rw-r--r--dviware/dvipng/color.c440
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;
+}