-int
-gfx_destroy (gfx_canvas_t *canvas){
- gfx_node_t *next,*node = canvas->firstnode;
- while(node){
- next = node->next;
- art_free(node->path);
- free(node->text);
- free(node->filename);
- art_free(node);
- node = next;
- }
- art_free(canvas);
- return 0;
-}
-
-static int gfx_save_png (art_u8 *buffer, FILE *fp, long width, long height, long bytes_per_pixel){
- png_structp png_ptr = NULL;
- png_infop info_ptr = NULL;
- int i;
- png_bytep *row_pointers;
- int rowstride = width * bytes_per_pixel;
- png_text text[2];
-
- if (fp == NULL)
- return (1);
-
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
- if (png_ptr == NULL)
- {
- return (1);
- }
- row_pointers = (png_bytepp)png_malloc(png_ptr,
- height*sizeof(png_bytep));
-
- info_ptr = png_create_info_struct(png_ptr);
-
- if (info_ptr == NULL)
- {
- png_free(png_ptr,row_pointers);
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- return (1);
- }
-
- if (setjmp(png_jmpbuf(png_ptr)))
- {
- /* If we get here, we had a problem writing the file */
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return (1);
- }
-
- png_init_io(png_ptr, fp);
- png_set_IHDR (png_ptr, info_ptr,width, height,
- 8, PNG_COLOR_TYPE_RGB_ALPHA,
- PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_DEFAULT,
- PNG_FILTER_TYPE_DEFAULT);
-
- text[0].key = "Software";
- text[0].text = "RRDtool, Tobias Oetiker <tobi@oetike.ch>, http://tobi.oetiker.ch";
- text[0].compression = PNG_TEXT_COMPRESSION_NONE;
- png_set_text (png_ptr, info_ptr, text, 1);
-
- /* lets make this fast */
- /* png_set_filter(png_ptr,0,PNG_FILTER_NONE); */
- png_set_compression_level(png_ptr,1);
- /* png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY); */
- /*
- png_set_filter(png_ptr,PNG_FILTER_TYPE_BASE,PNG_FILTER_SUB);
- png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY);
- png_set_compression_level(png_ptr,Z_BEST_SPEED); */
-
- /* Write header data */
- png_write_info (png_ptr, info_ptr);
- for (i = 0; i < height; i++)
- row_pointers[i] = (png_bytep) (buffer + i*rowstride);
-
- png_write_image(png_ptr, row_pointers);
- png_write_end(png_ptr, info_ptr);
- png_free(png_ptr,row_pointers);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return 1;
-}
-
-
+int gfx_destroy(
+ gfx_canvas_t *canvas)
+{
+ gfx_node_t *next, *node = canvas->firstnode;
+
+ while (node) {
+ next = node->next;
+ art_free(node->path);
+ free(node->text);
+ free(node->filename);
+ art_free(node);
+ node = next;
+ }
+ art_free(canvas);
+ return 0;
+}
+
+static int gfx_save_png(
+ art_u8 * buffer,
+ FILE * fp,
+ long width,
+ long height,
+ long bytes_per_pixel)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+ int i;
+ png_bytep *row_pointers;
+ int rowstride = width * bytes_per_pixel;
+ png_text text[2];
+
+ if (fp == NULL)
+ return (1);
+
+ png_ptr =
+ png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL) {
+ return (1);
+ }
+ row_pointers = (png_bytepp) png_malloc(png_ptr,
+ height * sizeof(png_bytep));
+
+ info_ptr = png_create_info_struct(png_ptr);
+
+ if (info_ptr == NULL) {
+ png_free(png_ptr, row_pointers);
+ png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
+ return (1);
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ /* If we get here, we had a problem writing the file */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return (1);
+ }
+
+ png_init_io(png_ptr, fp);
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ text[0].key = "Software";
+ text[0].text =
+ "RRDtool, Tobias Oetiker <tobi@oetike.ch>, http://tobi.oetiker.ch";
+ text[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ png_set_text(png_ptr, info_ptr, text, 1);
+
+ /* lets make this fast while ending up with some increass in image size */
+ png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
+ /* png_set_filter(png_ptr,0,PNG_FILTER_SUB); */
+ png_set_compression_level(png_ptr, 1);
+ /* png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY); */
+ /*
+ png_set_filter(png_ptr,PNG_FILTER_TYPE_BASE,PNG_FILTER_SUB);
+ png_set_compression_strategy(png_ptr,Z_HUFFMAN_ONLY);
+ png_set_compression_level(png_ptr,Z_BEST_SPEED); */
+
+ /* Write header data */
+ png_write_info(png_ptr, info_ptr);
+ for (i = 0; i < height; i++)
+ row_pointers[i] = (png_bytep) (buffer + i * rowstride);
+
+ png_write_image(png_ptr, row_pointers);
+ png_write_end(png_ptr, info_ptr);
+ png_free(png_ptr, row_pointers);
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ return 1;
+}
+
+
+/* ----- COMMON ROUTINES for pdf, svg and eps */
+#define min3(a, b, c) (a < b ? (a < c ? a : c) : (b < c ? b : c))
+#define max3(a, b, c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
+
+#define PDF_CALC_DEBUG 0
+
+typedef struct pdf_point {
+ double x, y;
+} pdf_point;
+
+typedef struct {
+ double ascender, descender, baselineY;
+ pdf_point sizep, minp, maxp;
+ double x, y, tdx, tdy;
+ double r, cos_r, sin_r;
+ double ma, mb, mc, md, mx, my; /* pdf coord matrix */
+ double tmx, tmy; /* last 2 coords of text coord matrix */
+#if PDF_CALC_DEBUG
+ int debug;
+#endif
+} pdf_coords;
+
+#if PDF_CALC_DEBUG
+static void pdf_dump_calc(
+ gfx_node_t *node,
+ pdf_coords * g)
+{
+ fprintf(stderr, "PDF CALC =============================\n");
+ fprintf(stderr, " '%s' at %f pt\n", node->text, node->size);
+ fprintf(stderr, " align h = %s, v = %s, sizep = %f, %f\n",
+ (node->halign == GFX_H_RIGHT ? "r" :
+ (node->halign == GFX_H_CENTER ? "c" :
+ (node->halign == GFX_H_LEFT ? "l" : "N"))),
+ (node->valign == GFX_V_TOP ? "t" :
+ (node->valign == GFX_V_CENTER ? "c" :
+ (node->valign == GFX_V_BOTTOM ? "b" : "N"))),
+ g->sizep.x, g->sizep.y);
+ fprintf(stderr, " r = %f = %f, cos = %f, sin = %f\n",
+ g->r, node->angle, g->cos_r, g->sin_r);
+ fprintf(stderr, " ascender = %f, descender = %f, baselineY = %f\n",
+ g->ascender, g->descender, g->baselineY);
+ fprintf(stderr, " sizep: %f, %f\n", g->sizep.x, g->sizep.y);
+ fprintf(stderr, " minp: %f, %f maxp = %f, %f\n",
+ g->minp.x, g->minp.y, g->maxp.x, g->maxp.y);
+ fprintf(stderr, " x = %f, y = %f\n", g->x, g->y);
+ fprintf(stderr, " tdx = %f, tdy = %f\n", g->tdx, g->tdy);
+ fprintf(stderr, " GM = %f, %f, %f, %f, %f, %f\n",
+ g->ma, g->mb, g->mc, g->md, g->mx, g->my);
+ fprintf(stderr, " TM = %f, %f, %f, %f, %f, %f\n",
+ g->ma, g->mb, g->mc, g->md, g->tmx, g->tmy);
+}
+#endif
+
+#if PDF_CALC_DEBUG
+#define PDF_DD(x) if (g->debug) x;
+#else
+#define PDF_DD(x)
+#endif
+
+static void pdf_rotate(
+ pdf_coords * g,
+ pdf_point *p)
+{
+ double x2 = g->cos_r * p->x - g->sin_r * p->y;
+ double y2 = g->sin_r * p->x + g->cos_r * p->y;
+
+ PDF_DD(fprintf
+ (stderr, " rotate(%f, %f) -> %f, %f\n", p->x, p->y, x2, y2))
+ p->x = x2;
+ p->y = y2;
+}
+
+
+static void pdf_calc(
+ int page_height,
+ gfx_node_t *node,
+ pdf_coords * g)
+{
+ pdf_point a, b, c;
+
+#if PDF_CALC_DEBUG
+ /* g->debug = !!strstr(node->text, "RevProxy-1") || !!strstr(node->text, "08:00"); */
+ g->debug = !!strstr(node->text, "sekunder")
+ || !!strstr(node->text, "Web");
+#endif
+ g->x = node->x;
+ g->y = page_height - node->y;
+ if (node->angle) {
+ g->r = 2 * M_PI * node->angle / 360.0;
+ g->cos_r = cos(g->r);
+ g->sin_r = sin(g->r);
+ } else {
+ g->r = 0;
+ g->cos_r = 1;
+ g->sin_r = 0;
+ }
+ g->ascender = afm_get_ascender(node->filename, node->size);
+ g->descender = afm_get_descender(node->filename, node->size);
+ g->sizep.x =
+ afm_get_text_width(0, node->filename, node->size, node->tabwidth,
+ node->text);
+ /* seems like libart ignores the descender when doing vertial-align = bottom,
+ so we do that too, to get labels v-aligning properly */
+ g->sizep.y = -g->ascender; /* + afm_get_descender(font->ps_font, node->size); */
+ g->baselineY = -g->ascender - g->sizep.y / 2;
+ a.x = g->sizep.x;
+ a.y = g->sizep.y;
+ b.x = g->sizep.x;
+ b.y = 0;
+ c.x = 0;
+ c.y = g->sizep.y;
+ if (node->angle) {
+ pdf_rotate(g, &a);
+ pdf_rotate(g, &b);
+ pdf_rotate(g, &c);
+ }
+ g->minp.x = min3(a.x, b.x, c.x);
+ g->minp.y = min3(a.y, b.y, c.y);
+ g->maxp.x = max3(a.x, b.x, c.x);
+ g->maxp.y = max3(a.y, b.y, c.y);
+ /* The alignment parameters in node->valign and node->halign
+ specifies the alignment in the non-rotated coordinate system
+ (very unlike pdf/postscript), which complicates matters.
+ */
+ switch (node->halign) {
+ case GFX_H_RIGHT:
+ g->tdx = -g->maxp.x;
+ break;
+ case GFX_H_CENTER:
+ g->tdx = -(g->maxp.x + g->minp.x) / 2;
+ break;
+ case GFX_H_LEFT:
+ g->tdx = -g->minp.x;
+ break;
+ case GFX_H_NULL:
+ g->tdx = 0;
+ break;
+ }
+ switch (node->valign) {
+ case GFX_V_TOP:
+ g->tdy = -g->maxp.y;
+ break;
+ case GFX_V_CENTER:
+ g->tdy = -(g->maxp.y + g->minp.y) / 2;
+ break;
+ case GFX_V_BOTTOM:
+ g->tdy = -g->minp.y;
+ break;
+ case GFX_V_NULL:
+ g->tdy = 0;
+ break;
+ }
+ g->ma = g->cos_r;
+ g->mb = g->sin_r;
+ g->mc = -g->sin_r;
+ g->md = g->cos_r;
+ g->mx = g->x + g->tdx;
+ g->my = g->y + g->tdy;
+ g->tmx = g->mx - g->ascender * g->mc;
+ g->tmy = g->my - g->ascender * g->md;
+ PDF_DD(pdf_dump_calc(node, g))
+}
+