/** \file * \brief SVG driver * * See Copyright Notice in cd.h */ #include #include #include #include #include #include #include "cd.h" #include "wd.h" #include "cd_private.h" #include "cdsvg.h" #include "lodepng.h" #include "base64.h" typedef struct _cdCtxCanvas { cdCanvas* canvas; char* filename; char bgColor[20]; char fgColor[20]; char linecap[10]; char linejoin[10]; char linestyle[20]; char poly[256]; char pattern[30]; char font_weight[15]; char font_style[15]; char font_decoration[15]; char font_family[256]; char font_size[10]; int backopacity; int writemode; int linewidth; int hatchboxsize; double xmatrix[6]; /* Transformation matrix that includes axis inversion */ /* private */ int last_fill_mode; int last_clip_path; int clip_off_control; int clip_polygon; int transform_control; FILE* file; } cdCtxCanvas; static void cdkillcanvas(cdCtxCanvas* ctxcanvas) { while(ctxcanvas->clip_off_control > 0) { fprintf(ctxcanvas->file, "\n"); --ctxcanvas->clip_off_control; } if(ctxcanvas->transform_control) fprintf(ctxcanvas->file, "\n"); fprintf(ctxcanvas->file, "\n"); fprintf(ctxcanvas->file, "\n"); free(ctxcanvas->filename); fclose(ctxcanvas->file); memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); free(ctxcanvas); } static void setclip_area(cdCtxCanvas *ctxcanvas) { cdRect* clip_rect = &ctxcanvas->canvas->clip_rect; fprintf(ctxcanvas->file, "\n", ++ctxcanvas->last_clip_path); if (ctxcanvas->canvas->use_matrix) { cdPoint poly[4]; poly[0].x = clip_rect->xmin; poly[0].y = clip_rect->ymin; poly[1].x = clip_rect->xmin; poly[1].y = clip_rect->ymax; poly[2].x = clip_rect->xmax; poly[2].y = clip_rect->ymax; poly[3].x = clip_rect->xmax; poly[3].y = clip_rect->ymin; sprintf(ctxcanvas->poly, "%g,%g", (double)poly[0].x, (double)poly[0].y); sprintf(ctxcanvas->poly, "%s %g,%g", ctxcanvas->poly, (double)poly[1].x, (double)poly[1].y); sprintf(ctxcanvas->poly, "%s %g,%g", ctxcanvas->poly, (double)poly[2].x, (double)poly[2].y); sprintf(ctxcanvas->poly, "%s %g,%g", ctxcanvas->poly, (double)poly[3].x, (double)poly[3].y); fprintf(ctxcanvas->file, "\n", ctxcanvas->poly); } else { double x, y, w, h; x = (double)clip_rect->xmin; y = (double)clip_rect->ymin; w = (double)(clip_rect->xmax - clip_rect->xmin + 1); h = (double)(clip_rect->ymax - clip_rect->ymin + 1); fprintf(ctxcanvas->file, "\n", x, y, w, h); } fprintf(ctxcanvas->file, "\n"); fprintf(ctxcanvas->file, "\n", ctxcanvas->last_clip_path); ++ctxcanvas->clip_off_control; } int cdclip(cdCtxCanvas *ctxcanvas, int clip_mode) { switch (clip_mode) { case CD_CLIPOFF: if(ctxcanvas->clip_off_control > 0) { fprintf(ctxcanvas->file, "\n"); --ctxcanvas->clip_off_control; } break; case CD_CLIPAREA: setclip_area(ctxcanvas); break; case CD_CLIPPOLYGON: if (ctxcanvas->clip_polygon) { fprintf(ctxcanvas->file, "\n", ctxcanvas->last_clip_path); ++ctxcanvas->clip_off_control; } break; } return clip_mode; } static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) { if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) { ctxcanvas->canvas->clip_rect.xmin = (int)xmin; ctxcanvas->canvas->clip_rect.ymin = (int)ymin; ctxcanvas->canvas->clip_rect.xmax = (int)xmax; ctxcanvas->canvas->clip_rect.ymax = (int)ymax; cdclip(ctxcanvas, CD_CLIPAREA); } } static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) { cdfcliparea(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); } static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) { if (matrix) { /* Matrix identity */ ctxcanvas->xmatrix[0] = 1; ctxcanvas->xmatrix[1] = 0; ctxcanvas->xmatrix[2] = 0; ctxcanvas->xmatrix[3] = -1; ctxcanvas->xmatrix[4] = 0; ctxcanvas->xmatrix[5] = (ctxcanvas->canvas->h-1); if(ctxcanvas->transform_control) { fprintf(ctxcanvas->file, "\n"); --ctxcanvas->transform_control; } cdMatrixMultiply(matrix, ctxcanvas->xmatrix); ++ctxcanvas->transform_control; fprintf(ctxcanvas->file, "\n", ctxcanvas->xmatrix[0], ctxcanvas->xmatrix[1], ctxcanvas->xmatrix[2], ctxcanvas->xmatrix[3], ctxcanvas->xmatrix[4], ctxcanvas->xmatrix[5]); ctxcanvas->canvas->invert_yaxis = 0; } else { ctxcanvas->canvas->invert_yaxis = 1; } } static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) { fprintf(ctxcanvas->file, "\n", x1, y1, x2, y2, ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) { cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); } static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) { fprintf(ctxcanvas->file, "\n", xmin, ymin, xmax-xmin, ymax-ymin, ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) { cdfrect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); } static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) { fprintf(ctxcanvas->file, "\n", xmin, ymin, xmax-xmin, ymax-ymin, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : ctxcanvas->pattern, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : "none", ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) { cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); } static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) { double arcStartX, arcStartY, arcEndX, arcEndY; int largeArc = 0; if((a1 == 0.0) && (a2 == 360.0)) /* an ellipse/circle */ { fprintf(ctxcanvas->file, "\n", xc, yc, w/2, h/2, ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); return; } if (ctxcanvas->canvas->use_matrix) /* Transformation active */ { double temp = 360 - a1; a1 = 360 - a2; a2 = temp; } arcStartX = (xc+(w/2)*cos(a1*CD_DEG2RAD)); arcStartY = (yc-(h/2)*sin(a1*CD_DEG2RAD)); arcEndX = (xc+(w/2)*cos(a2*CD_DEG2RAD)); arcEndY = (yc-(h/2)*sin(a2*CD_DEG2RAD)); if((a2-a1) > 180.0) largeArc = 1; fprintf(ctxcanvas->file, "\n", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) { cdfarc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); } static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) { double arcStartX, arcStartY, arcEndX, arcEndY; int largeArc = 0; if((a1 == 0.0) && (a2 == 360.0)) /* an ellipse/circle */ { fprintf(ctxcanvas->file, "\n", xc, yc, w/2, h/2, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : ctxcanvas->pattern, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : "none", ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); return; } if (ctxcanvas->canvas->use_matrix) /* Transformation active */ { double temp = 360 - a1; a1 = 360 - a2; a2 = temp; } arcStartX = (xc+(w/2)*cos(a1*CD_DEG2RAD)); arcStartY = (yc-(h/2)*sin(a1*CD_DEG2RAD)); arcEndX = (xc+(w/2)*cos(a2*CD_DEG2RAD)); arcEndY = (yc-(h/2)*sin(a2*CD_DEG2RAD)); if((a2-a1) > 180.0) largeArc = 1; fprintf(ctxcanvas->file, "\n", xc, yc, arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : ctxcanvas->pattern, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : "none", ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) { cdfsector(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); } static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) { double arcStartX, arcStartY, arcEndX, arcEndY; int largeArc = 0; if (ctxcanvas->canvas->use_matrix) /* Transformation active */ { double temp = 360 - a1; a1 = 360 - a2; a2 = temp; } arcStartX = (xc+(w/2)*cos(a1*CD_DEG2RAD)); arcStartY = (yc-(h/2)*sin(a1*CD_DEG2RAD)); arcEndX = (xc+(w/2)*cos(a2*CD_DEG2RAD)); arcEndY = (yc-(h/2)*sin(a2*CD_DEG2RAD)); if((a2-a1) > 180.0) largeArc = 1; fprintf(ctxcanvas->file, "\n", arcStartX, arcStartY, w/2, h/2, largeArc, arcEndX, arcEndY, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : ctxcanvas->pattern, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : "none", ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) { cdfchord(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); } static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text, int len) { char anchor[10]; char alignment[20]; int i; switch (ctxcanvas->canvas->text_alignment) { case CD_NORTH: case CD_NORTH_EAST: case CD_NORTH_WEST: sprintf(alignment, "%s", "text-before-edge"); break; case CD_SOUTH: case CD_SOUTH_EAST: case CD_SOUTH_WEST: sprintf(alignment, "%s", "text-after-edge"); break; case CD_CENTER: case CD_EAST: case CD_WEST: sprintf(alignment, "%s", "middle"); break; case CD_BASE_CENTER: case CD_BASE_LEFT: case CD_BASE_RIGHT: sprintf(alignment, "%s", "baseline"); break; } switch (ctxcanvas->canvas->text_alignment) { case CD_WEST: case CD_NORTH_WEST: case CD_SOUTH_WEST: case CD_BASE_LEFT: sprintf(anchor, "%s", "start"); break; case CD_CENTER: case CD_NORTH: case CD_SOUTH: case CD_BASE_CENTER: sprintf(anchor, "%s", "middle"); break; case CD_EAST: case CD_NORTH_EAST: case CD_SOUTH_EAST: case CD_BASE_RIGHT: sprintf(anchor, "%s", "end"); break; } /* Characters are putting in file using hexadecimal representations */ /* string no print special characters, like cedilla and acutes */ /* Future solution: use glyphs in embedded fonts (TO DO)*/ if (ctxcanvas->canvas->text_orientation != 0) { double text_cos = cos(ctxcanvas->canvas->text_orientation*CD_DEG2RAD); double text_sin = sin(ctxcanvas->canvas->text_orientation*CD_DEG2RAD); if (ctxcanvas->canvas->use_matrix) /* Transformation active */ fprintf(ctxcanvas->file, "\n", text_cos, text_sin, text_sin, -text_cos, x, y, ctxcanvas->font_family, ctxcanvas->font_size, ctxcanvas->font_style, ctxcanvas->font_weight, ctxcanvas->font_decoration, anchor, alignment, ctxcanvas->fgColor); else fprintf(ctxcanvas->file, "\n", text_cos, -text_sin, text_sin, text_cos, x, y, ctxcanvas->font_family, ctxcanvas->font_size, ctxcanvas->font_style, ctxcanvas->font_weight, ctxcanvas->font_decoration, anchor, alignment, ctxcanvas->fgColor); for(i = 0; i < len; i++) fprintf(ctxcanvas->file, "&#x%02X;", (unsigned char)text[i]); fprintf(ctxcanvas->file, "\n\n"); } else { fprintf(ctxcanvas->file, "\n", x, y, ctxcanvas->font_family, ctxcanvas->font_size, ctxcanvas->font_style, ctxcanvas->font_weight, ctxcanvas->font_decoration, anchor, alignment, ctxcanvas->fgColor); for(i = 0; i < len; i++) fprintf(ctxcanvas->file, "&#x%02X;", (unsigned char)text[i]); fprintf(ctxcanvas->file, "\n\n"); } } static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text, int len) { cdftext(ctxcanvas, (double)x, (double)y, text, len); } static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) { int i, m = 0; char rule[8]; if(mode == CD_BEZIER) m = 1; sprintf(ctxcanvas->poly, "%g,%g", poly[m].x, poly[m].y); for(i = m+1; ipoly, "%s %g,%g", ctxcanvas->poly, poly[i].x, poly[i].y); switch (mode) { case CD_CLOSED_LINES : fprintf(ctxcanvas->file, "\n", ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity, ctxcanvas->poly); break; case CD_OPEN_LINES : fprintf(ctxcanvas->file, "\n", ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity, ctxcanvas->poly); break; case CD_BEZIER : fprintf(ctxcanvas->file, "\n", poly[0].x, poly[0].y, ctxcanvas->poly, ctxcanvas->fgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); break; case CD_FILL : if(ctxcanvas->canvas->fill_mode==CD_EVENODD) sprintf(rule, "%s", "evenodd"); else sprintf(rule, "%s", "nonzero"); fprintf(ctxcanvas->file, "\n", (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : ctxcanvas->pattern, rule, (ctxcanvas->canvas->interior_style == CD_SOLID) ? ctxcanvas->fgColor : "none", ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity, ctxcanvas->poly); break; case CD_CLIP: fprintf(ctxcanvas->file, "\n", ++ctxcanvas->last_clip_path); fprintf(ctxcanvas->file, "\n", ctxcanvas->poly); fprintf(ctxcanvas->file, "\n"); ctxcanvas->clip_polygon = 1; if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) cdclip(ctxcanvas, CD_CLIPPOLYGON); break; } } static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) { int i; cdfPoint* newPoly = NULL; newPoly = (cdfPoint*)malloc(sizeof(cdfPoint)*(n+1)); for(i = 0; i < n; i++) { newPoly[i].x = (double)poly[i].x; newPoly[i].y = (double)poly[i].y; } cdfpoly(ctxcanvas, mode, (cdfPoint*)newPoly, n); free(newPoly); } static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity) { ctxcanvas->backopacity = opacity; return opacity; } static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) { switch (style) { case CD_CONTINUOUS : /* empty dash */ sprintf(ctxcanvas->linestyle, "%s", "0"); break; case CD_DASHED : sprintf(ctxcanvas->linestyle, "%s", "6,2"); break; case CD_DOTTED : sprintf(ctxcanvas->linestyle, "%s", "2,2"); break; case CD_DASH_DOT : sprintf(ctxcanvas->linestyle, "%s", "6,2,2,2"); break; case CD_DASH_DOT_DOT : sprintf(ctxcanvas->linestyle, "%s", "6,2,2,2,2,2"); break; case CD_CUSTOM : { int i; sprintf(ctxcanvas->linestyle, "%d", ctxcanvas->canvas->line_dashes[0]); for (i = 1; i < ctxcanvas->canvas->line_dashes_count; i++) sprintf(ctxcanvas->linestyle, "%s, %d", ctxcanvas->linestyle, ctxcanvas->canvas->line_dashes[i]); } break; } return style; } static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) { ctxcanvas->linewidth = width; return width; } static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) { if(cap == CD_CAPROUND) sprintf(ctxcanvas->linecap, "%s", "round"); else if(cap == CD_CAPSQUARE) sprintf(ctxcanvas->linecap, "%s", "square"); else /* CD_CAPFLAT */ sprintf(ctxcanvas->linecap, "%s", "butt"); return cap; } static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) { if(join == CD_ROUND) sprintf(ctxcanvas->linejoin, "%s", "round"); else if(join == CD_BEVEL) sprintf(ctxcanvas->linejoin, "%s", "bevel"); else /* CD_MITER */ sprintf(ctxcanvas->linejoin, "%s", "miter"); return join; } static int cdhatch(cdCtxCanvas *ctxcanvas, int style) { int hsize = ctxcanvas->hatchboxsize - 1; int hhalf = hsize / 2; ctxcanvas->canvas->interior_style = CD_HATCH; sprintf(ctxcanvas->pattern, "url(#pattern%d)", ++ctxcanvas->last_fill_mode); fprintf(ctxcanvas->file, "\n", ctxcanvas->last_fill_mode, hsize, hsize); switch(style) { case CD_HORIZONTAL: fprintf(ctxcanvas->file, "\n", 0, hhalf, hsize, hhalf, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; case CD_VERTICAL: fprintf(ctxcanvas->file, "\n", hhalf, 0, hhalf, hsize, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; case CD_BDIAGONAL: fprintf(ctxcanvas->file, "\n", 0, hsize, hsize, 0, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; case CD_FDIAGONAL: fprintf(ctxcanvas->file, "\n", 0, 0, hsize, hsize, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; case CD_CROSS: fprintf(ctxcanvas->file, "\n", hsize, 0, hsize, hsize, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); fprintf(ctxcanvas->file, "\n", 0, hhalf, hsize, hhalf, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; case CD_DIAGCROSS: fprintf(ctxcanvas->file, "\n", 0, 0, hsize, hsize, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); fprintf(ctxcanvas->file, "\n", hsize, 0, 0, hsize, (ctxcanvas->canvas->back_opacity != CD_OPAQUE) ? ctxcanvas->fgColor : ctxcanvas->bgColor, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->backopacity); break; } fprintf(ctxcanvas->file, "\n"); return style; } static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)) { int i, j; unsigned char r, g, b; char color[20]; sprintf(ctxcanvas->pattern, "url(#pattern%d)", ++ctxcanvas->last_fill_mode); fprintf(ctxcanvas->file, "\n", ctxcanvas->last_fill_mode, n, m); for (j = 0; j < m; j++) { for (i = 0; i < n; i++) { int ret = data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b); if (ret == -1) continue; sprintf(color, "rgb(%d,%d,%d)", (int)r, (int)g, (int)b); fprintf(ctxcanvas->file, "\n", (double)i, (double)j, 1.0, 1.0, color, ctxcanvas->backopacity); } } fprintf(ctxcanvas->file, "\n"); } static int long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) { long* long_data = (long*)data; (void)ctxcanvas; cdDecodeColor(long_data[j*n+i], r, g, b); return 1; } static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) { ctxcanvas->canvas->interior_style = CD_PATTERN; make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); } static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) { int ret = 1; unsigned char* uchar_data = (unsigned char*)data; if (uchar_data[j*n+i]) { cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); ret = 1; } else { cdDecodeColor(ctxcanvas->canvas->background, r, g, b); if (ctxcanvas->canvas->back_opacity==CD_TRANSPARENT) ret = -1; } return ret; } static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) { ctxcanvas->canvas->interior_style = CD_STIPPLE; make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); } static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size) { /* Define type_face and size */ if(type_face != NULL) sprintf(ctxcanvas->font_family, "%s", type_face); if(size > 0) sprintf(ctxcanvas->font_size, "%dpt", size); else sprintf(ctxcanvas->font_size, "%dpx", (-1)*size); if(style != -1) { /* Default: CD_PLAIN */ sprintf(ctxcanvas->font_weight, "%s", "normal"); sprintf(ctxcanvas->font_style, "%s", "normal"); sprintf(ctxcanvas->font_decoration, "%s", "none"); /* Define styles and decorations */ if (style & CD_BOLD) sprintf(ctxcanvas->font_weight, "%s", "bold"); if (style & CD_ITALIC) sprintf(ctxcanvas->font_style, "%s", "italic"); if (style & CD_STRIKEOUT) sprintf(ctxcanvas->font_decoration, "%s", "line-through"); if (style & CD_UNDERLINE) sprintf(ctxcanvas->font_decoration, "%s", "underline"); } return 1; } static long cdbackground(cdCtxCanvas *ctxcanvas, long int color) { unsigned char r, g, b; cdDecodeColor(color, &r, &g, &b); sprintf(ctxcanvas->bgColor, "rgb(%d,%d,%d)", (int)r, (int)g, (int)b); return color; } static long cdforeground(cdCtxCanvas *ctxcanvas, long int color) { unsigned char r, g, b; cdDecodeColor(color, &r, &g, &b); sprintf(ctxcanvas->fgColor, "rgb(%d,%d,%d)", (int)r, (int)g, (int)b); return color; } static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) { int i, j, d, rw, rh, rgb_size, buffer_size, target_size; unsigned char* rgb_data, *rgb_buffer; LodePNG_Encoder encoder; char* rgb_target; if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; rw = xmax-xmin+1; rh = ymax-ymin+1; rgb_size = 4*rw*rh; rgb_data = (unsigned char*)malloc(rgb_size); if (!rgb_data) return; d = 0; for (i=ymax; i>=ymin; i--) { for (j=xmin; j<=xmax; j++) { rgb_data[d] = r[i*iw+j]; d++; rgb_data[d] = g[i*iw+j]; d++; rgb_data[d] = b[i*iw+j]; d++; rgb_data[d] = (unsigned char)0xFF; d++; } } LodePNG_Encoder_init(&encoder); LodePNG_encode(&encoder, &rgb_buffer, &(size_t)buffer_size, rgb_data, rw, rh); target_size = (buffer_size+2)/3*4+1; rgb_target = (char*)malloc(target_size); base64_encode(rgb_buffer, buffer_size, rgb_target, target_size); if (ctxcanvas->canvas->use_matrix) /* Transformation active */ fprintf(ctxcanvas->file, "\n", 1, 0, 0, -1, x, y+h, w, h, rgb_target); else fprintf(ctxcanvas->file, "\n", 1, 0, 0, 1, x, y-h, w, h, rgb_target); free(rgb_data); free(rgb_buffer); free(rgb_target); LodePNG_Encoder_cleanup(&encoder); } static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) { int i, j, d, rw, rh, rgb_size, buffer_size, target_size; unsigned char* rgb_data, *rgb_buffer; LodePNG_Encoder encoder; char* rgb_target; if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; rw = xmax-xmin+1; rh = ymax-ymin+1; rgb_size = 4*rw*rh; rgb_data = (unsigned char*)malloc(rgb_size); if (!rgb_data) return; d = 0; for (i=ymax; i>=ymin; i--) { for (j=xmin; j<=xmax; j++) { rgb_data[d] = r[i*iw+j]; d++; rgb_data[d] = g[i*iw+j]; d++; rgb_data[d] = b[i*iw+j]; d++; rgb_data[d] = a[i*iw+j]; d++; } } LodePNG_Encoder_init(&encoder); LodePNG_encode(&encoder, &rgb_buffer, &(size_t)buffer_size, rgb_data, rw, rh); target_size = (buffer_size+2)/3*4+1; rgb_target = (char*)malloc(target_size); base64_encode(rgb_buffer, buffer_size, rgb_target, target_size); if (ctxcanvas->canvas->use_matrix) /* Transformation active */ fprintf(ctxcanvas->file, "\n", 1, 0, 0, -1, x, y+h, w, h, rgb_target); else fprintf(ctxcanvas->file, "\n", 1, 0, 0, 1, x, y-h, w, h, rgb_target); free(rgb_data); free(rgb_buffer); free(rgb_target); LodePNG_Encoder_cleanup(&encoder); } static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) { int i, j, d, rw, rh, rgb_size, buffer_size, target_size; unsigned char* rgb_data, *rgb_buffer; LodePNG_Encoder encoder; char* rgb_target; if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; rw = xmax-xmin+1; rh = ymax-ymin+1; rgb_size = 4*rw*rh; rgb_data = (unsigned char*)malloc(rgb_size); if (!rgb_data) return; d = 0; for (i=ymax; i>=ymin; i--) { for (j=xmin; j<=xmax; j++) { unsigned char r, g, b; cdDecodeColor(colors[index[i*iw+j]], &r, &g, &b); rgb_data[d] = r; d++; rgb_data[d] = g; d++; rgb_data[d] = b; d++; rgb_data[d] = (unsigned char)0xFF; d++; } } LodePNG_Encoder_init(&encoder); LodePNG_encode(&encoder, &rgb_buffer, &(size_t)buffer_size, rgb_data, rw, rh); target_size = (buffer_size+2)/3*4+1; rgb_target = (char*)malloc(target_size); base64_encode(rgb_buffer, buffer_size, rgb_target, target_size); if (ctxcanvas->canvas->use_matrix) /* Transformation active */ fprintf(ctxcanvas->file, "\n", 1, 0, 0, -1, x, y+h, w, h, rgb_target); else fprintf(ctxcanvas->file, "\n", 1, 0, 0, 1, x, y-h, w, h, rgb_target); free(rgb_data); free(rgb_buffer); free(rgb_target); LodePNG_Encoder_cleanup(&encoder); } static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) { unsigned char r, g, b; cdDecodeColor(color, &r, &g, &b); fprintf(ctxcanvas->file, "\n", x, y, r, g, b, r, g, b, ctxcanvas->linewidth, ctxcanvas->linecap, ctxcanvas->linejoin, ctxcanvas->linestyle, ctxcanvas->backopacity); } static void cdcreatecanvas(cdCanvas *canvas, void *data) { char filename[10240] = ""; char* strdata = (char*)data; double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; cdCtxCanvas* ctxcanvas; int size; strdata += cdGetFileName(strdata, filename); if (filename[0] == 0) return; sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); ctxcanvas->file = fopen(filename, "w"); if (!ctxcanvas->file) { free(ctxcanvas); return; } size = strlen(filename); ctxcanvas->filename = malloc(size+1); memcpy(ctxcanvas->filename, filename, size+1); /* store the base canvas */ ctxcanvas->canvas = canvas; /* update canvas context */ canvas->w = (int)(w_mm * res); canvas->h = (int)(h_mm * res); canvas->w_mm = w_mm; canvas->h_mm = h_mm; canvas->bpp = 24; canvas->xres = res; canvas->yres = res; canvas->invert_yaxis = 1; /* update canvas context */ canvas->ctxcanvas = ctxcanvas; ctxcanvas->last_fill_mode = -1; ctxcanvas->last_clip_path = -1; ctxcanvas->clip_off_control = 0; ctxcanvas->transform_control = 0; ctxcanvas->clip_polygon = 0; ctxcanvas->hatchboxsize = 8; fprintf(ctxcanvas->file, "\n"); fprintf(ctxcanvas->file, "\n", canvas->w, canvas->h, canvas->w, canvas->h); fprintf(ctxcanvas->file, "\n"); } static void cdinittable(cdCanvas* canvas) { canvas->cxPixel = cdpixel; canvas->cxLine = cdline; canvas->cxPoly = cdpoly; canvas->cxRect = cdrect; canvas->cxBox = cdbox; canvas->cxArc = cdarc; canvas->cxSector = cdsector; canvas->cxChord = cdchord; canvas->cxText = cdtext; canvas->cxClip = cdclip; canvas->cxClipArea = cdcliparea; canvas->cxFont = cdfont; canvas->cxPutImageRectRGB = cdputimagerectrgb; canvas->cxPutImageRectRGBA = cdputimagerectrgba; canvas->cxPutImageRectMap = cdputimagerectmap; canvas->cxFLine = cdfline; canvas->cxFPoly = cdfpoly; canvas->cxFRect = cdfrect; canvas->cxFBox = cdfbox; canvas->cxFArc = cdfarc; canvas->cxFSector = cdfsector; canvas->cxFChord = cdfchord; canvas->cxFText = cdftext; canvas->cxFClipArea = cdfcliparea; canvas->cxBackOpacity = cdbackopacity; canvas->cxLineStyle = cdlinestyle; canvas->cxLineWidth = cdlinewidth; canvas->cxLineCap = cdlinecap; canvas->cxLineJoin = cdlinejoin; canvas->cxHatch = cdhatch; canvas->cxStipple = cdstipple; canvas->cxPattern = cdpattern; canvas->cxBackground = cdbackground; canvas->cxForeground = cdforeground; canvas->cxTransform = cdtransform; canvas->cxKillCanvas = (void (*)(cdCtxCanvas*))cdkillcanvas; } static cdContext cdSVGContext = { CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_PALETTE | CD_CAP_REGION | CD_CAP_IMAGESRV | CD_CAP_WRITEMODE | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE | CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB), 0, cdcreatecanvas, cdinittable, NULL, NULL, }; cdContext* cdContextSVG(void) { return &cdSVGContext; }