/****************************************************************************
- * RRDtool 1.2.6 Copyright by Tobi Oetiker, 1997-2005
+ * RRDtool 1.2.13 Copyright by Tobi Oetiker, 1997-2006
****************************************************************************
* rrd_gfx.c graphics wrapper for rrdtool
**************************************************************************/
/* #define DEBUG */
#ifdef DEBUG
-# define DPRINT(x) (void)(printf x, printf("\n"))
+# define DPRINTF(...) fprintf(stderr, __VA_ARGS__);
#else
-# define DPRINT(x)
+# define DPRINTF(...)
#endif
#include "rrd_tool.h"
#include <png.h>
struct gfx_string_s {
unsigned int width;
unsigned int height;
- size_t count; /* number of characters */
+ int count; /* number of characters */
gfx_char glyphs;
size_t num_glyphs;
FT_BBox bbox;
FT_Init_FreeType( &library );
error = FT_New_Face( library, font, 0, &face );
- if ( error ) return -1;
+ if ( error ) {
+ FT_Done_FreeType(library);
+ return -1;
+ }
error = FT_Set_Char_Size(face, size*64,size*64, 100,100);
- if ( error ) return -1;
-
+ if ( error ) {
+ FT_Done_FreeType(library);
+ return -1;
+ }
string = gfx_string_create( canvas, face, text, rotation, tabwidth, size );
text_width = string->width;
gfx_string_destroy(string);
FT_UInt previous;
FT_Vector ft_pen;
- gfx_string string;
+ gfx_string string = (gfx_string) malloc (sizeof(struct gfx_string_s));
+
gfx_char glyph; /* current glyph in table */
- unsigned int n;
+ int n;
int error;
int gottab = 0;
+
+#ifdef HAVE_MBSTOWCS
+ wchar_t *cstr;
+ size_t clen = strlen(text)+1;
+ cstr = malloc(sizeof(wchar_t) * clen); /* yes we are allocating probably too much here, I know */
+ string->count=mbstowcs(cstr,text,clen);
+ if ( string->count == -1){
+ /* conversion did not work, so lets fall back to just use what we got */
+ string->count=clen-1;
+ for(n=0;text[n] != '\0';n++){
+ cstr[n]=(unsigned char)text[n];
+ }
+ }
+#else
+ char *cstr = strdup(text);
+ string->count = strlen (text);
+#endif
+
ft_pen.x = 0; /* start at (0,0) !! */
ft_pen.y = 0;
- string = (gfx_string) malloc (sizeof(struct gfx_string_s));
+
string->width = 0;
string->height = 0;
- string->count = strlen (text);
string->glyphs = (gfx_char) calloc (string->count,sizeof(struct gfx_char_s));
string->num_glyphs = 0;
string->transform.xx = (FT_Fixed)( cos(M_PI*(rotation)/180.0)*0x10000);
use_kerning = FT_HAS_KERNING(face);
previous = 0;
glyph = string->glyphs;
- for (n=0; n<string->count;glyph++) {
+ for (n=0; n<string->count;glyph++,n++) {
FT_Vector vec;
/* handle the tabs ...
have a witespace glyph inserted, but set its width such that the distance
of the new right edge is x times tabwidth from 0,0 where x is an integer. */
- unsigned char letter = text[n];
+ unsigned int letter = cstr[n];
+ letter = afm_fix_osx_charset(letter); /* unsafe macro */
gottab = 0;
- if (letter == '\\' && n+1 < string->count && text[n+1] == 't'){
+ if (letter == '\\' && n+1 < string->count && cstr[n+1] == 't'){
/* we have a tab here so skip the backslash and
set t to ' ' so that we get a white space */
gottab = 1;
glyph->pos.x = 0;
glyph->pos.y = 0;
glyph->image = NULL;
-
glyph->index = FT_Get_Char_Index( face, letter );
/* compute glyph origin */
canvas->aa_type == AA_LIGHT ? FT_LOAD_TARGET_LIGHT :
FT_LOAD_TARGET_MONO : FT_LOAD_TARGET_MONO);
if (error) {
- fprintf (stderr, "couldn't load glyph: %c\n", letter);
+ DPRINTF("couldn't load glyph: %c\n", letter)
continue;
}
error = FT_Get_Glyph (slot, &glyph->image);
if (error) {
- fprintf (stderr, "couldn't get glyph from slot: %c\n", letter);
+ DPRINTF("couldn't get glyph %c from slot %d\n", letter, (int)slot)
continue;
}
/* if we are in tabbing mode, we replace the tab with a space and shift the position
FT_Vector_Transform (&vec, &string->transform);
error = FT_Glyph_Transform (glyph->image, &string->transform, &vec);
if (error) {
- fprintf (stderr, "couldn't transform glyph\n");
+ DPRINTF("couldn't transform glyph id %d\n", letter)
continue;
}
canvas->aa_type == AA_LIGHT ? FT_RENDER_MODE_LIGHT :
FT_RENDER_MODE_MONO : FT_RENDER_MODE_MONO, 0, 1);
if (error) {
- fprintf (stderr, "couldn't convert glyph to bitmap\n");
+ DPRINTF("couldn't convert glyph id %d to bitmap\n", letter)
continue;
}
/* increment number of glyphs */
previous = glyph->index;
string->num_glyphs++;
- n++;
-
}
+ free(cstr);
/* printf ("number of glyphs = %d\n", string->num_glyphs);*/
compute_string_bbox( string );
/* the last character was a tab */
string->width = string->bbox.xMax - string->bbox.xMin;
} */
string->height = string->bbox.yMax - string->bbox.yMin;
-
return string;
}
&face );
if ( error ) {
rrd_set_error("failed to load %s",node->filename);
+
break;
}
error = FT_Set_Char_Size(face, /* handle to face object */
pen_x += vec.x/64;
pen_y += vec.y/64;
glyph = string->glyphs;
- for(n=0; n<string->num_glyphs; ++n, ++glyph) {
+ for(n=0; n<string->num_glyphs; n++, glyph++) {
int gr;
FT_Glyph image;
FT_BitmapGlyph bit;
/* long buf_x,comp_n; */
/* make copy to transform */
if (! glyph->image) {
- fprintf (stderr, "no image\n");
+ DPRINTF("no image\n")
continue;
}
error = FT_Glyph_Copy (glyph->image, &image);
if (error) {
- fprintf (stderr, "couldn't copy image\n");
+ DPRINTF("couldn't copy image\n")
continue;
}
static void svg_write_text(FILE *fp, const char *text)
{
- const unsigned char *p, *start, *last;
- unsigned int ch;
- p = (const unsigned char*)text;
- if (!p)
- return;
- /* trim leading spaces */
- while (*p == ' ')
- p++;
- start = p;
- /* trim trailing spaces */
- last = p - 1;
- while ((ch = *p) != 0) {
- if (ch != ' ')
- last = p;
- p++;
- }
- /* encode trimmed text */
- p = start;
- while (p <= last) {
+#ifdef HAVE_MBSTOWCS
+ size_t clen;
+ wchar_t *p, *cstr, ch;
+ int text_count;
+ if (!text)
+ return;
+ clen = strlen(text) + 1;
+ cstr = malloc(sizeof(wchar_t) * clen);
+ text_count = mbstowcs(cstr, text, clen);
+ if (text_count == -1)
+ text_count = mbstowcs(cstr, "Enc-Err", 6);
+ p = cstr;
+#else
+ unsigned char *p = text;
+ unsigned char *cstr;
+ char ch;
+ if (!p)
+ return;
+#endif
+ while (1) {
ch = *p++;
- ch = afm_host2unicode(ch); /* unsafe macro */
+ ch = afm_fix_osx_charset(ch); /* unsafe macro */
switch (ch) {
+ case 0:
+#ifdef HAVE_MBSTOWCS
+ free(cstr);
+#endif
+ return;
case '&': fputs("&", fp); break;
case '<': fputs("<", fp); break;
case '>': fputs(">", fp); break;
case '"': fputs(""", fp); break;
default:
- if (ch >= 127)
- fprintf(fp, "&#%d;", ch);
+ if (ch == 32) {
+#ifdef HAVE_MBSTOWCS
+ if (p <= cstr + 1 || !*p || *p == 32)
+ fputs(" ", fp); /* non-breaking space in unicode */
+ else
+#endif
+ fputc(32, fp);
+ } else if (ch < 32 || ch >= 127)
+ fprintf(fp, "&#%d;", (int)ch);
else
- putc(ch, fp);
+ putc((char)ch, fp);
}
}
}
" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
"<!--\n"
" SVG file created by\n"
-" RRDtool 1.2.6 Tobias Oetiker, http://tobi.oetiker.ch\n"
+" RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch\n"
"\n"
" The width/height attributes in the outhermost svg node\n"
" are just default sizes for the browser which is used\n"
"-->\n", fp);
svg_start_tag(fp, "svg");
fputs(" width=\"", fp);
- svg_write_number(fp, width * canvas->zoom);
+ svg_write_number(fp, width * canvas->zoom);
fputs("\" height=\"", fp);
- svg_write_number(fp, height * canvas->zoom);
+ svg_write_number(fp, height * canvas->zoom);
fputs("\" x=\"0\" y=\"0\" viewBox=\"", fp);
svg_write_number(fp, -LINEOFFSET);
fputs(" ", fp);
fputs(" ", fp);
svg_write_number(fp, height - LINEOFFSET);
fputs("\" preserveAspectRatio=\"xMidYMid\"", fp);
- fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
- fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
+ fprintf(fp, " font-family=\"%s\"", svg_default_font); /* default font */
+ fputs(" stroke-linecap=\"round\" stroke-linejoin=\"round\"", fp);
+ fputs(" xmlns=\"http://www.w3.org/2000/svg\"", fp);
+ fputs(" xmlns:xlink=\"http://www.w3.org/1999/xlink\"", fp);
svg_close_tag(fp);
svg_start_tag(fp, "rect");
fprintf(fp, " x=\"0\" y=\"0\" width=\"%d\" height=\"%d\"", width, height);
gfx_node_t *node;
fputs(
"%!PS-Adobe-3.0 EPSF-3.0\n"
- "%%Creator: RRDtool 1.2.6 Tobias Oetiker, http://tobi.oetiker.ch\n"
+ "%%Creator: RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch\n"
/* can't like weird chars here */
"%%Title: (RRDtool output)\n"
"%%DocumentData: Clean7Bit\n"
static void eps_write_text(eps_state *state, gfx_node_t *node)
{
FILE *fp = state->fp;
- const unsigned char *p;
const char *ps_font = afm_get_font_postscript_name(node->filename);
int lineLen = 0;
pdf_coords g;
+#ifdef HAVE_MBSTOWCS
+ size_t clen;
+ wchar_t *p, *cstr, ch;
+ int text_count;
+ if (!node->text)
+ return;
+ clen = strlen(node->text) + 1;
+ cstr = malloc(sizeof(wchar_t) * clen);
+ text_count = mbstowcs(cstr, node->text, clen);
+ if (text_count == -1)
+ text_count = mbstowcs(cstr, "Enc-Err", 6);
+ p = cstr;
+#else
+ const unsigned char *p = node->text;
+ unsigned char ch;
+ if (!p)
+ return;
+#endif
pdf_calc(state->page_height, node, &g);
eps_set_color(state, node->color);
if (strcmp(ps_font, state->font) || node->size != state->font_size) {
fputs("T1 ", fp);
fputs("(", fp);
lineLen = 20;
- for (p = (const unsigned char*)node->text; *p; p++) {
- if (lineLen > 70) {
+ while (1) {
+ ch = *p;
+ if (!ch)
+ break;
+ ch = afm_fix_osx_charset(ch); /* unsafe macro */
+ if (++lineLen > 70) {
fputs("\\\n", fp); /* backslash and \n */
lineLen = 0;
}
- switch (*p) {
+ switch (ch) {
+ case '%':
case '(':
case ')':
case '\\':
+ fputc('\\', fp);
+ fputc(ch, fp);
+ break;
case '\n':
+ fputs("\\n", fp);
+ break;
case '\r':
+ fputs("\\r", fp);
+ break;
case '\t':
- fputc('\\', fp);
- lineLen++;
- /* fall-through */
+ fputs("\\t", fp);
+ break;
default:
- if (*p >= 126)
- fprintf(fp, "\\%03o", *p);
- else
- fputc(*p, fp);
- lineLen++;
- }
+ if (ch > 255) {
+ fputc('?', fp);
+ } else if (ch >= 126 || ch < 32) {
+ fprintf(fp, "\\%03o", (unsigned int)ch);
+ lineLen += 3;
+ } else {
+ fputc(ch, fp);
+ }
+ }
+ p++;
}
+#ifdef HAVE_MBSTOWCS
+ free(cstr);
+#endif
if (node->angle) {
/* can't use svg_write_number as 2 decimals is far from enough to avoid
skewed text */
state.linecap = -1;
state.linejoin = -1;
state.has_dash = 0;
+ state.line_width = 1;
if (eps_prologue(&state) == -1)
return -1;
eps_set_color(&state, background);
buf->current_size += len;
}
+static void pdf_put_char(pdf_buffer *buf, char c)
+{
+ if (buf->alloc_size >= buf->current_size + 1) {
+ buf->data[buf->current_size++] = c;
+ } else {
+ char tmp[1];
+ tmp[0] = (char)c;
+ pdf_put(buf, tmp, 1);
+ }
+}
+
static void pdf_puts(pdf_buffer *buf, const char *text)
{
pdf_put(buf, text, strlen(text));
pdf_puts(buf, tmp);
}
-static void pdf_put_string_contents(pdf_buffer *buf, const char *text)
+static void pdf_put_string_contents_wide(pdf_buffer *buf, const afm_char *text)
{
- const char *p = text;
+ const afm_char *p = text;
while (1) {
- char ch = *p;
+ afm_char ch = *p;
+ ch = afm_fix_osx_charset(ch); /* unsafe macro */
switch (ch) {
- case 0: return;
+ case 0:
+ return;
case '(':
+ pdf_puts(buf, "\\(");
+ break;
case ')':
+ pdf_puts(buf, "\\)");
+ break;
case '\\':
- pdf_puts(buf, "\\");
- pdf_put(buf, p, 1);
+ pdf_puts(buf, "\\\\");
break;
case '\n':
pdf_puts(buf, "\\n");
pdf_puts(buf, "\\t");
break;
default:
- if (ch >= 126 || ch < 32) {
+ if (ch > 255) {
+ pdf_put_char(buf, '?');
+ } else if (ch > 125 || ch < 32) {
+ pdf_put_char(buf, ch);
+ } else {
char tmp[10];
- snprintf(tmp, sizeof(tmp), "\\%03o", ch);
+ snprintf(tmp, sizeof(tmp), "\\%03o", (int)ch);
pdf_puts(buf, tmp);
- } else {
- pdf_put(buf, p, 1);
}
}
p++;
}
}
+static void pdf_put_string_contents(pdf_buffer *buf, const char *text)
+{
+#ifdef HAVE_MBSTOWCS
+ size_t clen = strlen(text) + 1;
+ wchar_t *cstr = malloc(sizeof(wchar_t) * clen);
+ int text_count = mbstowcs(cstr, text, clen);
+ if (text_count == -1)
+ text_count = mbstowcs(cstr, "Enc-Err", 6);
+ pdf_put_string_contents_wide(buf, cstr);
+#if 0
+ if (*text == 'W') {
+ fprintf(stderr, "Decoding utf8 for '%s'\n", text);
+ wchar_t *p = cstr;
+ char *pp = text;
+ fprintf(stderr, "sz wc = %d\n", sizeof(wchar_t));
+ while (*p) {
+ fprintf(stderr, " %d = %c versus %d = %c\n", *p, (char)*p, 255 & (int)*pp, *pp);
+ p++;
+ pp++;
+ }
+ }
+#endif
+ free(cstr);
+#else
+ pdf_put_string_contents_wide(buf, text);
+#endif
+}
+
static void pdf_init_object(pdf_state *state, pdf_buffer *buf)
{
pdf_init_buffer(state, buf);
static void pdf_setup_document(pdf_state *state)
{
- const char *creator = "RRDtool 1.2.6 Tobias Oetiker, http://tobi.oetiker.ch";
+ const char *creator = "RRDtool " PACKAGE_VERSION " Tobias Oetiker, http://tobi.oetiker.ch";
/* all objects created by now, so init code can reference them */
/* HEADER */
pdf_puts(&state->pdf_header, "%PDF-1.3\n");