summaryrefslogtreecommitdiff
path: root/src/drv
diff options
context:
space:
mode:
authorscuri <scuri>2008-10-17 06:10:33 +0000
committerscuri <scuri>2008-10-17 06:10:33 +0000
commit7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch)
treed0857278bde2eff784227c57dcaf930346ceb7ac /src/drv
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/drv')
-rw-r--r--src/drv/cd0emf.c17
-rw-r--r--src/drv/cd0prn.c17
-rw-r--r--src/drv/cd0wmf.c16
-rw-r--r--src/drv/cdcgm.c1135
-rw-r--r--src/drv/cddebug.c729
-rw-r--r--src/drv/cddgn.c1696
-rw-r--r--src/drv/cddxf.c1184
-rw-r--r--src/drv/cdirgb.c2135
-rw-r--r--src/drv/cdmf.c1188
-rw-r--r--src/drv/cdpdf.c1491
-rw-r--r--src/drv/cdpicture.c1133
-rw-r--r--src/drv/cdps.c1836
-rw-r--r--src/drv/cgm.c2281
-rw-r--r--src/drv/cgm.h156
14 files changed, 15014 insertions, 0 deletions
diff --git a/src/drv/cd0emf.c b/src/drv/cd0emf.c
new file mode 100644
index 0000000..13beb4c
--- /dev/null
+++ b/src/drv/cd0emf.c
@@ -0,0 +1,17 @@
+/** \file
+ * \brief Dummy EMF
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include "cd.h"
+#include "cdemf.h"
+
+
+cdContext* cdContextEMF(void)
+{
+ return NULL;
+}
+
+
diff --git a/src/drv/cd0prn.c b/src/drv/cd0prn.c
new file mode 100644
index 0000000..429a392
--- /dev/null
+++ b/src/drv/cd0prn.c
@@ -0,0 +1,17 @@
+/** \file
+ * \brief Dummy Printer
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include "cd.h"
+#include "cdprint.h"
+
+
+
+cdContext* cdContextPrinter(void)
+{
+ return NULL;
+}
+
diff --git a/src/drv/cd0wmf.c b/src/drv/cd0wmf.c
new file mode 100644
index 0000000..a96761a
--- /dev/null
+++ b/src/drv/cd0wmf.c
@@ -0,0 +1,16 @@
+/** \file
+ * \brief Dummy WMF
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include "cd.h"
+#include "cdwmf.h"
+
+
+cdContext* cdContextWMF(void)
+{
+ return NULL;
+}
+
diff --git a/src/drv/cdcgm.c b/src/drv/cdcgm.c
new file mode 100644
index 0000000..4ba0065
--- /dev/null
+++ b/src/drv/cdcgm.c
@@ -0,0 +1,1135 @@
+/** \file
+ * \brief CGM driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+#include <limits.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cdcgm.h"
+#include "cgm.h"
+
+#define get_red(_) (((double)cdRed(_))/255.)
+#define get_green(_) (((double)cdGreen(_))/255.)
+#define get_blue(_) (((double)cdBlue(_))/255.)
+
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+ CGM *cgm;
+
+ char filename[256]; /* Arquivo CGM */
+
+ int codificacao; /* Codificacao */
+ int vdc_int_prec;
+ int first; /* Primeira primitiva a ser desenhada */
+ long point;
+ int hassize;
+ int patindex;
+
+ struct
+ {
+ cdfRect bbox;
+ int first;
+ } clip;
+
+ cdfRect b_box;
+};
+
+static double cve_black[] = { 0.0, 0.0, 0.0 };
+static double cve_white[] = { 1.0, 1.0, 1.0 };
+
+/* From INTCGM */
+int cdplayCGM(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data);
+int cdRegisterCallbackCGM(int cb, cdCallback func);
+
+
+/*
+%F Atualiza os valores do bounding box
+*/
+static void setbbox (cdCtxCanvas *ctxcanvas, double x, double y )
+{
+ if ( ctxcanvas->first )
+ {
+ ctxcanvas->b_box.xmin = x;
+ ctxcanvas->b_box.xmax = x;
+ ctxcanvas->b_box.ymin = y;
+ ctxcanvas->b_box.ymax = y;
+ ctxcanvas->first = 0;
+ }
+
+ if ( x<ctxcanvas->b_box.xmin ) ctxcanvas->b_box.xmin = x;
+ if ( x>ctxcanvas->b_box.xmax ) ctxcanvas->b_box.xmax = x;
+ if ( y<ctxcanvas->b_box.ymin ) ctxcanvas->b_box.ymin = y;
+ if ( y>ctxcanvas->b_box.ymax ) ctxcanvas->b_box.ymax = y;
+}
+
+
+/*
+%F metafile descriptor elements
+*/
+static void metafile_descriptor (cdCtxCanvas *ctxcanvas)
+{
+ const char *font_list[] = { "SYSTEM", "COURIER", "TIMES_ROMAN", "HELVETICA",
+ "SYSTEM_BOLD", "COURIER_BOLD", "TIMES_ROMAN_BOLD", "HELVETICA_BOLD",
+ "SYSTEM_ITALIC", "COURIER_ITALIC", "TIMES_ROMAN_ITALIC",
+ "HELVETICA_ITALIC", "SYSTEM_BOLDITALIC", "COURIER_BOLDITALIC",
+ "TIMES_ROMAN_BOLDITALIC", "HELVETICA_BOLDITALIC", NULL };
+
+ cgm_metafile_version ( ctxcanvas->cgm, 1);
+ cgm_metafile_description ( ctxcanvas->cgm, "CD generated" );
+ cgm_vdc_type ( ctxcanvas->cgm, 0 /* integer */ );
+ cgm_integer_precision ( ctxcanvas->cgm, 16 );
+ cgm_real_precision ( ctxcanvas->cgm, 3 /* fixed 32 */ );
+ cgm_index_precision ( ctxcanvas->cgm, 16 );
+ cgm_colour_precision ( ctxcanvas->cgm, 8 );
+ cgm_colour_index_precision ( ctxcanvas->cgm, 8 );
+ cgm_maximum_colour_index ( ctxcanvas->cgm, 255ul );
+ cgm_colour_value_extent ( ctxcanvas->cgm, cve_black, cve_white );
+
+ {
+ static int classes[] = { -1 /* drawing set */ };
+ static int ids [] = { 1 /* plus control set */ };
+ cgm_metafile_element_list ( ctxcanvas->cgm, 1, classes, ids );
+ }
+
+ cgm_begin_metafile_defaults ( ctxcanvas->cgm );
+
+ cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec );
+ cgm_interior_style ( ctxcanvas->cgm, 1 ); /* SOLID */
+ cgm_edge_visibility ( ctxcanvas->cgm, 0 ); /* OFF */
+
+ cgm_end_metafile_defaults ( ctxcanvas->cgm );
+
+ cgm_font_list ( ctxcanvas->cgm, font_list );
+}
+
+/*
+%F Pictire descriptor elements
+*/
+static void picture_descriptor (cdCtxCanvas *ctxcanvas)
+{
+ cgm_scaling_mode ( ctxcanvas->cgm, 1 /* metric */, 1.0f );
+ cgm_colour_selection_mode ( ctxcanvas->cgm, 1 /* direct */ );
+ cgm_line_width_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ );
+ cgm_marker_size_specify_mode ( ctxcanvas->cgm, 0 /* absolute=0, scaled=1 */ );
+
+ ctxcanvas->point = ftell ( ctxcanvas->cgm->file );
+ if ( ctxcanvas->codificacao == CD_CLEAR_TEXT )
+ {
+ fprintf ( ctxcanvas->cgm->file, "%80s\n", "" );
+ fprintf ( ctxcanvas->cgm->file, "%80s\n", "" );
+ }
+ else
+ {
+ cgm_vdc_extent( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h);
+ }
+}
+
+/*
+%F Control descriptor elements
+*/
+static void control_elements (cdCtxCanvas *ctxcanvas)
+{
+ double c[3] = {1.0,1.0,1.0};
+
+ cgm_vdc_integer_precision ( ctxcanvas->cgm, ctxcanvas->vdc_int_prec );
+ cgm_vdc_real_precision ( ctxcanvas->cgm, 2 /* fixed 32 */ );
+ cgm_auxiliary_colour ( ctxcanvas->cgm, c );
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ long pt;
+
+ pt = ftell ( ctxcanvas->cgm->file );
+ fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET );
+
+ if (ctxcanvas->hassize)
+ cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h);
+ else
+ {
+ if ( ctxcanvas->clip.first )
+ cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin, ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax );
+ else
+ cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin, ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax );
+ }
+
+ fseek ( ctxcanvas->cgm->file, pt, SEEK_SET );
+
+ cgm_end_picture ( ctxcanvas->cgm );
+ cgm_end_metafile ( ctxcanvas->cgm );
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cddeactivate(cdCtxCanvas *ctxcanvas)
+{
+ fflush(ctxcanvas->cgm->file);
+}
+
+/*
+%F Comeca uma nova pagina.
+*/
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ long pt;
+
+ pt = ftell ( ctxcanvas->cgm->file );
+ fseek ( ctxcanvas->cgm->file, ctxcanvas->point, SEEK_SET );
+
+ if (ctxcanvas->hassize)
+ cgm_vdc_extent ( ctxcanvas->cgm, 0, 0, (double)ctxcanvas->canvas->w, (double)ctxcanvas->canvas->h);
+ else
+ {
+ if ( ctxcanvas->clip.first )
+ cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->b_box.xmin, ctxcanvas->b_box.ymin,
+ ctxcanvas->b_box.xmax, ctxcanvas->b_box.ymax );
+ else
+ cgm_vdc_extent ( ctxcanvas->cgm, ctxcanvas->clip.bbox.xmin, ctxcanvas->clip.bbox.ymin,
+ ctxcanvas->clip.bbox.xmax, ctxcanvas->clip.bbox.ymax );
+ }
+
+ fseek ( ctxcanvas->cgm->file, pt, SEEK_SET );
+
+ cgm_end_picture ( ctxcanvas->cgm );
+
+ cgm_begin_picture ( ctxcanvas->cgm, "Picture x" );
+ picture_descriptor ( ctxcanvas);
+ cgm_begin_picture_body ( ctxcanvas->cgm );
+}
+
+
+/******************************************************/
+/* coordinate transformation */
+/******************************************************/
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ if (mode == CD_CLIPPOLYGON)
+ return ctxcanvas->canvas->clip_mode;
+
+ cgm_clip_indicator ( ctxcanvas->cgm, mode );
+
+ if (mode == CD_CLIPAREA)
+ cgm_clip_rectangle ( ctxcanvas->cgm, (double) ctxcanvas->canvas->clip_rect.xmin, (double) ctxcanvas->canvas->clip_rect.ymin,
+ (double) ctxcanvas->canvas->clip_rect.xmax, (double) ctxcanvas->canvas->clip_rect.ymax );
+
+ return mode;
+}
+
+static void clip_bbox (cdCtxCanvas *ctxcanvas, double xmin, double ymin, double xmax, double ymax)
+{
+ if ( ctxcanvas->clip.first )
+ {
+ ctxcanvas->clip.bbox.xmin = xmin;
+ ctxcanvas->clip.bbox.xmax = xmax;
+ ctxcanvas->clip.bbox.ymin = ymin;
+ ctxcanvas->clip.bbox.ymax = ymax;
+ ctxcanvas->clip.first = 0;
+ }
+
+ if ( xmin < ctxcanvas->clip.bbox.xmin ) ctxcanvas->clip.bbox.xmin = xmin;
+ if ( ymin < ctxcanvas->clip.bbox.ymin ) ctxcanvas->clip.bbox.ymin = ymin;
+ if ( xmax > ctxcanvas->clip.bbox.xmax ) ctxcanvas->clip.bbox.xmax = xmax;
+ if ( ymax > ctxcanvas->clip.bbox.ymax ) ctxcanvas->clip.bbox.ymax = ymax;
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ cgm_clip_rectangle ( ctxcanvas->cgm, (double) xmin, (double) ymin,
+ (double) xmax, (double) ymax );
+
+ clip_bbox (ctxcanvas, (double)xmin, (double)ymin, (double)xmax, (double)ymax );
+}
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ cgm_clip_rectangle ( ctxcanvas->cgm, xmin, ymin, xmax, ymax );
+
+ clip_bbox (ctxcanvas, xmin, ymin, xmax, ymax );
+}
+
+/******************************************************/
+/* primitives */
+/******************************************************/
+
+static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style);
+
+static void cdline(cdCtxCanvas *ctxcanvas, int px1, int py1, int px2, int py2)
+{
+ double points[4];
+
+ points[0] = (double)px1;
+ points[1] = (double)py1;
+ points[2] = (double)px2;
+ points[3] = (double)py2;
+
+ cgm_polyline( ctxcanvas->cgm, 2, points);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double px1, double py1, double px2, double py2)
+{
+ double points[4];
+
+ points[0] = px1;
+ points[1] = py1;
+ points[2] = px2;
+ points[3] = py2;
+
+ cgm_polyline( ctxcanvas->cgm, 2, points);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ double points[4];
+
+ points[0] = (double)xmin;
+ points[1] = (double)ymin;
+ points[2] = (double)xmax;
+ points[3] = (double)ymax;
+
+ cgm_interior_style ( ctxcanvas->cgm, HOLLOW);
+ cgm_rectangle( ctxcanvas->cgm, points);
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+ setbbox (ctxcanvas, points[0], points[3] );
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ double points[4];
+
+ points[0] = xmin;
+ points[1] = ymin;
+ points[2] = xmax;
+ points[3] = ymax;
+
+ cgm_interior_style ( ctxcanvas->cgm, HOLLOW);
+ cgm_rectangle( ctxcanvas->cgm, points);
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+ setbbox (ctxcanvas, points[0], points[3] );
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ double points[4];
+
+ points[0] = (double)xmin;
+ points[1] = (double)ymin;
+ points[2] = (double)xmax;
+ points[3] = (double)ymax;
+
+ cgm_rectangle( ctxcanvas->cgm, points);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+ setbbox (ctxcanvas, points[0], points[3] );
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ double points[4];
+
+ points[0] = xmin;
+ points[1] = ymin;
+ points[2] = xmax;
+ points[3] = ymax;
+
+ cgm_rectangle( ctxcanvas->cgm, points);
+
+ setbbox (ctxcanvas, points[0], points[1] );
+ setbbox (ctxcanvas, points[2], points[1] );
+ setbbox (ctxcanvas, points[2], points[3] );
+ setbbox (ctxcanvas, points[0], points[3] );
+}
+
+static void arc (cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2,
+ double *center, double *first_end_point,
+ double *second_end_point, double *dx_start, double *dy_start,
+ double *dx_end, double *dy_end )
+{
+ double width, height;
+
+ center[0] = xc;
+ center[1] = yc;
+
+ width = w/2;
+ height = h/2;
+
+ first_end_point[0] = center[0] + width;
+ first_end_point[1] = center[1];
+
+ second_end_point[0] = center[0];
+ second_end_point[1] = center[1] + height;
+
+ *dx_start = width*cos(a1*CD_DEG2RAD);
+ *dy_start = height*sin(a1*CD_DEG2RAD);
+
+ *dx_end = width*cos(a2*CD_DEG2RAD);
+ *dy_end = height*sin(a2*CD_DEG2RAD);
+
+ setbbox (ctxcanvas, center[0]-width, center[1]-height );
+ setbbox (ctxcanvas, center[0]+width, center[1]-height );
+ setbbox (ctxcanvas, center[0]+width, center[1]+height );
+ setbbox (ctxcanvas, center[0]-width, center[1]+height );
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ double center[2], first_end_point[2], second_end_point[2];
+ double dx_start, dy_start, dx_end, dy_end;
+
+ arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point,
+ &dx_start, &dy_start, &dx_end, &dy_end );
+
+ cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end );
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ double center[2], first_end_point[2], second_end_point[2];
+ double dx_start, dy_start, dx_end, dy_end;
+
+ arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point,
+ &dx_start, &dy_start, &dx_end, &dy_end );
+
+ cgm_elliptical_arc ( ctxcanvas->cgm, center, first_end_point, second_end_point, dx_start, dy_start, dx_end, dy_end );
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ double center[2], first_end_point[2], second_end_point[2];
+ double dx_start, dy_start, dx_end, dy_end;
+
+ arc (ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2, center, first_end_point, second_end_point,
+ &dx_start, &dy_start, &dx_end, &dy_end );
+
+
+ cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point,
+ dx_start, dy_start, dx_end, dy_end, 0 );
+
+ setbbox (ctxcanvas, (double)xc-w/2., (double)yc-h/2. );
+ setbbox (ctxcanvas, (double)xc+w/2., (double)yc-h/2. );
+ setbbox (ctxcanvas, (double)xc+w/2., (double)yc+h/2. );
+ setbbox (ctxcanvas, (double)xc-w/2., (double)yc+h/2. );
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ double center[2], first_end_point[2], second_end_point[2];
+ double dx_start, dy_start, dx_end, dy_end;
+
+ arc (ctxcanvas, xc, yc, w, h, a1, a2, center, first_end_point, second_end_point,
+ &dx_start, &dy_start, &dx_end, &dy_end );
+
+
+ cgm_elliptical_arc_close ( ctxcanvas->cgm, center, first_end_point, second_end_point,
+ dx_start, dy_start, dx_end, dy_end, 0 );
+
+ setbbox (ctxcanvas, xc-w/2., yc-h/2. );
+ setbbox (ctxcanvas, xc+w/2., yc-h/2. );
+ setbbox (ctxcanvas, xc+w/2., yc+h/2. );
+ setbbox (ctxcanvas, xc-w/2., yc+h/2. );
+}
+
+static void settextbbox (cdCtxCanvas *ctxcanvas, double x, double y, int width, int height )
+{
+ switch ( ctxcanvas->canvas->text_alignment )
+ {
+ case CD_NORTH:
+ setbbox (ctxcanvas, x-(width/2.), y-height );
+ setbbox (ctxcanvas, x+(width/2.), y );
+ break;
+ case CD_SOUTH:
+ setbbox (ctxcanvas, x-(width/2.), y+height );
+ setbbox (ctxcanvas, x+(width/2.), y );
+ break;
+ case CD_EAST:
+ setbbox (ctxcanvas, x-width, y-(height/2.) );
+ setbbox (ctxcanvas, x, y+(height/2.) );
+ break;
+ case CD_WEST:
+ setbbox (ctxcanvas, x, y-(height/2.) );
+ setbbox (ctxcanvas, x+width, y+(height/2.) );
+ break;
+ case CD_NORTH_EAST:
+ setbbox (ctxcanvas, x-width, y-height );
+ setbbox (ctxcanvas, x, y );
+ break;
+ case CD_NORTH_WEST:
+ setbbox (ctxcanvas, x, y-height );
+ setbbox (ctxcanvas, x+width, y );
+ break;
+ case CD_SOUTH_EAST:
+ setbbox (ctxcanvas, x-width, y );
+ setbbox (ctxcanvas, x, y+height );
+ break;
+ case CD_SOUTH_WEST:
+ setbbox (ctxcanvas, x, y );
+ setbbox (ctxcanvas, x+width, y+height );
+ break;
+ case CD_CENTER:
+ setbbox (ctxcanvas, x-(width/2.), y-(height/2.) );
+ setbbox (ctxcanvas, x+(width/2.), y+(height/2.) );
+ break;
+ case CD_BASE_LEFT:
+ setbbox (ctxcanvas, x, y );
+ setbbox (ctxcanvas, x+width, y+height );
+ break;
+ case CD_BASE_CENTER:
+ setbbox (ctxcanvas, x-(width/2.), y );
+ setbbox (ctxcanvas, x+(width/2.), y+height );
+ break;
+ case CD_BASE_RIGHT:
+ setbbox (ctxcanvas, x-width, y );
+ setbbox (ctxcanvas, x, y+height );
+ break;
+ }
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ int width, height;
+
+ cgm_text( ctxcanvas->cgm, 1 /* final */ , (double)x, (double)y, s );
+
+ cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height);
+
+ settextbbox (ctxcanvas, (double) x, (double) y, width, height );
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s)
+{
+ int width, height;
+
+ cgm_text( ctxcanvas->cgm, 1 /* final */ , x, y, s );
+
+ cdCanvasGetTextSize(ctxcanvas->canvas, s, &width, &height);
+
+ settextbbox (ctxcanvas, x, y, width, height );
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+ double *fpoly;
+
+ fpoly = (double *)malloc(2 * (n+1) * sizeof(double));
+
+ for (i = 0; i < n; i++)
+ {
+ fpoly[2*i] = (double) poly[i].x;
+ fpoly[2*i+1] = (double) poly[i].y;
+
+ setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] );
+ }
+
+ switch ( mode )
+ {
+ case CD_OPEN_LINES:
+ cgm_polyline( ctxcanvas->cgm, n, fpoly );
+ break;
+ case CD_CLOSED_LINES:
+ fpoly[2*n] = fpoly[0];
+ fpoly[2*n+1] = fpoly[1];
+ n++;
+ cgm_polyline( ctxcanvas->cgm, n, fpoly );
+ break;
+ case CD_FILL:
+ cgm_polygon( ctxcanvas->cgm, n, fpoly);
+ break;
+ }
+
+ free(fpoly);
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+ double *fpoly = (double*)poly;
+
+ for (i = 0; i < n; i++)
+ {
+ setbbox (ctxcanvas, fpoly[2*i] , fpoly[2*i+1] );
+ }
+
+ switch ( mode )
+ {
+ case CD_OPEN_LINES:
+ cgm_polyline( ctxcanvas->cgm, n, fpoly );
+ break;
+ case CD_CLOSED_LINES:
+ fpoly[2*n] = fpoly[0];
+ fpoly[2*n+1] = fpoly[1];
+ n++;
+ cgm_polyline( ctxcanvas->cgm, n, fpoly );
+ break;
+ case CD_FILL:
+ cgm_polygon( ctxcanvas->cgm, n, fpoly);
+ break;
+ }
+}
+
+
+/******************************************************/
+/* attributes */
+/******************************************************/
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ cgm_line_type( ctxcanvas->cgm, (long)(style + 1));
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ cgm_line_width( ctxcanvas->cgm, (double)width );
+ return width;
+}
+
+static int cdinteriorstyle (cdCtxCanvas *ctxcanvas, int style )
+{
+ switch ( style )
+ {
+ case CD_SOLID:
+ style = 1;
+ break;
+ case CD_STIPPLE:
+ case CD_PATTERN:
+ style = 2;
+ break;
+ case CD_HATCH:
+ style = 3;
+ break;
+ }
+
+ cgm_interior_style ( ctxcanvas->cgm, style );
+
+ return style;
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ int cgm_style = style;
+
+ if ( cgm_style==2 )
+ cgm_style = 3;
+ else if ( cgm_style==3 )
+ cgm_style = 2;
+
+ cgm_hatch_index ( ctxcanvas->cgm, (long)cgm_style+1 );
+
+ cgm_interior_style ( ctxcanvas->cgm, 3 );
+
+ return style;
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple)
+{
+ double *pattab;
+ int i, j=0;
+
+ pattab = (double *) malloc ( n*m*3*sizeof(double));
+
+ for ( i=0; i<n*m; i++ )
+ {
+ pattab[j+0] = ( stipple[i] ) ? get_red(ctxcanvas->canvas->foreground) : get_red(ctxcanvas->canvas->background);
+ pattab[j+1] = ( stipple[i] ) ? get_green(ctxcanvas->canvas->foreground) : get_green(ctxcanvas->canvas->background);
+ pattab[j+2] = ( stipple[i] ) ? get_blue(ctxcanvas->canvas->foreground) : get_blue(ctxcanvas->canvas->background);
+ j+=3;
+ }
+
+ cgm_pattern_table ( ctxcanvas->cgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab );
+ cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ );
+ free(pattab);
+
+ cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern)
+{
+ double *pattab;
+ int i, j=0;
+
+ pattab = (double *) malloc ( n*m*3*sizeof(double) );
+
+ for ( i=0; i<n*m; i++ )
+ {
+ pattab[j+0] = get_red(pattern[i]);
+ pattab[j+1] = get_green(pattern[i]);
+ pattab[j+2] = get_blue(pattern[i]);
+ j+=3;
+ }
+
+ cgm_pattern_table ( ctxcanvas->cgm, (long) ctxcanvas->patindex, (long) n, (long) m, (int) 8, pattab );
+ cgm_pattern_index ( ctxcanvas->cgm, (long) ctxcanvas->patindex++ );
+ free(pattab);
+
+ cgm_interior_style ( ctxcanvas->cgm, 2 ); /* PATTERN */
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ long index = 0;
+
+ if (cdStrEqualNoCase(type_face, "System"))
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ index = 1;
+ break;
+ case CD_BOLD:
+ index = 5;
+ break;
+ case CD_ITALIC:
+ index = 9;
+ break;
+ case CD_BOLD_ITALIC:
+ index = 13;
+ break;
+ }
+ else if (cdStrEqualNoCase(type_face, "Courier"))
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ index = 2;
+ break;
+ case CD_BOLD:
+ index = 6;
+ break;
+ case CD_ITALIC:
+ index = 10;
+ break;
+ case CD_BOLD_ITALIC:
+ index = 14;
+ break;
+ }
+ else if (cdStrEqualNoCase(type_face, "Times"))
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ index = 3;
+ break;
+ case CD_BOLD:
+ index = 7;
+ break;
+ case CD_ITALIC:
+ index = 11;
+ break;
+ case CD_BOLD_ITALIC:
+ index = 15;
+ break;
+ }
+ else if (cdStrEqualNoCase(type_face, "Helvetica"))
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ index = 4;
+ break;
+ case CD_BOLD:
+ index = 8;
+ break;
+ case CD_ITALIC:
+ index = 12;
+ break;
+ case CD_BOLD_ITALIC:
+ index = 16;
+ break;
+ }
+
+ if (index == 0) return 0;
+
+ cgm_char_height ( ctxcanvas->cgm, cdGetFontSizePixels(ctxcanvas->canvas, size));
+ cgm_text_font_index( ctxcanvas->cgm, index );
+
+ return 1;
+}
+
+static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment)
+{
+ int hor = 0, ver = 0;
+ enum { NORMHORIZ, LEFT, CTR, RIGHT };
+ enum { NORMVERT, TOP, CAP, HALF, BASE, BOTTOM };
+
+ switch ( alignment )
+ {
+ case CD_NORTH:
+ hor = CTR;
+ ver = TOP;
+ break;
+ case CD_SOUTH:
+ hor = CTR;
+ ver = BOTTOM;
+ break;
+ case CD_EAST:
+ hor = RIGHT;
+ ver = HALF;
+ break;
+ case CD_WEST:
+ hor = LEFT;
+ ver = HALF;
+ break;
+ case CD_NORTH_EAST:
+ hor = RIGHT;
+ ver = TOP;
+ break;
+ case CD_NORTH_WEST:
+ hor = LEFT;
+ ver = TOP;
+ break;
+ case CD_SOUTH_EAST:
+ hor = RIGHT;
+ ver = BOTTOM;
+ break;
+ case CD_SOUTH_WEST:
+ hor = LEFT;
+ ver = BOTTOM;
+ break;
+ case CD_CENTER:
+ hor = CTR;
+ ver = HALF;
+ break;
+ case CD_BASE_LEFT:
+ hor = LEFT;
+ ver = BASE;
+ break;
+ case CD_BASE_CENTER:
+ hor = CTR;
+ ver = BASE;
+ break;
+ case CD_BASE_RIGHT:
+ hor = RIGHT;
+ ver = BASE;
+ break;
+ }
+
+ cgm_text_alignment ( ctxcanvas->cgm, hor, ver , (double)0.0, (double)0.0 );
+
+ return alignment;
+}
+
+/******************************************************/
+/* color */
+/******************************************************/
+
+static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ double cor[3];
+
+ cor[0] = get_red(color);
+ cor[1] = get_green(color);
+ cor[2] = get_blue(color);
+
+ cgm_text_colour( ctxcanvas->cgm, cor );
+ cgm_fill_colour( ctxcanvas->cgm, cor );
+ cgm_line_colour( ctxcanvas->cgm, cor );
+
+ return color;
+}
+
+static long int cdbackground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ double bc[3];
+
+ bc[0] = get_red(color);
+ bc[1] = get_green(color);
+ bc[2] = get_blue(color);
+
+ ctxcanvas->canvas->background = color;
+ cgm_backgound_colour ( ctxcanvas->cgm, bc );
+
+ return color;
+}
+
+static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opaque)
+{
+ if (opaque == CD_TRANSPARENT)
+ cgm_transparency(ctxcanvas->cgm, 1);
+ else
+ cgm_transparency(ctxcanvas->cgm, 0);
+ return opaque;
+}
+
+/******************************************************/
+/* client images */
+/******************************************************/
+
+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)
+{
+ double p[6];
+ double *color_array;
+ int i,j,index,c;
+ int rw, rh;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ color_array = (double *) malloc ( rw*rh*3*sizeof(double) );
+ if (!color_array)
+ return;
+
+ p[0] = (double) x; p[1] = (double) (y+h);
+ p[2] = (double) (x+w); p[3] = (double) y;
+ p[4] = (double) (x+w); p[5] = (double) (y+h);
+
+ for ( i=0; i<rh; i++ )
+ {
+ for ( j=0; j<rw; j++ )
+ {
+ index = (ih-i-1-ymin)*iw+j+xmin;
+ c = i*rw*3+j*3;
+ color_array[c] = (double) r[index]/255.;
+ color_array[c+1] = (double) g[index]/255.;
+ color_array[c+2] = (double) b[index]/255.;
+ }
+ }
+
+ cgm_cell_array ( ctxcanvas->cgm, p, (long)rw, (long)rh, 8, color_array );
+
+ free(color_array);
+
+ setbbox (ctxcanvas, p[0], p[1] );
+ setbbox (ctxcanvas, p[2], p[3] );
+}
+
+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)
+{
+ double p[6];
+ double *color_array;
+ int i,j,c;
+ unsigned char r, g, b;
+ int rw, rh;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ color_array = (double *) malloc ( rw*rh*3*sizeof(double) );
+ if (!color_array)
+ return;
+
+ p[0] = (double) x; p[1] = (double) y;
+ p[2] = (double) (x+w); p[3] = (double) (y+h);
+ p[4] = (double) (x+w); p[5] = (double) y;
+
+ for ( i=0; i<rh; i++ )
+ {
+ for ( j=0; j<rw; j++ )
+ {
+ c = i*rw*3+j*3;
+ cdDecodeColor(colors[index[(ih-i-1-ymin)*iw+j+xmin]], &r,&b,&g);
+ color_array[c] = ((double)r)/255.;
+ color_array[c+1] = ((double)g)/255.;
+ color_array[c+2] = ((double)b)/255.;
+ }
+ }
+
+ cgm_cell_array ( ctxcanvas->cgm, p, (long)rw, (long)rh, 8, color_array );
+
+ free(color_array);
+
+ setbbox (ctxcanvas, p[0], p[1] );
+ setbbox (ctxcanvas, p[2], p[3] );
+}
+
+/******************************************************/
+/* server images */
+/******************************************************/
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ double cor[3];
+ double pts[2];
+
+ pts[0] = (double) x;
+ pts[1] = (double) y;
+
+ cor[0] = get_red(color);
+ cor[1] = get_green(color);
+ cor[2] = get_blue(color);
+
+ cgm_marker_colour( ctxcanvas->cgm, cor);
+ cgm_polymarker ( ctxcanvas->cgm, 1, pts );
+}
+
+/*
+%F Cria um canvas CGM.
+Parametros passados em data:
+[nome] nome do arquivo de saida <= 255 caracteres
+[size] tamanho do papel
+-t codificacao clear text se nao binaria
+*/
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas *ctxcanvas;
+ char *line = (char *)data;
+ char c;
+ char words[4][256];
+ char filename[10240] = "";
+ double w=0, h=0, r=0;
+ int p=0;
+ int i, n;
+
+ line += cdGetFileName(line, filename);
+ if (filename[0] == 0)
+ return;
+
+ n = sscanf(line, "%s %s %s %s", words[0], words[1], words[2], words[3]);
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+
+ canvas->ctxcanvas = ctxcanvas;
+ ctxcanvas->canvas = canvas;
+
+ strcpy(ctxcanvas->filename, filename);
+
+ canvas->w_mm = (double)INT_MAX*3.78;
+ canvas->h_mm = (double)INT_MAX*3.78;
+ canvas->xres = 3.78;
+ canvas->yres = 3.78;
+ canvas->bpp = 24;
+
+ ctxcanvas->vdc_int_prec = 16;
+ ctxcanvas->codificacao = CD_BIN;
+ ctxcanvas->first = 1;
+ ctxcanvas->clip.first = 1;
+ ctxcanvas->patindex = 1;
+
+ ctxcanvas->hassize = 0; /* Indica se foi passado um tamanho para o canvas */
+
+ for (i = 0; i < n; i++)
+ {
+ if (sscanf ( words[i], "%lgx%lg", &w, &h )== 2)
+ {
+ canvas->w_mm = w;
+ canvas->h_mm = h;
+ ctxcanvas->hassize = 1;
+ }
+ else if (sscanf ( words[i], "%lg", &r ) == 1)
+ canvas->yres = canvas->xres = r;
+ else if (sscanf ( words[i], "-%c%d", &c, &p )>0)
+ {
+ if ( c=='t' )
+ ctxcanvas->codificacao = CD_CLEAR_TEXT;
+ else if ( c=='p' )
+ ctxcanvas->vdc_int_prec = p;
+ }
+ }
+
+ if ( ctxcanvas->vdc_int_prec != 16 && w == 0.0 && h == 0.0 )
+ {
+ canvas->w_mm = (double) (pow(2,p)/2)-1;
+ canvas->h_mm = (double) (pow(2,p)/2)-1;
+ }
+
+ /* update canvas context */
+ canvas->w = (int)(canvas->w_mm * canvas->xres);
+ canvas->h = (int)(canvas->h_mm * canvas->yres);
+
+ ctxcanvas->cgm = cgm_begin_metafile ( ctxcanvas->filename, ctxcanvas->codificacao, "CD - CanvasDraw, Tecgraf/PUC-RIO" );
+
+ metafile_descriptor(ctxcanvas);
+
+ cgm_begin_picture ( ctxcanvas->cgm, "Picture x" );
+
+ picture_descriptor (ctxcanvas);
+
+ cgm_clip_rectangle ( ctxcanvas->cgm, 0, 0, (double)canvas->w, (double)canvas->h);
+ cgm_clip_indicator (ctxcanvas->cgm, 0);
+
+ cgm_begin_picture_body ( ctxcanvas->cgm );
+
+ control_elements (ctxcanvas);
+
+ cgm_marker_type( ctxcanvas->cgm, MARKER_DOT);
+ cgm_marker_size( ctxcanvas->cgm, 1.0);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ /* initialize function table*/
+ canvas->cxFlush = cdflush;
+ canvas->cxPixel = cdpixel;
+ canvas->cxLine = cdline;
+ canvas->cxPoly = cdpoly;
+ canvas->cxRect = cdrect;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarc;
+ canvas->cxSector = cdsector;
+ canvas->cxText = cdtext;
+ canvas->cxFLine = cdfline;
+ canvas->cxFPoly = cdfpoly;
+ canvas->cxFRect = cdfrect;
+ canvas->cxFBox = cdfbox;
+ canvas->cxFArc = cdfarc;
+ canvas->cxFSector = cdfsector;
+ canvas->cxFText = cdftext;
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxInteriorStyle = cdinteriorstyle;
+ canvas->cxHatch = cdhatch;
+ canvas->cxStipple = cdstipple;
+ canvas->cxPattern = cdpattern;
+ canvas->cxFont = cdfont;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxBackground = cdbackground;
+ canvas->cxForeground = cdforeground;
+ canvas->cxBackOpacity = cdbackopacity;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+/******************************************************/
+
+static cdContext cdCGMContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PALETTE |
+ CD_CAP_CLIPPOLY | CD_CAP_WRITEMODE | CD_CAP_IMAGESRV |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD |
+ CD_CAP_FONTDIM | CD_CAP_TEXTSIZE |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB |
+ CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ cdplayCGM,
+ cdRegisterCallbackCGM,
+};
+
+cdContext* cdContextCGM(void)
+{
+ return &cdCGMContext;
+}
+
diff --git a/src/drv/cddebug.c b/src/drv/cddebug.c
new file mode 100644
index 0000000..5532568
--- /dev/null
+++ b/src/drv/cddebug.c
@@ -0,0 +1,729 @@
+/** \file
+ * \brief CD DEBUG driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "cd.h"
+#include "wd.h"
+#include "cd_private.h"
+#include "cddebug.h"
+
+
+#define CDDBG_FLUSH "Flush"
+#define CDDBG_CLEAR "Clear"
+#define CDDBG_CLIP "Clip"
+#define CDDBG_CLIPAREA "Cliparea"
+#define CDDBG_LINE "Line"
+#define CDDBG_BOX "Box"
+#define CDDBG_ARC "Arc"
+#define CDDBG_SECTOR "Sector"
+#define CDDBG_TEXT "Text"
+#define CDDBG_BEGIN "Begin"
+#define CDDBG_VERTEX "Vertex"
+#define CDDBG_END "End"
+#define CDDBG_MARK "Mark"
+#define CDDBG_BACKOPACITY "BackOpacity"
+#define CDDBG_WRITEMODE "WriteMode"
+#define CDDBG_LINESTYLE "LineStyle"
+#define CDDBG_LINEWIDTH "LineWidth"
+#define CDDBG_INTERIORSTYLE "InteriorStyle"
+#define CDDBG_HATCH "Hatch"
+#define CDDBG_STIPPLE "Stipple"
+#define CDDBG_PATTERN "Pattern"
+#define CDDBG_NATIVEFONT "NativeFont"
+#define CDDBG_TEXTALIGNMENT "TextAlignment"
+#define CDDBG_PALETTE "Palette"
+#define CDDBG_BACKGROUND "Background"
+#define CDDBG_FOREGROUND "Foreground"
+#define CDDBG_PIXEL "Pixel"
+#define CDDBG_SCROLLAREA "ScrollArea"
+#define CDDBG_TEXTORIENTATION "TextOrientation"
+#define CDDBG_RECT "Rect"
+#define CDDBG_FILLMODE "FillMode"
+#define CDDBG_LINESTYLEDASHES "LineStyleDashes"
+#define CDDBG_LINECAP "LineCap"
+#define CDDBG_LINEJOIN "LineJoin"
+#define CDDBG_CHORD "Chord"
+#define CDDBG_FLINE "fLine"
+#define CDDBG_FRECT "fRect"
+#define CDDBG_FBOX "fBox"
+#define CDDBG_FARC "fArc"
+#define CDDBG_FSECTOR "fSector"
+#define CDDBG_FTEXT "fText"
+#define CDDBG_FVERTEX "fVertex"
+#define CDDBG_MATRIX "Matrix"
+#define CDDBG_FCHORD "fChord"
+#define CDDBG_FCLIPAREA "fClipArea"
+#define CDDBG_FONT "Font"
+#define CDDBG_PUTIMAGERGB "PutImageRGB"
+#define CDDBG_PUTIMAGERGBA "PutImageRGBA"
+#define CDDBG_PUTIMAGEMAP "PutImageMap"
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+ char* filename;
+ FILE* file;
+ int last_line_style;
+ int last_fill_mode;
+};
+
+struct _cdCtxImage {
+ cdCtxCanvas *ctxcanvas;
+};
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ fflush(ctxcanvas->file);
+ fprintf(ctxcanvas->file, "%s()\n", CDDBG_FLUSH);
+}
+
+static void cdclear(cdCtxCanvas *ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "%s()\n", CDDBG_CLEAR);
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ const char* enum2str[] = {
+ "CD_CLIPOFF",
+ "CD_CLIPAREA",
+ "CD_CLIPPOLYGON",
+ "CD_CLIPREGION"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_CLIP, enum2str[mode]);
+ return mode;
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_CLIPAREA, xmin, xmax, ymin, ymax);
+}
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FCLIPAREA, xmin, xmax, ymin, ymax);
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ if (matrix)
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ else
+ fprintf(ctxcanvas->file, "%s(NULL)\n", CDDBG_MATRIX);
+}
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_LINE, x1, y1, x2, y2);
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FLINE, x1, y1, x2, y2);
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_RECT, xmin, xmax, ymin, ymax);
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FRECT, xmin, xmax, ymin, ymax);
+}
+
+static const char* get_region_mode(int combine_mode)
+{
+ const char* enum2str[] = {
+ "CD_UNION",
+ "CD_INTERSECT",
+ "CD_DIFFERENCE",
+ "CD_NOTINTERSECT"
+ };
+ return enum2str[combine_mode];
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %s)\n", CDDBG_BOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d)\n", CDDBG_BOX, xmin, xmax, ymin, ymax);
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %s)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g)\n", CDDBG_FBOX, xmin, xmax, ymin, ymax);
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_ARC, xc, yc, w, h, a1, a2);
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FARC, xc, yc, w, h, a1, a2);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_SECTOR, xc, yc, w, h, a1, a2);
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FSECTOR, xc, yc, w, h, a1, a2);
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%d, %d, %d, %d, %g, %g, %s)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %g, %g)\n", CDDBG_CHORD, xc, yc, w, h, a1, a2);
+}
+
+static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%g, %g, %g, %g, %g, %g, %s)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%g, %g, %g, %g, %g, %g)\n", CDDBG_FCHORD, xc, yc, w, h, a1, a2);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%d, %d, \"%s\", %s)\n", CDDBG_TEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%d, %d, \"%s\")\n", CDDBG_TEXT, x, y, text);
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text)
+{
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%g, %g, \"%s\", %s)\n", CDDBG_FTEXT, x, y, text, get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%g, %g, \"%s\")\n", CDDBG_FTEXT, x, y, text);
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+ const char* enum2str[] = {
+ "CD_FILL",
+ "CD_OPEN_LINES",
+ "CD_CLOSED_LINES",
+ "CD_CLIP",
+ "CD_BEZIER",
+ "CD_REGION"
+ };
+
+ if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode)
+ {
+ const char* enum2str[] = {
+ "CD_EVENODD",
+ "CD_WINDING"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]);
+ ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode;
+ }
+
+ if (ctxcanvas->canvas->new_region)
+ fprintf(ctxcanvas->file, "%sRegion(%s, %s)\n", CDDBG_BEGIN, enum2str[mode], get_region_mode(ctxcanvas->canvas->combine_mode));
+ else
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]);
+
+ for(i = 0; i<n; i++)
+ fprintf(ctxcanvas->file, "%s(%d, %d)\n", CDDBG_VERTEX, poly[i].x, poly[i].y);
+
+ fprintf(ctxcanvas->file, "%s()\n", CDDBG_END);
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+ const char* enum2str[] = {
+ "CD_FILL",
+ "CD_OPEN_LINES",
+ "CD_CLOSED_LINES",
+ "CD_CLIP",
+ "CD_BEZIER",
+ "CD_REGION"
+ };
+
+ if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode)
+ {
+ const char* enum2str[] = {
+ "CD_EVENODD",
+ "CD_WINDING"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_FILLMODE, enum2str[ctxcanvas->canvas->fill_mode]);
+ ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode;
+ }
+
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BEGIN, enum2str[mode]);
+
+ for(i = 0; i<n; i++)
+ fprintf(ctxcanvas->file, "%s(%g, %g)\n", CDDBG_FVERTEX, poly[i].x, poly[i].y);
+
+ fprintf(ctxcanvas->file, "%s()\n", CDDBG_END);
+}
+
+static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity)
+{
+ const char* enum2str[] = {
+ "CD_OPAQUE",
+ "CD_TRANSPARENT"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_BACKOPACITY, enum2str[opacity]);
+ return opacity;
+}
+
+static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode)
+{
+ const char* enum2str[] = {
+ "CD_REPLACE",
+ "CD_XOR",
+ "CD_NOT_XOR"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_WRITEMODE, enum2str[mode]);
+ return mode;
+}
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ const char* enum2str[] = {
+ "CD_CONTINUOUS",
+ "CD_DASHED",
+ "CD_DOTTED",
+ "CD_DASH_DOT",
+ "CD_DASH_DOT_DOT",
+ "CD_CUSTOM"
+ };
+
+ if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style)
+ {
+ int i;
+
+ fprintf(ctxcanvas->file, "%s(%d", CDDBG_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count);
+ for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++)
+ fprintf(ctxcanvas->file, ", %d", ctxcanvas->canvas->line_dashes[i]);
+ fprintf(ctxcanvas->file, ")\n");
+
+ ctxcanvas->last_line_style = ctxcanvas->canvas->line_style;
+ }
+
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINESTYLE, enum2str[style]);
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ fprintf(ctxcanvas->file, "%s(%d)\n", CDDBG_LINEWIDTH, width);
+ return width;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ const char* enum2str[] = {
+ "CD_CAPFLAT",
+ "CD_CAPSQUARE",
+ "CD_CAPROUND"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINECAP, enum2str[cap]);
+ return cap;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ const char* enum2str[] = {
+ "CD_MITER",
+ "CD_BEVEL",
+ "CD_ROUND"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_LINEJOIN, enum2str[join]);
+ return join;
+}
+
+static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ const char* enum2str[] = {
+ "CD_SOLID",
+ "CD_HATCH",
+ "CD_STIPPLE",
+ "CD_PATTERN",
+ "CD_HOLLOW"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_INTERIORSTYLE, enum2str[style]);
+ return style;
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ const char* enum2str[] = {
+ "CD_HORIZONTAL",
+ "CD_VERTICAL",
+ "CD_FDIAGONAL",
+ "CD_BDIAGONAL",
+ "CD_CROSS",
+ "CD_DIAGCROSS"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_HATCH, enum2str[style]);
+ return style;
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_STIPPLE, w, h, stipple);
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %p)\n", CDDBG_PATTERN, w, h, pattern);
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size)
+{
+ char style_str[50] = "";
+ if (style & CD_BOLD)
+ strcat(style_str, "CD_BOLD");
+ if (style & CD_ITALIC)
+ {
+ if (style_str[0]!=0) strcat(style_str, "|");
+ strcat(style_str, "CD_ITALIC");
+ }
+ if (style & CD_UNDERLINE)
+ {
+ if (style_str[0]!=0) strcat(style_str, "|");
+ strcat(style_str, "CD_UNDERLINE");
+ }
+ if (style & CD_STRIKEOUT)
+ {
+ if (style_str[0]!=0) strcat(style_str, "|");
+ strcat(style_str, "CD_STRIKEOUT");
+ }
+ if (style_str[0]==0) strcat(style_str, "CD_PLAIN");
+ fprintf(ctxcanvas->file, "%s(\"%s\", %s, %d)\n", CDDBG_FONT, type_face, style_str, size);
+ return 1;
+}
+
+static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font)
+{
+ fprintf(ctxcanvas->file, "%s(\"%s\")\n", CDDBG_NATIVEFONT, font);
+ return 1;
+}
+
+static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment)
+{
+ const char* enum2str[] = {
+ "CD_NORTH",
+ "CD_SOUTH",
+ "CD_EAST",
+ "CD_WEST",
+ "CD_NORTH_EAST",
+ "CD_NORTH_WEST",
+ "CD_SOUTH_EAST",
+ "CD_SOUTH_WEST",
+ "CD_CENTER",
+ "CD_BASE_LEFT",
+ "CD_BASE_CENTER",
+ "CD_BASE_RIGHT"
+ };
+ fprintf(ctxcanvas->file, "%s(%s)\n", CDDBG_TEXTALIGNMENT, enum2str[alignment]);
+ return alignment;
+}
+
+static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle)
+{
+ fprintf(ctxcanvas->file, "%s(%g)\n", CDDBG_TEXTORIENTATION, angle);
+ return angle;
+}
+
+static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode)
+{
+ const char* enum2str[] = {
+ "CD_POLITE",
+ "CD_FORCE"
+ };
+ fprintf(ctxcanvas->file, "%s(%d, %p, %s)\n", CDDBG_PALETTE, n, palette, enum2str[mode]);
+}
+
+static long cdbackground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ unsigned char r, g, b;
+ cdDecodeColor(color, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_BACKGROUND, (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);
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d)\n", CDDBG_FOREGROUND, (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)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGB, iw, ih, r, g, b, x, y, w, h, xmin, xmax, ymin, ymax);
+}
+
+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)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGERGBA, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax);
+}
+
+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)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %p, %p, %d, %d, %d, %d, %d, %d, %d, %d)\n", CDDBG_PUTIMAGEMAP, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax);
+}
+
+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, "%s(%d, %d, %d, %d, %d)\n", CDDBG_PIXEL, x, y, (int)r, (int)g, (int)b);
+}
+
+static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy)
+{
+ fprintf(ctxcanvas->file, "%s(%d, %d, %d, %d, %d, %d)\n", CDDBG_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy);
+}
+
+static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h)
+{
+ fprintf(ctxcanvas->file, "%p, %p, %p = GetImageRGB(%d, %d, %d, %d)\n", r, g, b, x, y, w, h);
+}
+
+static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h)
+{
+ cdCtxImage* ctximage = malloc(sizeof(cdCtxImage));
+ ctximage->ctxcanvas = ctxcanvas;
+ fprintf(ctxcanvas->file, "%p = GetImage(%d, %d)\n", ctximage, w, h);
+ return ctximage;
+}
+
+static void cdkillimage(cdCtxImage* ctximage)
+{
+ fprintf(ctximage->ctxcanvas->file, "KillImage(%p)\n", ctximage);
+ free(ctximage);
+}
+
+static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y)
+{
+ fprintf(ctxcanvas->file, "GetImage(%p, %d, %d)\n", ctximage, x, y);
+}
+
+static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "PutImage(%p, %d, %d, %d, %d, %d, %d)\n", ctximage, x, y, xmin, xmax, ymin, ymax);
+}
+
+static void cdnewregion(cdCtxCanvas* ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "NewRegion()\n");
+}
+
+static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ fprintf(ctxcanvas->file, "IsPointInRegion(%d, %d)\n", x, y);
+ return 0;
+}
+
+static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ fprintf(ctxcanvas->file, "OffsetRegion(%d, %d)\n", x, y);
+}
+
+static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ (void)xmin;
+ (void)ymin;
+ (void)xmax;
+ (void)ymax;
+ fprintf(ctxcanvas->file, "GetRegionBox()\n");
+}
+
+static int cdactivate(cdCtxCanvas* ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "Activate()\n");
+ return CD_OK;
+}
+
+static void cddeactivate(cdCtxCanvas* ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "Deactivate()\n");
+}
+
+static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ int tmp_max_width, tmp_height, tmp_ascent, tmp_descent;
+ if (!max_width) max_width = &tmp_max_width;
+ if (!height) height = &tmp_height;
+ if (!ascent) ascent = &tmp_ascent;
+ if (!descent) descent = &tmp_descent;
+ cdgetfontdimEX(ctxcanvas, max_width, height, ascent, descent);
+ fprintf(ctxcanvas->file, "%d, %d, %d, %d = GetFontDim()\n", *max_width, *height, *ascent, *descent);
+}
+
+static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height)
+{
+ int tmp_width, tmp_height;
+ if (!width) width = &tmp_width;
+ if (!height) height = &tmp_height;
+ cdgettextsizeEX(ctxcanvas, s, width, height);
+ fprintf(ctxcanvas->file, "%d, %d = GetTextSize(\"%s\")\n", *width, *height, s);
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "KillCanvas()\n");
+ free(ctxcanvas->filename);
+ fclose(ctxcanvas->file);
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+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);
+
+ 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->ctxcanvas = ctxcanvas;
+
+ ctxcanvas->last_line_style = -1;
+ ctxcanvas->last_fill_mode = -1;
+
+ fprintf(ctxcanvas->file, "CreateCanvas(CD_DEBUG, \"%s\")\n", (char*)data);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxClear = cdclear;
+ 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->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxScrollArea = cdscrollarea;
+ 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->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxBackOpacity = cdbackopacity;
+ canvas->cxWriteMode = cdwritemode;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxLineCap = cdlinecap;
+ canvas->cxLineJoin = cdlinejoin;
+ canvas->cxInteriorStyle = cdinteriorstyle;
+ canvas->cxHatch = cdhatch;
+ canvas->cxStipple = cdstipple;
+ canvas->cxPattern = cdpattern;
+ canvas->cxFont = cdfont;
+ canvas->cxNativeFont = cdnativefont;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxTextOrientation = cdtextorientation;
+ canvas->cxPalette = cdpalette;
+ canvas->cxBackground = cdbackground;
+ canvas->cxForeground = cdforeground;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxTransform = cdtransform;
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxGetImageRGB = cdgetimagergb;
+ canvas->cxScrollArea = cdscrollarea;
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxKillImage = cdkillimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxNewRegion = cdnewregion;
+ canvas->cxIsPointInRegion = cdispointinregion;
+ canvas->cxOffsetRegion = cdoffsetregion;
+ canvas->cxGetRegionBox = cdgetregionbox;
+ canvas->cxActivate = cdactivate;
+ canvas->cxDeactivate = cddeactivate;
+ canvas->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+}
+
+static cdContext cdDebugContext =
+{
+ CD_CAP_ALL,
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextDebug(void)
+{
+ return &cdDebugContext;
+}
+
diff --git a/src/drv/cddgn.c b/src/drv/cddgn.c
new file mode 100644
index 0000000..32435b9
--- /dev/null
+++ b/src/drv/cddgn.c
@@ -0,0 +1,1696 @@
+/** \file
+ * \brief DGN driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cddgn.h"
+
+/* defines */
+
+#define MAX_NUM_VERTEX 101
+#define MAX_NUM_VERTEX_PER_POLYLINE 15000
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+#define END_OF_DGN_FILE 0xffff
+#define DGN_FILE_BLOCK 512
+
+#define NOFILL 0 /* tipos de fill que o driver faz */
+#define CONVEX 1
+#define NORMAL 2
+
+/* macros */
+
+#define SIZE_LINE_STRING(x) (19+4*(x))
+#define SIZE_FILLED_SHAPE(x) (27+4*(x))
+#define SIZE_ARC 40
+#define SIZE_LINE 26
+
+#define IGNORE(x) ((void) x)
+
+
+/* estruturas similares as que o MicroStation usa */
+
+typedef struct
+{
+ union
+ {
+ struct
+ {
+ unsigned level:6;
+ unsigned :1;
+ unsigned complex:1;
+ unsigned type:7;
+ unsigned :1;
+ } flags;
+ short type_as_word;
+ } type;
+
+ unsigned short words;
+ unsigned long xmin;
+ unsigned long ymin;
+ unsigned long xmax;
+ unsigned long ymax;
+} Elm_hdr;
+
+typedef struct
+{
+ short attindx;
+ union
+ {
+ short s;
+ struct
+ {
+ unsigned /*class*/ :4;
+ unsigned /*res*/ :4;
+ unsigned /*l*/ :1;
+ unsigned /*n*/ :1;
+ unsigned /*m*/ :1;
+ unsigned attributes:1;
+ unsigned /*r*/ :1;
+ unsigned /*p*/ :1;
+ unsigned /*s*/ :1;
+ unsigned /*hole*/ :1;
+ } flags;
+ } props;
+
+ union
+ {
+ short s;
+ struct
+ {
+ unsigned style:3;
+ unsigned weight:5;
+ unsigned color:8;
+ } b;
+ } symb;
+
+} Disp_hdr;
+
+/* tipo de poligono/setor */
+enum
+{
+ FILLED,
+ OPEN
+};
+
+/* grupos de tamanhos de caracter
+ (usado por gettextwidth e cdgetfontdim) */
+
+static long fontsizes[4][8]=
+{
+ {1,2,4,5,6,7,0},
+ {5,3,2,1,0},
+ {8,6,4,3,2,1,0},
+ {5,3,2,1,0}
+};
+
+
+/**********************
+ * contexto do driver *
+ **********************/
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ FILE *file; /* arquivo dgn */
+ long int bytes; /* tamanho do arquivo */
+ char level;
+
+ short color, style;
+
+ short alignment;
+ short typeface_index;
+ short symbology;
+ long tl;
+ short is_base; /* setado se texto e' do tipo CD_BASE_... */
+
+ short fill_type; /* como o driver faz fill:
+ NOFILL -> nao faz fill
+ CONVEX -> so faz fill de poligonos convexos
+ NORMAL -> faz fill normalmente */
+
+ long colortable[256]; /* palette */
+ short num_colors;
+
+ short is_complex;
+};
+
+/* prototipos de funcao */
+static void startComplexShape(cdCtxCanvas*, unsigned short,short,unsigned short,
+ unsigned long,unsigned long,
+ unsigned long,unsigned long);
+static void endComplexElement(cdCtxCanvas*);
+
+/******************************
+ * *
+ * funcoes internas do driver *
+ * *
+ ******************************/
+
+/*********************************************************
+ * Obtem o descent do texto (para letras como q,p,g etc) *
+ *********************************************************/
+
+static long get_descent(const char *text, int size_pixel)
+{
+ char *descent="jgyqp";
+ long a=0;
+ long length = strlen(text);
+
+ while(a < length)
+ {
+ if(strchr(descent, text[a]))
+ return size_pixel/2;
+
+ a++;
+ }
+ return 0;
+}
+
+/***********************************************
+ * Calcula a largura da string no MicroStation *
+ ***********************************************/
+
+static long gettextwidth(cdCtxCanvas* ctxcanvas, const char *s, int size_pixel)
+{
+ long a=0,
+ width=0,
+ length = strlen(s);
+
+ short default_size=0;
+
+ static char *fontchars[4][8] =
+ {
+ { /* CD_SYSTEM */
+ "Ww",
+ "jshyut#*-=<>",
+ "iIl[]",
+ ";:.,'|!()`{}",
+ "","","",""
+ },
+
+ { /* CD_COURIER */
+ "Iflrit!();.'",
+ "1|[]\"/`",
+ "BCDEKPRSUVXYbdgkpq&-_",
+ "w#%",
+ "Wm^+=<>~",
+ "@","",""
+ },
+
+ { /* CD_TIMES_ROMAN */
+ "m",
+ "HMUWw",
+ "CSTZLbhknpuvxy23567890e",
+ "fstz1#$-=<>",
+ "Iijl*[]",
+ ";:.,'|!()`{}",
+ "",""
+ },
+
+ { /* CD_HELVETICA */
+ "Ww",
+ "jshyut#*-=<>",
+ "iIl[]",
+ ";:.,'|!()`{}",
+ "","","",""
+ }
+ };
+
+ if (ctxcanvas->typeface_index == 1)
+ default_size=2;
+ else if (ctxcanvas->typeface_index == 2)
+ default_size=5;
+ else if (ctxcanvas->typeface_index == 3)
+ default_size=4;
+ else
+ default_size=4;
+
+ for(a=0,width=0;a < length; a++)
+ {
+ static short size_number;
+ static char letter;
+
+ if(s[a] == ' ')
+ letter = s[a-1];
+ else
+ letter = s[a];
+
+ for(size_number=0;size_number < 8;size_number++)
+ {
+ if(strchr(fontchars[ctxcanvas->typeface_index][size_number], letter))
+ {
+ width+=(ctxcanvas->tl*fontsizes[ctxcanvas->typeface_index][size_number])/6;
+ break;
+ }
+ }
+
+ if(size_number == 8)
+ width+=(ctxcanvas->tl*default_size)/6;
+
+ width+=ctxcanvas->tl/3;
+ }
+
+ width-=ctxcanvas->tl/3;
+
+ if (ctxcanvas->canvas->font_style & CD_ITALIC)
+ width+= (long) ((double)size_pixel*tan(4*atan(1)/8)); /* angulo de 15 graus */
+
+ return width;
+}
+
+/****************************
+ * Salva um byte no arquivo *
+ ****************************/
+
+static void put_byte(cdCtxCanvas* ctxcanvas, unsigned char byte)
+{
+ fputc(byte, ctxcanvas->file);
+}
+
+/************************************
+ * Salva um sequencia de caracteres *
+ ************************************/
+
+static void writec (cdCtxCanvas* ctxcanvas, const char *t, short tam )
+{
+ short i;
+
+ ctxcanvas->bytes += tam;
+ for ( i = 0; i < tam; i++ )
+ fputc ( t[i], ctxcanvas->file );
+}
+
+/******************
+ * Salva uma word *
+ ******************/
+
+static void put_word(cdCtxCanvas* ctxcanvas, unsigned short w)
+{
+ char c;
+
+ c = (char) (w & 0xff);
+ fputc (c, ctxcanvas->file);
+ c = (char) ((w >> 8) & 0xff);
+ fputc (c, ctxcanvas->file);
+ ctxcanvas->bytes += 2;
+}
+
+/****************************
+ * Salva um long no arquivo *
+ ****************************/
+
+static void put_long (cdCtxCanvas* ctxcanvas, unsigned long i)
+{
+ put_word(ctxcanvas, (short) (i >> 16));
+ put_word(ctxcanvas, (short) i);
+}
+
+/*******************
+ * Salva um double *
+ *******************/
+
+static void put_as_double(cdCtxCanvas* ctxcanvas, long i)
+{
+ float dfloat=(float) 4*i;
+
+ put_long(ctxcanvas, *((long *) &dfloat));
+ put_long(ctxcanvas, 0);
+
+ ctxcanvas->bytes+=sizeof(float);
+}
+
+/****************************
+ * Salva uma UOR no arquivo *
+ ****************************/
+
+static void put_uor(cdCtxCanvas* ctxcanvas, long i)
+{
+ put_word(ctxcanvas, (unsigned short)((i >> 16) ^ (1 << 15))); /* troca o bit 31
+ para transformar em uor */
+ put_word(ctxcanvas, (unsigned short)i);
+}
+
+/***************************************
+ * Salva a bounding box de um elemento *
+ ***************************************/
+
+static void put_bound(cdCtxCanvas* ctxcanvas, long xmin, long xmax, long ymin, long ymax)
+{
+ put_uor(ctxcanvas, xmin);
+ put_uor(ctxcanvas, ymin);
+ put_uor(ctxcanvas, 0L);
+ put_uor(ctxcanvas, xmax);
+ put_uor(ctxcanvas, ymax);
+ put_uor(ctxcanvas, 0L);
+}
+
+/******************************************
+ * Calcula a bounding box de uma polyline *
+ ******************************************/
+
+static void line_string_bound(cdPoint *buffer, short num_vertex,
+ unsigned long *xmin, unsigned long *ymin,
+ unsigned long *xmax, unsigned long *ymax)
+{
+ short i;
+ unsigned long v;
+
+ *xmin = *xmax = buffer[0].x;
+ *ymin = *ymax = buffer[0].y;
+
+ for (i = 1; i < num_vertex; i++)
+ {
+ v = buffer[i].x;
+ if (v < *xmin)
+ *xmin = v;
+ else if (v > *xmax)
+ *xmax = v;
+
+ v = (long) buffer[i].y;
+ if (v < *ymin)
+ *ymin = v;
+ else if (v > *ymax)
+ *ymax = v;
+ }
+}
+
+/************************************
+ * Retorna symbology de um elemento *
+ ************************************/
+
+static short symbology(cdCtxCanvas* ctxcanvas)
+{
+ return (short)((ctxcanvas->color << 8) | (ctxcanvas->canvas->line_width << 3) | ctxcanvas->style);
+}
+
+/*****************************************
+ * Salva um Element Header no arquivo *
+ *****************************************/
+
+static void putElementHeader(cdCtxCanvas* ctxcanvas, Elm_hdr *ehdr)
+{
+ ehdr->type.flags.complex = ctxcanvas->is_complex;
+
+ put_word(ctxcanvas, (short)(ehdr->type.flags.type << 8 |
+ ehdr->type.flags.complex << 7 | ehdr->type.flags.level));
+
+
+ put_word(ctxcanvas, ehdr->words);
+ put_bound(ctxcanvas, ehdr->xmin, ehdr->xmax, ehdr->ymin, ehdr->ymax);
+}
+
+/**************************************
+ * Salva um display header no arquivo *
+ **************************************/
+
+static void putDisplayHeader(cdCtxCanvas* ctxcanvas, Disp_hdr *dhdr)
+{
+ put_word(ctxcanvas, 0); /* graphics group */
+ put_word(ctxcanvas, dhdr->attindx); /* index to attributes */
+ put_word(ctxcanvas, dhdr->props.flags.attributes << 11); /* properties */
+ put_word(ctxcanvas, dhdr->symb.s); /* display symbology */
+}
+
+
+/***************************************
+ * completa o arquivo com zeros para *
+ * que o numero de bytes seja multiplo *
+ * de 512 *
+ ***************************************/
+
+static void complete_file(cdCtxCanvas* ctxcanvas)
+{
+ long resto, i;
+
+ put_word(ctxcanvas, END_OF_DGN_FILE);
+
+ resto = DGN_FILE_BLOCK - ctxcanvas->bytes % DGN_FILE_BLOCK;
+
+ /* checa validade do tamanho do arquivo */
+ if (resto%2 != 0) return;
+
+ for (i = 0; i < resto; i+=2)
+ put_word(ctxcanvas, 0);
+}
+
+/*************************************
+ * Salva um elemento arco no arquivo *
+ *************************************/
+
+static void arc (cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, double a1, double a2)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=16;
+ ehdr.words=SIZE_ARC-2;
+ ehdr.xmin=xc - w/2;
+ ehdr.xmax=xc + w/2;
+ ehdr.ymin=yc - h/2;
+ ehdr.ymax=yc + h/2;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx = ehdr.words - 14;
+ dhdr.props.flags.attributes = 0;
+ dhdr.symb.s = symbology(ctxcanvas);
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_long(ctxcanvas, (long) a1*360000); /* start angle */
+ put_long(ctxcanvas, (long) (a2-a1)*360000); /* sweep angle */
+ put_as_double(ctxcanvas, w/2); /* primary axis */
+ put_as_double(ctxcanvas, h/2); /* secondary axis */
+ put_long(ctxcanvas, 0); /* rotation angle (sempre 0) */
+ put_as_double(ctxcanvas, xc); /* x origin */
+ put_as_double(ctxcanvas, yc); /* y origin */
+}
+
+/***************************************
+ * Salva um elemento elipse no arquivo *
+ ***************************************/
+
+static void ellipse(cdCtxCanvas* ctxcanvas, long xc, long yc, long w, long h, short type)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=15;
+ ehdr.words=34+((type==FILLED) ? 8 : 0);
+ ehdr.xmin=xc - w/2;
+ ehdr.xmax=xc + w/2;
+ ehdr.ymin=yc - h/2;
+ ehdr.ymax=yc + h/2;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=20;
+ dhdr.props.flags.attributes=(type == FILLED) ? 1 : 0;
+ dhdr.symb.s=symbology(ctxcanvas);
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_as_double(ctxcanvas, w/2); /* primary axis */
+ put_as_double(ctxcanvas, h/2); /* secondary axis */
+ put_long(ctxcanvas, 50); /* rotation angle (sempre 0) */
+ put_as_double(ctxcanvas, xc); /* x origin */
+ put_as_double(ctxcanvas, yc); /* y origin */
+
+ /* salva atributo de fill */
+ if(type == FILLED)
+ {
+ put_word(ctxcanvas, 0x1007);
+ put_word(ctxcanvas, 65);
+ put_word(ctxcanvas, 0x802);
+ put_word(ctxcanvas, 0x0001);
+ put_word(ctxcanvas, ctxcanvas->color);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ }
+}
+
+static short getclosestColor(cdCtxCanvas* ctxcanvas, long color)
+{
+ short count=0, closest=0;
+ long diff=0;
+ unsigned char r = cdRed(color),
+ g = cdGreen(color),
+ b = cdBlue(color);
+ short rd, gd, bd;
+ long newdiff;
+
+ /* procura a cor mais proxima */
+
+ diff = 3*65536; /* inicializa com maior diferenca possivel */
+
+ for(count=0; count < ctxcanvas->num_colors; count++)
+ {
+ rd = r - cdRed(ctxcanvas->colortable[count]);
+ gd = g - cdGreen(ctxcanvas->colortable[count]);
+ bd = b - cdBlue(ctxcanvas->colortable[count]);
+
+ newdiff = rd*rd + gd*gd + bd*bd;
+
+ if(newdiff <= diff)
+ {
+ /* verifica se encontrou a cor */
+ if(newdiff == 0)
+ return count-1;
+
+ diff = newdiff;
+ closest=count-1;
+ }
+ }
+
+ /* nao encontrou a cor, tenta adicionar na palette, ou retorna a mais proxima */
+ if(ctxcanvas->num_colors < 254)
+ {
+ ctxcanvas->colortable[ctxcanvas->num_colors+1] = color;
+ return ctxcanvas->num_colors++;
+ }
+ else
+ return closest;
+}
+
+static void saveColorTable(cdCtxCanvas* ctxcanvas)
+{
+ unsigned char r,g,b;
+ short i;
+
+ put_word(ctxcanvas, (0x05 << 8) | 1); /* colortable */
+ put_word(ctxcanvas, 434);
+
+ put_long(ctxcanvas, 0);
+ put_long(ctxcanvas, 0);
+ put_long(ctxcanvas, 0);
+ put_long(ctxcanvas, 0xffffffff);
+ put_long(ctxcanvas, 0xffffffff);
+ put_long(ctxcanvas, 0xffffffff);
+
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 420);
+ put_word(ctxcanvas, 0x0400);
+ put_word(ctxcanvas, 0x100);
+ put_word(ctxcanvas, 0);
+
+ for(i=0;i<256;i++)
+ {
+ cdDecodeColor(ctxcanvas->colortable[i], &r, &g, &b);
+ put_byte(ctxcanvas, r);
+ put_byte(ctxcanvas, g);
+ put_byte(ctxcanvas, b);
+ }
+
+ put_word(ctxcanvas, 25);
+ for(i=0;i<32;i++)
+ put_word(ctxcanvas, 0x2020);
+}
+
+
+/*****************************
+ * Le uma word de um arquivo *
+ *****************************/
+
+static short file_get_word(FILE *fp)
+{
+ short word=0;
+
+ word = (short)fgetc(fp);
+ word |= ((short)fgetc(fp) << 8) & 0xff00;
+
+ return word;
+}
+
+/********************************
+ * Salva uma word em um arquivo *
+ ********************************/
+
+static void file_put_word (short word, FILE *fp)
+{
+ fputc ((char) (word & 0xff), fp);
+ fputc ((char) ((word >> 8) & 0xff), fp);
+}
+
+/*******************************************
+ * Le elementos de um arquivo DGN e os *
+ * coloca no inicio do arquivo aberto pelo *
+ * driver *
+ *******************************************/
+
+static void dgn_copy (FILE *file, cdCtxCanvas *ctxcanvas)
+{
+ short word=0;
+
+ while ((word = file_get_word(file)) != END_OF_DGN_FILE)
+ {
+ file_put_word(word, ctxcanvas->file); /* type e level do elemento */
+ ctxcanvas->bytes+=2;
+
+ word = file_get_word(file); /* words to follow */
+ file_put_word(word, ctxcanvas->file);
+ ctxcanvas->bytes+=2;
+
+ while (word) /* copia resto do elemento */
+ {
+ file_put_word(file_get_word(file), ctxcanvas->file);
+ word--;
+ ctxcanvas->bytes+=2;
+ }
+ }
+}
+
+
+/*
+ * Funcoes do driver
+ */
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ saveColorTable(ctxcanvas);
+ complete_file(ctxcanvas);
+ fclose (ctxcanvas->file);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cddeactivate (cdCtxCanvas* ctxcanvas)
+{
+ fflush(ctxcanvas->file);
+}
+
+static void cdflush (cdCtxCanvas* ctxcanvas)
+{
+ fflush(ctxcanvas->file);
+}
+
+
+/******************************************************/
+/* primitives */
+/******************************************************/
+
+static void cdline (cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+ cdPoint buffer[2];
+
+ buffer[0].x=x1;
+ buffer[0].y=y1;
+ buffer[1].x=x2;
+ buffer[1].y=y2;
+
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=3;
+
+ ehdr.words=SIZE_LINE-2;
+
+ line_string_bound(buffer, 2, &ehdr.xmin,
+ &ehdr.ymin,&ehdr.xmax,&ehdr.ymax);
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx = ehdr.words - 14;
+ dhdr.props.flags.attributes = 0;
+ dhdr.symb.s=symbology(ctxcanvas);
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ /* pontos inicial e final da linha */
+
+ put_long(ctxcanvas, (long) x1);
+ put_long(ctxcanvas, (long) y1);
+ put_long(ctxcanvas, (long) x2);
+ put_long(ctxcanvas, (long) y2);
+}
+
+static void cdbox (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=6;
+ ehdr.words=17+4*5+8;
+ ehdr.xmin=xmin;
+ ehdr.xmax=xmax;
+ ehdr.ymin=ymin;
+ ehdr.ymax=ymax;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=3+4*5;
+ dhdr.props.flags.attributes=1;
+ dhdr.symb.s=symbology(ctxcanvas);
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, 5); /* numero de vertices */
+
+ /* vertices */
+ put_long(ctxcanvas, (long) xmin);
+ put_long(ctxcanvas, (long) ymin);
+
+ put_long(ctxcanvas, (long) xmax);
+ put_long(ctxcanvas, (long) ymin);
+
+ put_long(ctxcanvas, (long) xmax);
+ put_long(ctxcanvas, (long) ymax);
+
+ put_long(ctxcanvas, (long) xmin);
+ put_long(ctxcanvas, (long) ymax);
+
+ put_long(ctxcanvas, (long) xmin);
+ put_long(ctxcanvas, (long) ymin);
+
+ /* atributos de fill */
+
+ put_word(ctxcanvas, 0x1007);
+ put_word(ctxcanvas, 65);
+ put_word(ctxcanvas, 0x802);
+ put_word(ctxcanvas, 0x0001);
+ put_word(ctxcanvas, ctxcanvas->color);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+}
+
+static void cdarc (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (a2 == a1 + 360)
+ ellipse(ctxcanvas, xc,yc,w,h,OPEN);
+ else
+ arc(ctxcanvas, xc, yc, w, h, a1, a2);
+}
+
+static void cdsector (cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (a2 == a1 + 360)
+ {
+ ellipse(ctxcanvas, xc,yc,w,h,FILLED);
+ return;
+ }
+
+ startComplexShape(ctxcanvas, 3, 1, SIZE_ARC+SIZE_LINE*2,
+ (unsigned long) xc-w/2, (unsigned long) yc-h/2,
+ (unsigned long) xc+h/2, (unsigned long) yc+h/2);
+
+ arc(ctxcanvas, xc, yc, w, h, a1, a2);
+
+ cdline(ctxcanvas, xc, yc, (int)
+ (((double)w*cos(a1*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a1*CD_DEG2RAD))/2.+.5));
+ cdline(ctxcanvas, xc, yc, (int)
+ (((double)w*cos(a2*CD_DEG2RAD)/2.+.5)), (int) (((double)h*sin(a2*CD_DEG2RAD))/2.+.5));
+
+ endComplexElement(ctxcanvas);
+}
+
+static void cdtext (cdCtxCanvas* ctxcanvas, int x, int y, const char *s)
+{
+ long n=0;
+ long descent=0;
+ short w=0;
+ long hc=0,wc=0;
+ int size_pixel;
+ short italic = (ctxcanvas->canvas->font_style&CD_ITALIC);
+
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ n = strlen(s);
+
+ if(n > 255)
+ n=255;
+
+ w = (short)((n/2)+(n%2));
+ size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size);
+ descent=get_descent(s, size_pixel);
+ hc = size_pixel+descent;
+ wc = gettextwidth(ctxcanvas, s, size_pixel);
+
+ y+=descent;
+
+ switch (ctxcanvas->alignment)
+ {
+ case 12: x = x; y = y; break;
+ case 13: x = x; y = y - (int) (hc/2.0); break;
+ case 14: x = x; y = y - (int) hc; break;
+ case 6: x = x - (int) (wc/2.0); y = y; break;
+ case 7: x = x - (int) (wc/2.0); y = y - (int) (hc/2.0); break;
+ case 8: x = x - (int) (wc/2.0); y = y - (int) hc; break;
+ case 0: x = x - (int) wc; y = y; break;
+ case 1: x = x - (int) wc; y = y - (int) (hc/2.0); break;
+ case 2: x = x - (int) wc; y = y - (int) hc; break;
+ }
+
+ if(ctxcanvas->is_base)
+ y -= (int) (hc/4.0);
+
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=17;
+ ehdr.words=28+w+((italic) ? 8 : 0);
+ ehdr.xmin=x;
+ ehdr.xmax=x+wc;
+ ehdr.ymin=y-descent;
+ ehdr.ymax=y+hc;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=14+w;
+ dhdr.props.flags.attributes=(italic) ? 1 : 0;
+
+ if (ctxcanvas->canvas->font_style&CD_BOLD)
+ dhdr.symb.s=ctxcanvas->color << 8 | (3 << 3);
+ else
+ dhdr.symb.s=ctxcanvas->color << 8;
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, (ctxcanvas->alignment << 8) | ctxcanvas->typeface_index);
+
+ put_long(ctxcanvas, (long)((1000 * ctxcanvas->tl) / 6) | (1 << 7));
+ put_long(ctxcanvas, (long)((1000 * size_pixel) / 6) | (1 << 7));
+
+ put_long(ctxcanvas, 0);
+ put_long(ctxcanvas, x);
+ put_long(ctxcanvas, y);
+ put_word(ctxcanvas, (unsigned short) n);
+ writec(ctxcanvas, s, (short)(n+(n%2))); /* deve escrever sempre um numero par de caracteres */
+
+ if(italic)
+ {
+ put_word(ctxcanvas, 0x1007); /* atributos e words to follow */
+ put_word(ctxcanvas, 0x80d4); /* tipo de atributo */
+ put_long(ctxcanvas, 0x000865c0);
+ put_long(ctxcanvas, 0x00520000);
+ put_long(ctxcanvas, 0x00000000);
+ }
+}
+
+static void startComplexShape(cdCtxCanvas* ctxcanvas,
+ unsigned short num_elements,
+ short is_fill,
+ unsigned short size,
+ unsigned long xmin,
+ unsigned long ymin,
+ unsigned long xmax,
+ unsigned long ymax)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=14;
+ ehdr.words=22 + ((is_fill) ? 8 : 0);
+ ehdr.xmax = xmax;
+ ehdr.xmin = xmin;
+ ehdr.ymax = ymax;
+ ehdr.ymin = ymin;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=4;
+ dhdr.props.flags.attributes = (is_fill) ? 1 : 0;
+ dhdr.symb.s=symbology(ctxcanvas);
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, size + 5 + ((is_fill) ? 8 : 0));
+ put_word(ctxcanvas, num_elements);
+
+ put_long(ctxcanvas, 0); /* atributo nulo */
+ put_long(ctxcanvas, 0);
+
+ /* salva atributo de fill */
+ if(is_fill)
+ {
+ put_word(ctxcanvas, 0x1007);
+ put_word(ctxcanvas, 65);
+ put_word(ctxcanvas, 0x802);
+ put_word(ctxcanvas, 0x0001);
+ put_word(ctxcanvas, ctxcanvas->color);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ }
+
+ /* marca inicio de elemento complexo */
+
+ ctxcanvas->is_complex = 1;
+}
+
+
+static void startComplexChain(cdCtxCanvas* ctxcanvas,
+ unsigned short num_elements,
+ unsigned short size,
+ unsigned long xmin,
+ unsigned long ymin,
+ unsigned long xmax,
+ unsigned long ymax)
+
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=12;
+
+ ehdr.words=22;
+ ehdr.xmax = xmax;
+ ehdr.xmin = xmin;
+ ehdr.ymax = ymax;
+ ehdr.ymin = ymin;
+
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=4;
+ dhdr.props.flags.attributes = 1;
+ dhdr.symb.s=symbology(ctxcanvas);
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, size+5);
+ put_word(ctxcanvas, num_elements);
+
+ put_long(ctxcanvas, 0); /* atributo nulo */
+ put_long(ctxcanvas, 0);
+
+
+ /* marca inicio de elemento complexo */
+
+ ctxcanvas->is_complex = 1;
+}
+
+static void endComplexElement(cdCtxCanvas* ctxcanvas)
+{
+ ctxcanvas->is_complex = 0;
+}
+
+static void putLineString(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+ short i=0;
+
+ ehdr.type.flags.level=ctxcanvas->level;
+
+ ehdr.type.flags.type=4;
+
+ ehdr.words=SIZE_LINE_STRING(num_vertex)-2;
+
+ line_string_bound(buffer, num_vertex, &ehdr.xmin,
+ &ehdr.ymin,&ehdr.xmax,&ehdr.ymax);
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=ehdr.words-14;
+ dhdr.props.flags.attributes = 0;
+ dhdr.symb.s=symbology(ctxcanvas);
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, num_vertex);
+
+ for (i = 0; i < num_vertex; i++)
+ {
+ put_long(ctxcanvas, (long) buffer[i].x);
+ put_long(ctxcanvas, (long) buffer[i].y);
+ }
+}
+
+static void putShape(cdCtxCanvas* ctxcanvas, cdPoint *buffer, short num_vertex)
+{
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+ short i=0;
+
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=6;
+
+ ehdr.words=SIZE_FILLED_SHAPE(num_vertex)-2;
+
+ line_string_bound(buffer, num_vertex, &ehdr.xmin,
+ &ehdr.ymin,&ehdr.xmax,&ehdr.ymax);
+
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=ehdr.words - 14 - 8; /* 8 -> size of attributes */
+ dhdr.props.flags.attributes = 1;
+ dhdr.symb.s=symbology(ctxcanvas);
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, num_vertex);
+
+ for (i = 0; i < num_vertex; i++)
+ {
+ put_long(ctxcanvas, (long) buffer[i].x);
+ put_long(ctxcanvas, (long) buffer[i].y);
+ }
+
+ put_word(ctxcanvas, 0x1007);
+ put_word(ctxcanvas, 65);
+ put_word(ctxcanvas, 0x802);
+ put_word(ctxcanvas, 0x0001);
+ put_word(ctxcanvas, ctxcanvas->color);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+}
+
+static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ short is_fill=0;
+
+ if(mode == CD_FILL && ctxcanvas->fill_type == NOFILL)
+ mode = CD_CLOSED_LINES;
+
+ if(n > MAX_NUM_VERTEX_PER_POLYLINE)
+ n = MAX_NUM_VERTEX_PER_POLYLINE;
+
+ /* acerta buffer de pontos */
+ if(mode == CD_FILL || mode == CD_CLOSED_LINES)
+ {
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+ }
+
+ /* se fill_type for CONVEX, testa se poligono e' convexo ou concavo */
+ if((ctxcanvas->fill_type == CONVEX) && (n > 3) && (mode == CD_FILL))
+ {
+ short signal=0;
+ short count=0;
+ long vect=0;
+
+ /* calcula sinal do vetorial entre o primeiro lado e o segundo */
+ vect = (poly[1].x - poly[0].x) *
+ (poly[2].y - poly[1].y) -
+ (poly[1].y - poly[0].y) *
+ (poly[2].x - poly[1].x);
+
+ if(vect == 0)
+ mode = CD_CLOSED_LINES; /* ver se precisa mudar */
+ else
+ {
+ signal = (short)(vect/abs(vect));
+
+ for(count=1 ; count< (n-2); count++)
+ {
+ vect = (poly[count+1].x - poly[count].x) *
+ (poly[count+2].y - poly[count+1].y) -
+ (poly[count+1].y - poly[count].y) *
+ (poly[count+2].x - poly[count+1].x);
+
+ if(vect == 0)
+ {
+ mode=CD_CLOSED_LINES;
+ break;
+ }
+
+ if((vect/abs(vect)) != signal)
+ {
+ mode=CD_CLOSED_LINES;
+ break;
+ }
+ }
+ }
+ }
+
+ /* se tiver fill */
+
+ if(mode == CD_FILL)
+ is_fill=1;
+
+ if(n > MAX_NUM_VERTEX) /* tem que usar complex shape ou chain */
+ {
+ short count=0;
+ short num_whole_elements = n / MAX_NUM_VERTEX;
+ short num_whole_vertex = num_whole_elements * MAX_NUM_VERTEX;
+ short rest = n % MAX_NUM_VERTEX;
+ short is_there_rest = (rest > 0) ? 1 : 0;
+ unsigned long xmax, xmin, ymax, ymin;
+ unsigned short size =
+ SIZE_LINE_STRING(MAX_NUM_VERTEX)*num_whole_elements+
+ SIZE_LINE_STRING(rest)*is_there_rest;
+
+ line_string_bound(poly, n, &xmin, &ymin, &xmax, &ymax);
+
+ if(mode == CD_OPEN_LINES)
+ startComplexChain(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)),
+ size, xmin, ymin, xmax, ymax);
+ else
+ startComplexShape(ctxcanvas, (unsigned short) (num_whole_elements+((rest > 0) ? 1 : 0)),
+ is_fill, size, xmin, ymin, xmax, ymax);
+
+ for(count=0;count < num_whole_vertex; count+=MAX_NUM_VERTEX, n-=MAX_NUM_VERTEX)
+ putLineString(ctxcanvas, &poly[count], MAX_NUM_VERTEX);
+
+ if(rest)
+ putLineString(ctxcanvas, &poly[num_whole_vertex],n);
+
+ endComplexElement(ctxcanvas);
+ }
+ else
+ {
+ if(is_fill)
+ putShape(ctxcanvas, poly, n);
+ else
+ putLineString(ctxcanvas, poly, n);
+ }
+}
+
+/**************
+ * attributes *
+ **************/
+
+static int cdlinestyle (cdCtxCanvas* ctxcanvas, int style)
+{
+ switch(style)
+ {
+ case CD_CONTINUOUS:
+ ctxcanvas->style = 0;
+ break;
+
+ case CD_DASHED:
+ ctxcanvas->style = 3;
+ break;
+
+ case CD_DOTTED:
+ ctxcanvas->style = 1;
+ break;
+
+ case CD_DASH_DOT:
+ ctxcanvas->style = 4;
+ break;
+
+ case CD_DASH_DOT_DOT:
+ ctxcanvas->style = 6;
+ break;
+ }
+
+ return style;
+}
+
+static int cdlinewidth (cdCtxCanvas* ctxcanvas, int width)
+{
+ (void)ctxcanvas;
+ width = width & 31;
+ return width;
+}
+
+static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size)
+{
+ (void)style;
+ ctxcanvas->tl = (long)(cdGetFontSizePoints(ctxcanvas->canvas, size)/4)*3;
+
+ if (cdStrEqualNoCase(type_face, "Courier"))
+ ctxcanvas->typeface_index=1;
+ else if (cdStrEqualNoCase(type_face, "Times"))
+ ctxcanvas->typeface_index=2;
+ else if (cdStrEqualNoCase(type_face, "Helvetica"))
+ ctxcanvas->typeface_index=3;
+ else if (cdStrEqualNoCase(type_face, "System"))
+ ctxcanvas->typeface_index=0;
+ else
+ return 0;
+
+ return 1;
+}
+
+static void cdgetfontdim (cdCtxCanvas* ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ int size_pixel;
+
+ if(max_width)
+ {
+ int a=0;
+ *max_width=0;
+
+ while(fontsizes[ctxcanvas->typeface_index][a])
+ {
+ if(fontsizes[ctxcanvas->typeface_index][a] > *max_width)
+ *max_width = fontsizes[ctxcanvas->typeface_index][a];
+ a++;
+ }
+ }
+
+ size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size);
+
+ if(height) *height = (size_pixel*3)/2;
+ if(ascent) *ascent = size_pixel;
+ if(descent) *descent = size_pixel/2;
+}
+
+static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height)
+{
+ int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size);
+ if(height) *height = size_pixel + get_descent(s, size_pixel);
+ if(width) *width = gettextwidth(ctxcanvas, s, size_pixel);
+}
+
+static int cdtextalignment (cdCtxCanvas* ctxcanvas, int alignment)
+{
+ ctxcanvas->is_base = 0;
+
+ /* DGN guarda posicao do texto em relacao ao ponto */
+
+ switch(alignment)
+ {
+ case CD_NORTH:
+ ctxcanvas->alignment = 8; /* center-bottom */
+ break;
+
+ case CD_SOUTH:
+ ctxcanvas->alignment = 6; /* center-top */
+ break;
+
+ case CD_EAST:
+ ctxcanvas->alignment = 1; /* left-center */
+ break;
+
+ case CD_WEST:
+ ctxcanvas->alignment = 13; /* right-center */
+ break;
+
+ case CD_NORTH_EAST:
+ ctxcanvas->alignment = 2; /* left-bottom */
+ break;
+
+ case CD_NORTH_WEST:
+ ctxcanvas->alignment = 14; /* right-bottom */
+ break;
+
+ case CD_SOUTH_EAST:
+ ctxcanvas->alignment = 0; /* left-top */
+ break;
+
+ case CD_SOUTH_WEST:
+ ctxcanvas->alignment = 12; /* right-top */
+ break;
+
+ case CD_CENTER:
+ ctxcanvas->alignment = 7; /* center-center */
+ break;
+
+ case CD_BASE_LEFT:
+ ctxcanvas->alignment = 13; /* right-center */
+ ctxcanvas->is_base=1;
+ break;
+
+ case CD_BASE_CENTER:
+ ctxcanvas->alignment = 7; /* center-center */
+ ctxcanvas->is_base=1;
+ break;
+
+ case CD_BASE_RIGHT:
+ ctxcanvas->alignment = 1; /* left-center */
+ ctxcanvas->is_base=1;
+ break;
+ }
+
+ return alignment;
+}
+
+/******************************************************/
+/* color */
+/******************************************************/
+
+static void cdpalette (cdCtxCanvas* ctxcanvas, int n, const long int *palette, int mode)
+{
+ int c=0;
+
+ IGNORE(mode);
+
+ for(c=0; c < n; c++)
+ ctxcanvas->colortable[c] = *palette++;
+
+ ctxcanvas->num_colors = n;
+}
+
+static long int cdforeground (cdCtxCanvas* ctxcanvas, long int color)
+{
+ ctxcanvas->color = getclosestColor(ctxcanvas, color);
+ return color;
+}
+
+/******************************************************/
+/* client images */
+/******************************************************/
+
+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=0,j=0, remainder=iw%2, total_colors;
+ int *ix=NULL,*iy=NULL;
+ Elm_hdr ehdr;
+ Disp_hdr dhdr;
+ unsigned char map_colors[256];
+
+
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=87;
+ ehdr.words=39;
+ ehdr.xmin=x;
+ ehdr.xmax=x+w;
+ ehdr.ymin=y;
+ ehdr.ymax=y+h;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=25;
+ dhdr.symb.s=0;
+
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ /* description of the element */
+ put_long(ctxcanvas, 21+(23+w/2+w%2)*h); /* total length of cell */
+ put_word(ctxcanvas, 0x0714); /* raster flags */
+ put_word(ctxcanvas, 0x0100); /* background e foreground colors
+ (nao usados) */
+ put_word(ctxcanvas, w); /* largura da imagem em pixels */
+ put_word(ctxcanvas, h); /* altura da imagem em pixel */
+ put_long(ctxcanvas, 0); /* resevado */
+ put_as_double(ctxcanvas, 0); /* resolution (nao usado) */
+
+ put_word(ctxcanvas, 0x4080); /* scale */
+ put_long(ctxcanvas, 0);
+ put_word(ctxcanvas, 0);
+
+ put_long(ctxcanvas, x); /* origem */
+ put_long(ctxcanvas, y+h);
+ put_long(ctxcanvas, 0);
+
+ put_word(ctxcanvas, 0); /* no de vertices */
+
+ ctxcanvas->is_complex = 1; /* elemento complexo */
+
+ /* obtem o maior indice usado na imagem */
+
+ total_colors = 0;
+ for (i = 0; i < iw*ih; i++)
+ {
+ if (index[i] > total_colors)
+ total_colors = index[i];
+ }
+ total_colors++;
+
+ /* cria tabela para acelerar match de cor na palette */
+
+ for (i = 0; i < total_colors; i++)
+ {
+ map_colors[i] = (unsigned char)getclosestColor(ctxcanvas, colors[i]);
+ }
+
+ /** salva dados da imagem **/
+
+ /* calcula stretch */
+
+ ix = cdGetZoomTable(w, xmax-xmin+1, xmin);
+ iy = cdGetZoomTable(h, ymax-ymin+1, ymin);
+
+ for(i=h-1; i >= 0; i--)
+ {
+ /* raster header element */
+ ehdr.type.flags.level=ctxcanvas->level;
+ ehdr.type.flags.type=88;
+ ehdr.words=21+w/2+remainder;
+
+ putElementHeader(ctxcanvas, &ehdr);
+
+ /* Display Header */
+ dhdr.attindx=7+w/2+remainder;
+ dhdr.symb.s=0;
+ putDisplayHeader(ctxcanvas, &dhdr);
+
+ put_word(ctxcanvas, 0x0714); /* raster flags */
+ put_word(ctxcanvas, 0x0100); /* background e foreground
+ colors (nao usados) */
+
+ put_word(ctxcanvas, 0); /* x offset da origem */
+ put_word(ctxcanvas, i); /* y offset */
+ put_word(ctxcanvas, w); /* numero de pixels neste elemento */
+
+ for(j=0; j < w; j++)
+ put_byte(ctxcanvas, map_colors[index[(iy[i])*iw + ix[j]]]);
+
+ if(remainder) put_byte(ctxcanvas, 0);
+ }
+
+ ctxcanvas->is_complex = 0;
+
+ free(ix); /* libera memoria alocada */
+ free(iy);
+}
+
+/******************************************************/
+/* server images */
+/******************************************************/
+
+static void cdpixel (cdCtxCanvas* ctxcanvas, int x, int y, long int color)
+{
+ long old_color = cdforeground(ctxcanvas, color);
+ int old_linestyle = cdlinestyle(ctxcanvas, CD_CONTINUOUS);
+ int old_linewidth = cdlinewidth(ctxcanvas, 1);
+
+ cdline(ctxcanvas, x,y,x,y);
+
+ cdforeground(ctxcanvas, old_color);
+ cdlinestyle(ctxcanvas, old_linestyle);
+ cdlinewidth(ctxcanvas, old_linewidth);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas *ctxcanvas;
+ char* strdata = (char*)data;
+ char words[4][256];
+ char filename[10240] = "";
+ char seedfile[10240] = "";
+ int count = 0;
+ double res = 0;
+
+ if (!data) return;
+
+ /* separa palavras da expressao, que e' na forma
+ "filename [mm_wxmm_h] [res] [-f] [-sseedfile]" */
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata, "%s %s %s %s", words[0], words[1], words[2], words[3]);
+
+ if(!strlen(filename)) /* se nao pegou filename */
+ return;
+
+ ctxcanvas = (cdCtxCanvas *) malloc(sizeof(cdCtxCanvas));
+
+ /* tenta criar arquivo DGN */
+
+ if((ctxcanvas->file = fopen (filename, "wb"))==NULL)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ /* verifica se foi passado tamanho do canvas em mm. Se foi,
+ extrai-o da string */
+
+ if(sscanf(words[0], "%lgx%lg",
+ &canvas->w_mm, &canvas->h_mm) == 2)
+ {
+ count++; /* incrementa contador de palavras */
+
+ if(canvas->w_mm == 0 || canvas->h_mm == 0)
+ {
+ fclose(ctxcanvas->file);
+ free(ctxcanvas);
+ return;
+ }
+ }
+ else
+ canvas->w_mm = canvas->h_mm = 0;
+
+ /* Verifica se foi passada resolucao */
+
+ if(sscanf(words[count], "%lg", &res) == 1)
+ {
+ count++; /* incrementa contador de palavras */
+
+ if(res <= 0) /* verifica validade da resolucao */
+ {
+ fclose(ctxcanvas->file);
+ free(ctxcanvas);
+ return;
+ }
+ }
+ else
+ res = 3.78;
+
+ /* se tamanho em milimetros nao tiver sido inicializado,
+ usa como default o tamanho maximo em pixels para fazer as
+ contas
+ */
+
+ if (canvas->w_mm == 0 || canvas->h_mm == 0)
+ {
+ canvas->w = INT_MAX;
+ canvas->h = INT_MAX;
+
+ canvas->w_mm = canvas->w / res;
+ canvas->h_mm = canvas->h / res;
+ }
+ else
+ {
+ canvas->w = (long) (canvas->w_mm * res);
+ canvas->h = (long) (canvas->h_mm * res);
+ }
+
+ canvas->xres = res;
+ canvas->yres = res;
+ canvas->bpp = 8;
+
+ /* verifica se usuario que alterar metodo de fill */
+
+ if (strcmp(words[count], "-f")==0)
+ {
+ ctxcanvas->fill_type = CONVEX;
+ count++;
+ }
+ else
+ ctxcanvas->fill_type = NORMAL;
+
+ /* se tiver passado seedfile como argumento */
+ if(sscanf(words[count], "-s%s", seedfile) == 1)
+ {
+ FILE *seed=NULL;
+ char *cd_dir = getenv("CDDIR");
+ static char newfilename[512];
+
+ if(cd_dir == NULL)
+ cd_dir = ".";
+
+ sprintf(newfilename, "%s/%s", cd_dir, seedfile);
+
+ count++;
+
+ /* testa concatenando com variavel de ambiente */
+
+ if((seed = fopen (newfilename, "rb"))==NULL)
+ {
+ /* tenta abrir usando string passada pelo usuario
+ diretamente */
+
+ if((seed = fopen (seedfile, "rb"))==NULL)
+ {
+ fclose(ctxcanvas->file);
+ free(ctxcanvas);
+ return;
+ }
+ }
+
+ /* concatena seed */
+
+ fseek(seed, 0, SEEK_SET);
+ fseek(ctxcanvas->file, 0, SEEK_SET);
+
+ ctxcanvas->bytes=0;
+ dgn_copy(seed, ctxcanvas);
+ fclose(seed);
+ }
+
+ ctxcanvas->canvas = canvas;
+ canvas->ctxcanvas = ctxcanvas;
+
+ /* config */
+
+ ctxcanvas->level = 1;
+
+ /** valores default do contexto sao setados **/
+
+ /* texto */
+
+ ctxcanvas->alignment = 12;
+ ctxcanvas->is_base = 1;
+ ctxcanvas->typeface_index = 0;
+ ctxcanvas->tl=12;
+
+ /* cores */
+
+ memset(ctxcanvas->colortable, 0, 1024);
+ ctxcanvas->colortable[0] = CD_BLACK;
+ ctxcanvas->num_colors = 1;
+
+ /* atributos */
+
+ ctxcanvas->color = 1;
+ ctxcanvas->style = 0;
+
+ /* DGN */
+
+ ctxcanvas->is_complex=0;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxPixel = cdpixel;
+ canvas->cxLine = cdline;
+ canvas->cxPoly = cdpoly;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarc;
+ canvas->cxSector = cdsector;
+ canvas->cxText = cdtext;
+ canvas->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxFont = cdfont;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxPalette = cdpalette;
+ canvas->cxForeground = cdforeground;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+/******************************************************/
+
+static cdContext cdDGNContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB |
+ CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | CD_CAP_RECT |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD |
+ CD_CAP_IMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE |
+ CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB |
+ CD_CAP_FPRIMTIVES | CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextDGN(void)
+{
+ return &cdDGNContext;
+}
+
+
diff --git a/src/drv/cddxf.c b/src/drv/cddxf.c
new file mode 100644
index 0000000..b5c8854
--- /dev/null
+++ b/src/drv/cddxf.c
@@ -0,0 +1,1184 @@
+/** \file
+ * \brief DXF driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+#include "cd.h"
+#include "cd_private.h"
+#include "cddxf.h"
+
+
+#ifndef ignore
+#define ignore(x) (void)x
+#endif
+
+#ifndef max
+#define max(x, y) ((x > y)? x : y)
+#endif
+
+#ifndef min
+#define min(x, y) ((x < y)? x : y)
+#endif
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ FILE *file; /* pointer to file */
+ int layer; /* layer */
+
+ int tf; /* text font */
+ double th; /* text height (in points) */
+ int toa; /* text oblique angle (for italics) */
+ int tha, tva; /* text horizontal and vertical alignment */
+
+ int fgcolor; /* foreground AutoCAD palette color */
+
+ int lt; /* line type */
+ double lw; /* line width (in milimeters) */
+};
+
+
+static void wnamline (cdCtxCanvas* ctxcanvas, int t) /* write name of a line */
+{
+
+ static char *line[] =
+ {"CONTINUOUS",
+ "DASHED",
+ "HIDDEN",
+ "CENTER",
+ "PHANTOM",
+ "DOT",
+ "DASHDOT",
+ "BORDER",
+ "DIVIDE"};
+
+/*
+ AutoCAD line styles ( see acad.lin ):
+
+ 0 CONTINUOUS ____________________________________________
+ 1 DASHED __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
+ 2 HIDDEN _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+ 3 CENTER ____ _ ____ _ ____ _ ____ _ ____ _ ____ _ __
+ 4 PHANTOM _____ _ _ _____ _ _ _____ _ _ _____ _ _ ____
+ 5 DOT ............................................
+ 6 DASHDOT __ . __ . __ . __ . __ . __ . __ . __ . __ .
+ 7 BORDER __ __ . __ __ . __ __ . __ __ . __ __ . __ _
+ 8 DIVIDE __ . . __ . . __ . . __ . . __ . . __ . . __
+
+*/
+
+ fprintf (ctxcanvas->file, "%s\n", line[t]);
+}
+
+
+static void wnamfont (cdCtxCanvas *ctxcanvas, int t) /* write name of a font */
+{
+ static char *font[] =
+ {
+ "STANDARD",
+ "ROMAN",
+ "ROMAN_BOLD",
+ "ROMANTIC",
+ "ROMANTIC_BOLD",
+ "SANSSERIF",
+ "SANSSERIF_BOLD",
+ };
+/*
+ CD Fonts / Style AutoCAD Fonts
+ -------------------------------------------------------------------
+ CD_SYSTEM 0 STANDARD
+ CD_COURIER / CD_PLAIN 1 ROMAN
+ CD_COURIER / CD_BOLD 2 ROMAN_BOLD
+ CD_COURIER / CD_ITALIC 1 ROMAN (ctxcanvas->toa = 15)
+ CD_COURIER / CD_BOLD_ITALIC 2 ROMAN_BOLD (ctxcanvas->toa = 15)
+ CD_TIMES_ROMAN / CD_PLAIN 3 ROMANTIC
+ CD_TIMES_ROMAN / CD_BOLD 4 ROMANTIC_BOLD
+ CD_TIMES_ROMAN / CD_ITALIC 3 ROMANTIC (ctxcanvas->toa = 15)
+ CD_TIMES_ROMAN / CD_BOLD_ITALIC 4 ROMANTIC_BOLD (ctxcanvas->toa = 15)
+ CD_HELVETICA / CD_PLAIN 5 SANSSERIF
+ CD_HELVETICA / CD_BOLD 6 SANSSERIF_BOLD
+ CD_HELVETICA / CD_ITALIC 5 SANSSERIF (ctxcanvas->toa = 15)
+ CD_HELVETICA / CD_BOLD_ITALIC 6 SANSSERIF_BOLD(ctxcanvas->toa = 15)
+*/
+
+ fprintf (ctxcanvas->file, "%s\n", font[t]);
+}
+
+
+static void writepoly (cdCtxCanvas *ctxcanvas, cdPoint *poly, int nv) /* write polygon */
+{
+ int i;
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "POLYLINE\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+
+ fprintf ( ctxcanvas->file, "6\n" );
+ wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */
+
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor );
+ fprintf ( ctxcanvas->file, "66\n" );
+ fprintf ( ctxcanvas->file, "1\n" );
+ fprintf ( ctxcanvas->file, "40\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres );
+ for ( i=0; i<nv; i++ )
+ {
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "VERTEX\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "10\n" );
+ fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "20\n" );
+ fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres );
+ }
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "SEQEND\n" );
+}
+
+static void writepolyf (cdCtxCanvas *ctxcanvas, cdfPoint *poly, int nv) /* write polygon */
+{
+ int i;
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "POLYLINE\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+
+ fprintf ( ctxcanvas->file, "6\n" );
+ wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */
+
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor );
+ fprintf ( ctxcanvas->file, "66\n" );
+ fprintf ( ctxcanvas->file, "1\n" );
+ fprintf ( ctxcanvas->file, "40\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "41\n" ); /* entire polygon line width */
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw/ctxcanvas->canvas->xres );
+ for ( i=0; i<nv; i++ )
+ {
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "VERTEX\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "10\n" );
+ fprintf ( ctxcanvas->file, "%f\n", poly[i].x/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "20\n" );
+ fprintf ( ctxcanvas->file, "%f\n", poly[i].y/ctxcanvas->canvas->xres );
+ }
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "SEQEND\n" );
+}
+
+static void deflines (cdCtxCanvas *ctxcanvas) /* define lines */
+{
+ int i, j;
+ static char *line[] =
+ {"Solid line",
+ "Dashed line",
+ "Hidden line",
+ "Center line",
+ "Phantom line",
+ "Dot line",
+ "Dashdot line",
+ "Border line",
+ "Divide Line"};
+
+#define TABSIZE (sizeof(tab)/sizeof(tab[0]))
+
+ static int tab[][8] =
+ {
+ { 0, 0, 0 , 0, 0, 0, 0, 0 },
+ { 2, 15, 10, -5, 0, 0, 0, 0 },
+ { 2, 10, 5 , -5, 0, 0, 0, 0 },
+ { 4, 35, 20, -5, 5, -5, 0, 0 },
+ { 6, 50, 25, -5, 5, -5, 5, -5 },
+ { 2, 5, 0 , -5, 0, 0, 0, 0 },
+ { 4, 20, 10, -5, 0, -5, 0, 0 },
+ { 6, 35, 10, -5, 10, -5, 0, -5 },
+ { 6, 25, 10, -5, 0, -5, 0, -5 }
+ };
+
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "TABLE\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "LTYPE\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "5\n");
+ for (j = 0; j < TABSIZE; j++)
+ {
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "LTYPE\n");
+ fprintf (ctxcanvas->file, "2\n");
+
+ wnamline (ctxcanvas, j); /* line style */
+
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "64\n");
+ fprintf (ctxcanvas->file, "3\n");
+ fprintf (ctxcanvas->file, "%s\n", line[j]); /* line style */
+ fprintf (ctxcanvas->file, "72\n");
+ fprintf (ctxcanvas->file, "65\n");
+ fprintf (ctxcanvas->file, "73\n");
+ fprintf (ctxcanvas->file, "%d\n", tab[j][0]); /* number of parameters */
+ fprintf (ctxcanvas->file, "40\n");
+ fprintf (ctxcanvas->file, "%d\n", tab[j][1]);
+ for (i = 2; i < 2 + tab[j][0]; i++)
+ {
+ fprintf (ctxcanvas->file, "49\n");
+ fprintf (ctxcanvas->file, "%d\n", tab[j][i]); /* parameters */
+ }
+ }
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "ENDTAB\n");
+}
+
+
+static void deffonts (cdCtxCanvas *ctxcanvas) /* define fonts */
+{
+ int i;
+ static char *font[] =
+ {
+ "romanc.shx" ,
+ "romant.shx" ,
+ "rom_____.pfb",
+ "romb____.pfb",
+ "sas_____.pfb",
+ "sasb____.pfb"
+ };
+
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "TABLE\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "STYLE\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "5\n");
+ for (i = 1; i < 7; i++)
+ {
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "STYLE\n");
+ fprintf (ctxcanvas->file, "2\n");
+
+ wnamfont (ctxcanvas, i); /* font style name */
+
+ fprintf (ctxcanvas->file, "3\n");
+ fprintf (ctxcanvas->file, "%s\n", font[i-1]); /* font style file */
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "64\n");
+ fprintf (ctxcanvas->file, "71\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "40\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "41\n");
+ fprintf (ctxcanvas->file, "1\n");
+ fprintf (ctxcanvas->file, "42\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "50\n");
+ fprintf (ctxcanvas->file, "0\n");
+ }
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "ENDTAB\n");
+}
+
+static void cddeactivate (cdCtxCanvas *ctxcanvas)
+{
+ fflush (ctxcanvas->file); /* flush file */
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "ENDSEC\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "EOF\n"); /* fputs eof */
+ fprintf (ctxcanvas->file, " \n");
+
+ fflush (ctxcanvas->file); /* flush file */
+ fclose (ctxcanvas->file);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free (ctxcanvas);
+}
+
+static void cdflush (cdCtxCanvas *ctxcanvas)
+{
+ ctxcanvas->layer++;
+}
+
+/*==========================================================================*/
+/* Primitives */
+/*==========================================================================*/
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ if (mode == CD_CLOSED_LINES || mode == CD_FILL)
+ {
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+ }
+
+ writepoly (ctxcanvas, poly, n); /* write polygon */
+}
+
+static void cdline (cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ cdPoint line[2]; /* uses new array of points to avoid */
+
+ line[0].x = x1; /* starting point */
+ line[0].y = y1;
+ line[1].x = x2; /* ending point */
+ line[1].y = y2;
+ writepoly (ctxcanvas, line, 2); /* draw line as a polygon */
+}
+
+static void cdboxrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdPoint rect[5]; /* uses new array of points to avoid */
+
+ rect[0].x = xmin;
+ rect[0].y = ymin;
+ rect[1].x = xmin;
+ rect[1].y = ymax;
+ rect[2].x = xmax; /* box edges */
+ rect[2].y = ymax;
+ rect[3].x = xmax;
+ rect[3].y = ymin;
+ rect[4].x = xmin;
+ rect[4].y = ymin;
+ writepoly (ctxcanvas, rect, 5); /* draw box as a polygon */
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ if (mode == CD_CLOSED_LINES || mode == CD_FILL)
+ {
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+ }
+
+ writepolyf (ctxcanvas, poly, n); /* write polygon */
+}
+
+static void cdfline (cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ cdfPoint line[2]; /* uses new array of points to avoid */
+
+ line[0].x = x1; /* starting point */
+ line[0].y = y1;
+ line[1].x = x2; /* ending point */
+ line[1].y = y2;
+ writepolyf (ctxcanvas, line, 2); /* draw line as a polygon */
+}
+
+static void cdfboxrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ cdfPoint rect[5]; /* uses new array of points to avoid */
+
+ rect[0].x = xmin;
+ rect[0].y = ymin;
+ rect[1].x = xmin;
+ rect[1].y = ymax;
+ rect[2].x = xmax; /* box edges */
+ rect[2].y = ymax;
+ rect[3].x = xmax;
+ rect[3].y = ymin;
+ rect[4].x = xmin;
+ rect[4].y = ymin;
+ writepolyf (ctxcanvas, rect, 5); /* draw box as a polygon */
+}
+
+/*--------------------------------------------------------------------------*/
+/* gives radius of the circle most resembling elliptic arc at angle t */
+/*--------------------------------------------------------------------------*/
+static double calc_radius (double a, double b, double t)
+{
+ return (pow ((a*a*sin(t)*sin(t) + b*b*cos(t)*cos(t)), 1.5))/(a*b);
+}
+
+/*--------------------------------------------------------------------------*/
+/* calculates bulge for a given circular arc segment (between points p1 and */
+/* p2, with radius r). Bulge is the tangent of 1/4 the angle theta of the */
+/* arc segment(a bulge of 1 is a semicircle, which has an angle of 180 deg) */
+/*--------------------------------------------------------------------------*/
+static double calc_bulge (double a, double b, double t1, double t2)
+{
+ cdfPoint p1, p2; /* initial and ending arc points */
+ double r; /* radius most resembling arc at angle (t1+t2)/2 */
+ double theta; /* angle of circular arc segment */
+ double sin_theta; /* sine of theta */
+ double dist_x; /* distance between two points along the x axis */
+ double dist_y; /* distance between two points along the y axis */
+ double halfdist; /* half distance between two points */
+
+ p1.x = a*cos(t1);
+ p1.y = b*sin(t1);
+ p2.x = a*cos(t2);
+ p2.y = b*sin(t2);
+ r = calc_radius (a, b, (t1+t2)/2);
+
+ dist_x = p2.x - p1.x;
+ dist_y = p2.y - p1.y;
+ halfdist = (sqrt (dist_x*dist_x + dist_y*dist_y))/2;
+ sin_theta = halfdist/r;
+ if (sin_theta > 1) sin_theta = 1;
+ theta = 2*asin(sin_theta);
+
+ return tan(theta/4);
+}
+
+static void writevertex (cdCtxCanvas *ctxcanvas, int xc, int yc, double a, double b, double t, double bulge)
+{
+ cdfPoint p;
+ p.x = (xc + a*cos(t))/ctxcanvas->canvas->xres;
+ p.y = (yc + b*sin(t))/ctxcanvas->canvas->xres;
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "VERTEX\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "10\n" );
+ fprintf ( ctxcanvas->file, "%f\n", p.x );
+ fprintf ( ctxcanvas->file, "20\n" ); /* vertex coordinates */
+ fprintf ( ctxcanvas->file, "%f\n", p.y );
+ fprintf ( ctxcanvas->file, "42\n" ); /* bulge from this vertex */
+ fprintf ( ctxcanvas->file, "%f\n", bulge ); /* to the next one */
+}
+
+static void cdarc (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ double bulge; /* bulge is the tangent of 1/4 the angle for a given */
+ /* circle arc segment (a bulge of 1 is a semicircle) */
+ double t; /* current arc angle being calculated */
+ double t1; /* a1 in radians */
+ double t2; /* a2 in radians */
+ double a; /* half horizontal axis */
+ double b; /* half vertical axis */
+ double seg_angle; /* angle of every arc segment */
+ double diff; /* angle between a1 and a2 */
+ int nseg; /* number of arc segments */
+ int i;
+
+ a = w/2;
+ b = h/2;
+ t1 = a1*CD_DEG2RAD; /* a1 in radians */
+ t2 = a2*CD_DEG2RAD; /* a2 in radians */
+ diff = fabs(a2 - a1);
+ nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */
+ nseg = max(nseg, 1);
+ seg_angle = (t2-t1)/nseg;
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "POLYLINE\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "6\n" );
+ wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */
+ fprintf ( ctxcanvas->file, "66\n" );
+ fprintf ( ctxcanvas->file, "1\n" );
+ fprintf ( ctxcanvas->file, "70\n" );
+ fprintf ( ctxcanvas->file, "128\n" );
+ fprintf ( ctxcanvas->file, "40\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw );
+ fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw );
+
+ for (i=0, t=t1; i<nseg; i++, t+=seg_angle)
+ { /* calculate bulge between t */
+ bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */
+ writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */
+ }
+ writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "SEQEND\n" );
+}
+
+static void cdsector (cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ double bulge; /* bulge is the tangent of 1/4 the angle for a given */
+ /* circle arc segment (a bulge of 1 is a semicircle) */
+ double t; /* current arc angle being calculated */
+ double t1; /* a1 in radians */
+ double t2; /* a2 in radians */
+ double a; /* half horizontal axis */
+ double b; /* half vertical axis */
+ double seg_angle; /* angle of every arc segment */
+ double diff; /* angle between a1 and a2 */
+ int nseg; /* number of arc segments */
+ int i;
+
+ a = w/2;
+ b = h/2;
+ t1 = a1*CD_DEG2RAD; /* a1 in radians */
+ t2 = a2*CD_DEG2RAD; /* a2 in radians */
+ diff = fabs(a2 - a1);
+ nseg = cdRound(diff)/(360/32); /* 32 segments in closed ellipse */
+ nseg = max(nseg, 1);
+ seg_angle = (t2-t1)/nseg;
+
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "POLYLINE\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "6\n" );
+ wnamline( ctxcanvas, ctxcanvas->lt ); /* line type */
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->fgcolor ); /* color */
+ fprintf ( ctxcanvas->file, "66\n" );
+ fprintf ( ctxcanvas->file, "1\n" );
+ fprintf ( ctxcanvas->file, "70\n" );
+ fprintf ( ctxcanvas->file, "128\n" );
+ fprintf ( ctxcanvas->file, "40\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw );
+ fprintf ( ctxcanvas->file, "41\n" ); /* entire arc line width */
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->lw );
+
+ if ((a2-a1) != 360)
+ writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */
+ for (i=0, t=t1; i<nseg; i++, t+=seg_angle)
+ { /* calculate bulge between t */
+ bulge = calc_bulge (a, b, t, t+seg_angle); /* and t+seg_angle and write */
+ writevertex (ctxcanvas, xc, yc, a, b, t, bulge); /* vertex at t */
+ }
+ writevertex (ctxcanvas, xc, yc, a, b, t2, 0); /* bulge of last vertex is useless */
+ if ((a2-a1) != 360)
+ writevertex (ctxcanvas, xc, yc, 0, 0, 0, 0); /* center */
+
+ fprintf ( ctxcanvas->file, " 0\n" );
+ fprintf ( ctxcanvas->file, "SEQEND\n" );
+}
+
+static void cdtext (cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "TEXT\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "7\n" );
+ wnamfont( ctxcanvas, ctxcanvas->tf ); /* current font */
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */
+ fprintf ( ctxcanvas->file, "10\n" );
+ fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* current position */
+ fprintf ( ctxcanvas->file, "20\n" );
+ fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "11\n" );
+ fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* alignment point */
+ fprintf ( ctxcanvas->file, "21\n" );
+ fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres );
+ fprintf ( ctxcanvas->file, "40\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->th ); /* text height */
+ fprintf ( ctxcanvas->file, "50\n" );
+ fprintf ( ctxcanvas->file, "%f\n", ctxcanvas->canvas->text_orientation ); /* text orientation angle */
+ fprintf ( ctxcanvas->file, "51\n" );
+ fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->toa ); /* text oblique angle */
+ fprintf ( ctxcanvas->file, "72\n" );
+ fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tha ); /* text horizontal alignment */
+ fprintf ( ctxcanvas->file, "73\n" );
+ fprintf ( ctxcanvas->file, "%3d\n", ctxcanvas->tva ); /* text vertical alignment */
+ fprintf ( ctxcanvas->file, "1\n" );
+ fprintf ( ctxcanvas->file, "%s\n", s ); /* text */
+}
+
+
+/*==========================================================================*/
+/* Attributes */
+/*==========================================================================*/
+
+static int cdlinestyle (cdCtxCanvas *ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_CONTINUOUS:
+ ctxcanvas->lt = 0;
+ break;
+ case CD_DASHED:
+ ctxcanvas->lt = 1;
+ break;
+ case CD_DOTTED:
+ ctxcanvas->lt = 5;
+ break;
+ case CD_DASH_DOT:
+ ctxcanvas->lt = 6;
+ break;
+ case CD_DASH_DOT_DOT:
+ ctxcanvas->lt = 8;
+ break;
+ }
+
+ return style;
+}
+
+static int cdlinewidth (cdCtxCanvas *ctxcanvas, int width)
+{
+ ctxcanvas->lw = width/ctxcanvas->canvas->xres;
+ return width;
+}
+
+static int cdfont (cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ /* obs: DXF's text height (ctxcanvas->th) corresponds to CD ascent */
+
+ if (cdStrEqualNoCase(type_face, "System"))
+ {
+ ctxcanvas->tf = 0;
+ ctxcanvas->toa = 0;
+ ctxcanvas->th = 0.75;
+ }
+ else if (cdStrEqualNoCase(type_face, "Courier"))
+ {
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ ctxcanvas->tf = 1;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_BOLD:
+ ctxcanvas->tf = 2;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_ITALIC:
+ ctxcanvas->tf = 1;
+ ctxcanvas->toa = 15;
+ break;
+
+ case CD_BOLD_ITALIC:
+ ctxcanvas->tf = 2;
+ ctxcanvas->toa = 15;
+ break;
+ }
+ ctxcanvas->th = 0.75;
+ }
+ else if (cdStrEqualNoCase(type_face, "Times"))
+ {
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ ctxcanvas->tf = 3;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_BOLD:
+ ctxcanvas->tf = 4;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_ITALIC:
+ ctxcanvas->tf = 3;
+ ctxcanvas->toa = 15;
+ break;
+
+ case CD_BOLD_ITALIC:
+ ctxcanvas->tf = 4;
+ ctxcanvas->toa = 15;
+ break;
+ }
+ ctxcanvas->th = 1.125;
+ }
+ else if (cdStrEqualNoCase(type_face, "Helvetica"))
+ {
+ switch (style&3)
+ {
+ case CD_PLAIN:
+ ctxcanvas->tf = 5;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_BOLD:
+ ctxcanvas->tf = 6;
+ ctxcanvas->toa = 0;
+ break;
+
+ case CD_ITALIC:
+ ctxcanvas->tf = 5;
+ ctxcanvas->toa = 15;
+ break;
+
+ case CD_BOLD_ITALIC:
+ ctxcanvas->tf = 6;
+ ctxcanvas->toa = 15;
+ break;
+ }
+ ctxcanvas->th = 1.;
+ }
+ else
+ return 0;
+
+ ctxcanvas->th = ctxcanvas->th * cdGetFontSizePoints(ctxcanvas->canvas, size);
+
+ return 1;
+}
+
+static void cdgetfontdim (cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ double tangent_ta;
+ double pixel_th;
+
+ tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD);
+ pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */
+ switch (ctxcanvas->tf)
+ {
+ case 0: /* STANDARD font (CD_SYSTEM) */
+ if (height) *height = cdRound(pixel_th*4/3);
+ if (ascent) *ascent = _cdRound(pixel_th);
+ if (descent) *descent = cdRound(pixel_th/3);
+ if (max_width) *max_width = _cdRound(pixel_th);
+ break;
+
+ case 1: /* ROMAN fonts (CD_COURIER) */
+ case 2:
+ if (height) *height = cdRound(pixel_th*4/3);
+ if (ascent) *ascent = _cdRound(pixel_th);
+ if (descent) *descent = cdRound(pixel_th/3);
+ if (max_width) *max_width = cdRound((pixel_th*21/20) + tangent_ta*(*ascent));
+ break;
+
+ case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */
+ if (height) *height = cdRound(pixel_th*8/9);
+ if (ascent) *ascent = cdRound(pixel_th*2/3);
+ if (descent) *descent = cdRound(pixel_th*2/9);
+ if (max_width) *max_width = cdRound((pixel_th*14/15) + tangent_ta*(*ascent));
+ break;
+
+ case 4:
+ if (height) *height = cdRound(pixel_th*8/9);
+ if (ascent) *ascent = cdRound(pixel_th*2/3);
+ if (descent) *descent = cdRound(pixel_th*2/9);
+ if (max_width) *max_width = cdRound((pixel_th*29/30) + tangent_ta*(*ascent));
+ break;
+
+ case 5: /* SANSSERIF fonts (CD_HELVETICA) */
+ case 6:
+ if (height) *height = _cdRound(pixel_th);
+ if (ascent) *ascent = cdRound(pixel_th*3/4);
+ if (descent) *descent = cdRound(pixel_th/4);
+ if (max_width) *max_width = cdRound((pixel_th*15/16) + tangent_ta*(*ascent));
+ break;
+ }
+}
+
+static void cdgettextsize (cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height)
+{
+ int i;
+ double tangent_ta;
+ double pixel_th;
+
+ i = (int)strlen(s);
+ tangent_ta = tan(ctxcanvas->toa*CD_DEG2RAD);
+ pixel_th = (ctxcanvas->th*ctxcanvas->canvas->xres)/CD_MM2PT; /* points to pixels */
+
+ switch (ctxcanvas->tf) /* width return value based on maximum character width */
+ {
+ case 0: /* STANDARD font (CD_SYSTEM) */
+ if (height) *height = cdRound(pixel_th*4/3);
+ if (width) *width = cdRound(pixel_th*i + (pixel_th/3)*(i-1));
+ break;
+
+ case 1: /* ROMAN fonts (CD_COURIER) */
+ case 2:
+ if (height) *height = cdRound(pixel_th*4/3);
+ if (width) *width = cdRound((pixel_th*21/20)*i + (pixel_th/10)*(i-1) + tangent_ta*pixel_th);
+ break;
+
+ case 3: /* ROMANTIC fonts (CD_TIMES_ROMAN) */
+ if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9);
+ if (width) *width = cdRound((pixel_th*14/15)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*2/3);
+ break;
+
+ case 4:
+ if (height) *height = cdRound(pixel_th*2/3 + pixel_th*2/9);
+ if (width) *width = cdRound((pixel_th*29/30)*i + (pixel_th*2/45)*(i-1) + tangent_ta*pixel_th*2/3);
+ break;
+
+ case 5: /* SANSSERIF fonts (CD_HELVETICA) */
+ case 6:
+ if (height) *height = _cdRound(pixel_th);
+ if (width) *width = cdRound((pixel_th*15/16)*i + (pixel_th/45)*(i-1) + tangent_ta*pixel_th*3/4);
+ break;
+ }
+}
+
+static int cdtextalignment (cdCtxCanvas *ctxcanvas, int alignment)
+{
+ switch (alignment) /* convert alignment to DXF format */
+ {
+ case CD_BASE_LEFT:
+ ctxcanvas->tva = 0;
+ ctxcanvas->tha = 0;
+ break;
+
+ case CD_BASE_CENTER:
+ ctxcanvas->tva = 0;
+ ctxcanvas->tha = 1;
+ break;
+
+ case CD_BASE_RIGHT:
+ ctxcanvas->tva = 0;
+ ctxcanvas->tha = 2;
+ break;
+
+ case CD_SOUTH_WEST:
+ ctxcanvas->tva = 1;
+ ctxcanvas->tha = 0;
+ break;
+
+ case CD_SOUTH:
+ ctxcanvas->tva = 1;
+ ctxcanvas->tha = 1;
+ break;
+
+ case CD_SOUTH_EAST:
+ ctxcanvas->tva = 1;
+ ctxcanvas->tha = 2;
+ break;
+
+ case CD_WEST:
+ ctxcanvas->tva = 2;
+ ctxcanvas->tha = 0;
+ break;
+
+ case CD_CENTER:
+ ctxcanvas->tva = 2;
+ ctxcanvas->tha = 1;
+ break;
+
+ case CD_EAST:
+ ctxcanvas->tva = 2;
+ ctxcanvas->tha = 2;
+ break;
+
+ case CD_NORTH_WEST:
+ ctxcanvas->tva = 3;
+ ctxcanvas->tha = 0;
+ break;
+
+ case CD_NORTH:
+ ctxcanvas->tva = 3;
+ ctxcanvas->tha = 1;
+ break;
+
+ case CD_NORTH_EAST:
+ ctxcanvas->tva = 3;
+ ctxcanvas->tha = 2;
+ break;
+ }
+
+ return alignment;
+}
+
+/*==========================================================================*/
+/* Color */
+/*==========================================================================*/
+
+static void RGB_to_HSB (unsigned char r, unsigned char g, unsigned char b,
+ double *hue, double *sat, double *bright)
+{
+ double maximum;
+ double minimum;
+ double delta;
+ double red = r/255.; /* red, green and blue range from 0 to 1 */
+ double green = g/255.;
+ double blue = b/255.;
+
+ maximum = max(max(red, green), blue); /* stores higher index */
+ minimum = min(min(red, green), blue); /* stores lower index */
+ delta = maximum - minimum;
+
+ *bright = maximum*100;
+ *sat = 0;
+
+ if (maximum != 0) /* sat from 0 to 100 */
+ *sat = (delta*100)/maximum;
+
+ if (*sat != 0) /* hue from 0 to 359 */
+ {
+ if (red == maximum) *hue = (green - blue)/delta;
+ if (green == maximum) *hue = 2 + (blue - red)/delta;
+ if (blue == maximum) *hue = 4 + (red - green)/delta;
+ *hue *= 60;
+ if (*hue < 0) *hue += 360;
+ }
+ else
+ *hue = 0; /* color is greyscale (hue is meaningless) */
+}
+
+static int HSB_to_AutoCAD_Palette (double hue, double sat, double bright)
+{
+ int index;
+ int h, s, b;
+
+ if (bright < 17) /* 5 levels of brightness in AutoCAD palette, 6 with */
+ { /* black. If bright < 17, index is black (7). */
+ index = 7; /* 17 is 100/6 (rounded up) */
+ }
+ else if (sat < 10) /* low saturation makes color tend to */
+ { /* grey/white. 6 levels of grey/white in */
+ b = (int)floor(bright/14.3)-1;/* palette WITHOUT black. 14.3 is 100/7 */
+ index = 250 + b; /* index is grey to white(255 in palette) */
+ }
+ else
+ {
+ h = cdRound(hue/15.) + 1;
+ if (h > 24) h -= 24; /* 15 is 360/24 */
+ h *= 10; /* h ranges from 10 to 240 in palette */
+ s = (sat < 55) ? 1 : 0; /* s is 'high'(0) or 'low'(1) in palette */
+ b = (int)floor(bright/16.7)-1;/* b is 0, 2, 4, 6 or 8 in palette */
+ b = 2*(4 - b); /* (from brightest to dimmest) */
+ index = h + s + b; /* index is simple sum of h, s and b */
+ }
+ return index;
+}
+
+static int get_palette_index (long int color) /* gives closest palette */
+{ /* index to RGB color */
+ unsigned char red, green, blue;
+ double hue, sat, bright;
+
+ cdDecodeColor (color, &red, &green, &blue); /* AutoCAD palette is */
+ RGB_to_HSB (red, green, blue, &hue, &sat, &bright); /* based on HSB model */
+
+ return HSB_to_AutoCAD_Palette (hue, sat, bright);
+}
+
+static long int cdforeground (cdCtxCanvas *ctxcanvas, long int color)
+{
+ ctxcanvas->fgcolor = get_palette_index (color);
+ return color;
+}
+
+
+/*==========================================================================*/
+/* Server Images */
+/*==========================================================================*/
+
+static void cdpixel (cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ int oldcolor = ctxcanvas->fgcolor; /* put 'color' as current */
+ cdforeground (ctxcanvas, color); /* foreground color */
+ fprintf ( ctxcanvas->file, "0\n" );
+ fprintf ( ctxcanvas->file, "POINT\n" );
+ fprintf ( ctxcanvas->file, "8\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->layer); /* current layer */
+ fprintf ( ctxcanvas->file, "62\n" );
+ fprintf ( ctxcanvas->file, "%d\n", ctxcanvas->fgcolor ); /* color */
+ fprintf ( ctxcanvas->file, "10\n" );
+ fprintf ( ctxcanvas->file, "%f\n", x/ctxcanvas->canvas->xres ); /* position */
+ fprintf ( ctxcanvas->file, " 20\n" );
+ fprintf ( ctxcanvas->file, "%f\n", y/ctxcanvas->canvas->xres );
+ ctxcanvas->fgcolor = oldcolor; /* retrieve old fgcolor */
+}
+
+/******************************************************/
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char filename[10240] = "";
+ char* strdata = (char*)data;
+ cdCtxCanvas *ctxcanvas;
+ double param1, param2, param3;
+
+ ctxcanvas = (cdCtxCanvas *) malloc (sizeof (cdCtxCanvas));
+
+ param1 = 0;
+ param2 = 0;
+ param3 = 0;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata, "%lfx%lf %lf", &param1, &param2, &param3);
+
+ ctxcanvas->file = fopen (filename, "w");
+ if (ctxcanvas->file == NULL)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ if (!param1)
+ {
+ canvas->w_mm = INT_MAX*3.78;
+ canvas->h_mm = INT_MAX*3.78;
+ canvas->xres = 3.78;
+ }
+ else if (!param2)
+ {
+ canvas->w_mm = INT_MAX*param1;
+ canvas->h_mm = INT_MAX*param1;
+ canvas->xres = param1;
+ }
+ else if (!param3)
+ {
+ canvas->w_mm = param1;
+ canvas->h_mm = param2;
+ canvas->xres = 3.78;
+ }
+ else
+ {
+ canvas->w_mm = param1;
+ canvas->h_mm = param2;
+ canvas->xres = param3;
+ }
+
+ ctxcanvas->canvas = canvas;
+ canvas->ctxcanvas = ctxcanvas;
+
+ canvas->bpp = 8;
+
+ canvas->yres = canvas->xres;
+
+ canvas->w = (int)(canvas->w_mm * canvas->xres);
+ canvas->h = (int)(canvas->h_mm * canvas->yres);
+
+ ctxcanvas->layer = 0; /* reset layer */
+
+ ctxcanvas->tf = 0; /* text font (0 is STANDARD) */
+ ctxcanvas->th = 9; /* text height */
+ ctxcanvas->toa = 0; /* text oblique angle */
+ ctxcanvas->tva = 0; /* text vertical alignment (0 is baseline) */
+ ctxcanvas->tha = 0; /* text horizontal alignment (0 is left) */
+ ctxcanvas->fgcolor = 7; /* foreground AutoCAD palette color */
+
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "SECTION\n"); /* header maker */
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "HEADER\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$LIMCHECK\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "1\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$LIMMIN\n");
+ fprintf (ctxcanvas->file, "10\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "20\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$LIMMAX\n");
+ fprintf (ctxcanvas->file, "10\n");
+ fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm);
+ fprintf (ctxcanvas->file, "20\n");
+ fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm);
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$EXTMIN\n");
+ fprintf (ctxcanvas->file, "10\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "20\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$EXTMAX\n");
+ fprintf (ctxcanvas->file, "10\n");
+ fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->w_mm);
+ fprintf (ctxcanvas->file, "20\n");
+ fprintf (ctxcanvas->file, "%f\n", ctxcanvas->canvas->h_mm);
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$CLAYER\n");
+ fprintf (ctxcanvas->file, "8\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$LUNITS\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$LUPREC\n");
+ fprintf (ctxcanvas->file, "70\n"); /* precision (resolution dependant) */
+ fprintf (ctxcanvas->file, "%d\n", (int)ceil(log10(ctxcanvas->canvas->xres)));
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$AUNITS\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$AUPREC\n");
+ fprintf (ctxcanvas->file, "70\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "9\n");
+ fprintf (ctxcanvas->file, "$TEXTSTYLE\n");
+ fprintf (ctxcanvas->file, "7\n");
+ fprintf (ctxcanvas->file, "STANDARD\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "ENDSEC\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "SECTION\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "TABLES\n");
+
+ deflines (ctxcanvas); /* define lines */
+ deffonts (ctxcanvas); /* define fonts */
+
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "ENDSEC\n");
+ fprintf (ctxcanvas->file, "0\n");
+ fprintf (ctxcanvas->file, "SECTION\n");
+ fprintf (ctxcanvas->file, "2\n");
+ fprintf (ctxcanvas->file, "ENTITIES\n");
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxPixel = cdpixel;
+ canvas->cxLine = cdline;
+ canvas->cxPoly = cdpoly;
+ canvas->cxRect = cdboxrect;
+ canvas->cxBox = cdboxrect;
+ canvas->cxFLine = cdfline;
+ canvas->cxFPoly = cdfpoly;
+ canvas->cxFRect = cdfboxrect;
+ canvas->cxFBox = cdfboxrect;
+ canvas->cxArc = cdarc;
+ canvas->cxSector = cdsector;
+ canvas->cxText = cdtext;
+ canvas->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxFont = cdfont;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxForeground = cdforeground;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+/******************************************************/
+
+static cdContext cdDXFContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE |
+ CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION | CD_CAP_CHORD |
+ CD_CAP_IMAGERGB | CD_CAP_IMAGEMAP | CD_CAP_IMAGESRV |
+ CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE |
+ CD_CAP_HATCH | CD_CAP_STIPPLE | CD_CAP_PATTERN |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextDXF(void)
+{
+ return &cdDXFContext;
+}
+
diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c
new file mode 100644
index 0000000..9fbb540
--- /dev/null
+++ b/src/drv/cdirgb.c
@@ -0,0 +1,2135 @@
+/** \file
+ * \brief Image RGB Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cd_truetype.h"
+#include "sim.h"
+#include "cdirgb.h"
+
+
+struct _cdCtxImage
+{
+ int w, h;
+ unsigned char* red; /* red color buffer */
+ unsigned char* green; /* green color buffer */
+ unsigned char* blue; /* blue color buffer */
+ unsigned char* alpha; /* alpha color buffer */
+};
+
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ int user_image; /* can not free an user image */
+
+ unsigned char* red; /* red color buffer */
+ unsigned char* green; /* green color buffer */
+ unsigned char* blue; /* blue color buffer */
+ unsigned char* alpha; /* alpha color buffer */
+ unsigned char* clip; /* clipping buffer */
+
+ unsigned char* clip_region; /* clipping region used during NewRegion */
+
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ cdCanvas* canvas_dbuffer; /* used by the CD_DBUFFERRGB driver */
+};
+
+/*******************/
+/* Local functions */
+/*******************/
+
+#define _sNormX(_ctxcanvas, _x) (_x < 0? 0: _x < _ctxcanvas->canvas->w? _x: _ctxcanvas->canvas->w-1)
+#define _sNormY(_ctxcanvas, _y) (_y < 0? 0: _y < _ctxcanvas->canvas->h? _y: _ctxcanvas->canvas->h-1)
+
+#define RGBA_COMPOSE(_SRC, _SRC_ALPHA, _DST, _TMP_MULTI, _TMP_ALPHA) (unsigned char)(((_SRC_ALPHA)*(_SRC) + (_TMP_MULTI)*(_DST)) / (_TMP_ALPHA))
+
+#define RGBA_COLOR_COMBINE(_ctxcanvas, _pdst_red, _pdst_green, _pdst_blue, _pdst_alpha, _src_red, _src_green, _src_blue, _src_alpha) \
+{ \
+ unsigned char _tmp_red = 0, _tmp_green = 0, _tmp_blue = 0; \
+ \
+ if (_pdst_alpha) /* (_pdst_alpha != NULL) */ \
+ { \
+ if (_src_alpha != 255) /* some transparency */ \
+ { \
+ if (_src_alpha != 0) /* source not full transparent */ \
+ { \
+ if (*_pdst_alpha == 0) /* destiny full transparent */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ *_pdst_alpha = _src_alpha; \
+ } \
+ else if (*_pdst_alpha == 255) /* destiny opaque */ \
+ { \
+ _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \
+ _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \
+ _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \
+ /* *_pdst_alpha is not changed */ \
+ } \
+ else /* (0<*_pdst_alpha<255 && 0<_src_alpha<255) destiny and source are semi-transparent */ \
+ { \
+ /* Closed Compositing Formulas for SRC over DST, Colors Not Premultiplied by Alpha: */ \
+ int _tmp_multi = *_pdst_alpha * (255 - _src_alpha); \
+ int _tmp_alpha = _src_alpha + _tmp_multi; \
+ _tmp_red = RGBA_COMPOSE(_src_red, _src_alpha, *_pdst_red, _tmp_multi, _tmp_alpha); \
+ _tmp_green = RGBA_COMPOSE(_src_green, _src_alpha, *_pdst_green, _tmp_multi, _tmp_alpha); \
+ _tmp_blue = RGBA_COMPOSE(_src_blue, _src_alpha, *_pdst_blue, _tmp_multi, _tmp_alpha); \
+ *_pdst_alpha = (unsigned char)(_tmp_alpha / 255); \
+ } \
+ } \
+ else /* (_src_alpha == 0) source full transparent */ \
+ { \
+ _tmp_red = *_pdst_red; \
+ _tmp_green = *_pdst_green; \
+ _tmp_blue = *_pdst_blue; \
+ /* *_pdst_alpha is not changed */ \
+ } \
+ } \
+ else /* (_src_alpha == 255) source has no alpha = opaque */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ *_pdst_alpha = (unsigned char)255; /* set destiny as opaque */ \
+ } \
+ } \
+ else /* (_pdst_alpha == NULL) */ \
+ { \
+ if (_src_alpha != 255) /* source has some transparency */ \
+ { \
+ if (_src_alpha != 0) /* source semi-transparent */ \
+ { \
+ _tmp_red = CD_ALPHA_BLEND(_src_red, *_pdst_red, _src_alpha); \
+ _tmp_green = CD_ALPHA_BLEND(_src_green, *_pdst_green, _src_alpha); \
+ _tmp_blue = CD_ALPHA_BLEND(_src_blue, *_pdst_blue, _src_alpha); \
+ } \
+ else /* (_src_alpha == 0) source full transparent */ \
+ { \
+ _tmp_red = *_pdst_red; \
+ _tmp_green = *_pdst_green; \
+ _tmp_blue = *_pdst_blue; \
+ } \
+ } \
+ else /* (_src_alpha == 255) source has no alpha = opaque */ \
+ { \
+ _tmp_red = _src_red; \
+ _tmp_green = _src_green; \
+ _tmp_blue = _src_blue; \
+ } \
+ } \
+ \
+ switch (_ctxcanvas->canvas->write_mode) \
+ { \
+ case CD_REPLACE: \
+ *_pdst_red = _tmp_red; \
+ *_pdst_green = _tmp_green; \
+ *_pdst_blue = _tmp_blue; \
+ break; \
+ case CD_XOR: \
+ *_pdst_red ^= _tmp_red; \
+ *_pdst_green ^= _tmp_green; \
+ *_pdst_blue ^= _tmp_blue; \
+ break; \
+ case CD_NOT_XOR: \
+ *_pdst_red = (unsigned char)~(_tmp_red ^ *_pdst_red); \
+ *_pdst_green = (unsigned char)~(_tmp_green ^ *_pdst_green); \
+ *_pdst_blue = (unsigned char)~(_tmp_blue ^ *_pdst_blue); \
+ break; \
+ } \
+}
+
+static void sCombineRGBColor(cdCtxCanvas* ctxcanvas, int offset, long color)
+{
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ unsigned char sr = cdRed(color);
+ unsigned char sg = cdGreen(color);
+ unsigned char sb = cdBlue(color);
+ unsigned char sa = cdAlpha(color);
+
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa);
+}
+
+static void sCombineRGB(cdCtxCanvas* ctxcanvas, int offset, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa)
+{
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, sr, sg, sb, sa);
+}
+
+static void sCombineRGBLine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, int size)
+{
+ int c;
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+ unsigned char src_a = 255;
+
+ if (size > 0)
+ {
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a);
+ dr++; dg++; db++; clip++;
+ sr++; sg++; sb++;
+ if (da) da++;
+ }
+ }
+ else
+ {
+ size *= -1;
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, src_a);
+ dr--; dg--; db--; clip--;
+ sr--; sg--; sb--;
+ if (da) da--;
+ }
+ }
+}
+
+static void sCombineRGBALine(cdCtxCanvas* ctxcanvas, int offset, const unsigned char *sr, const unsigned char *sg, const unsigned char *sb, const unsigned char *sa, int size)
+{
+ int c;
+ unsigned char *dr = ctxcanvas->red + offset;
+ unsigned char *dg = ctxcanvas->green + offset;
+ unsigned char *db = ctxcanvas->blue + offset;
+ unsigned char *da = ctxcanvas->alpha? ctxcanvas->alpha + offset: NULL;
+ unsigned char *clip = ctxcanvas->clip + offset;
+
+ if (size > 0)
+ {
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa);
+ dr++; dg++; db++; clip++;
+ sr++; sg++; sb++; sa++;
+ if (da) da++;
+ }
+ }
+ else
+ {
+ size *= -1;
+ for (c = 0; c < size; c++)
+ {
+ if (*clip)
+ RGBA_COLOR_COMBINE(ctxcanvas, dr, dg, db, da, *sr, *sg, *sb, *sa);
+ dr--; dg--; db--; clip--;
+ sr--; sg--; sb--; sa--;
+ if (da) da--;
+ }
+ }
+}
+
+static void irgbSolidLine(cdCanvas* canvas, int xmin, int y, int xmax)
+{
+ int x;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0)
+ return;
+
+ if (y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ for (x = xmin; x <= xmax; x++)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+}
+
+static void irgbPatternLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const long *pattern)
+{
+ int x, i;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ i = xmin % pw;
+
+ for (x = xmin; x <= xmax; x++,i++)
+ {
+ if (i == pw)
+ i = 0;
+
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, pattern[i]);
+ }
+}
+
+static void irgbStippleLine(cdCanvas* canvas, int xmin, int xmax, int y, int pw, const unsigned char *stipple)
+{
+ int x,i;
+ unsigned long offset = y * canvas->w;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ i = xmin % pw;
+
+ for (x = xmin; x <= xmax; x++,i++)
+ {
+ if (i == pw)
+ i = 0;
+ if(stipple[i])
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+ else if (canvas->back_opacity == CD_OPAQUE)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background);
+ }
+}
+
+static void irgbHatchLine(cdCanvas* canvas, int xmin, int xmax, int y, unsigned char hatch)
+{
+ int x;
+ unsigned long offset = y * canvas->w;
+ unsigned char n;
+
+ if (y < 0 || y > (canvas->h-1))
+ return;
+
+ if (xmin < 0) /* Arruma limites de acordo com o retangulo de clip */
+ xmin = 0; /* so clipa em x */
+ if (xmax > (canvas->w-1))
+ xmax = (canvas->w-1);
+
+ n = (unsigned char)(xmin&7);
+ simRotateHatchN(hatch, n);
+
+ for (x = xmin; x <= xmax; x++)
+ {
+ if (hatch & 0x80)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->foreground);
+ else if (canvas->back_opacity == CD_OPAQUE)
+ sCombineRGBColor(canvas->ctxcanvas, offset + x, canvas->background);
+
+ _cdRotateHatch(hatch);
+ }
+}
+
+/********************/
+/* driver functions */
+/********************/
+
+static void cdkillcanvas(cdCtxCanvas* ctxcanvas)
+{
+ if (!ctxcanvas->user_image)
+ free(ctxcanvas->red);
+
+ if (ctxcanvas->clip_region)
+ free(ctxcanvas->clip_region);
+
+ free(ctxcanvas->clip);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+unsigned char* cdAlphaImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->alpha;
+}
+
+unsigned char* cdRedImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->red;
+}
+
+unsigned char* cdGreenImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->green;
+}
+
+unsigned char* cdBlueImage(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas;
+ assert(canvas);
+ ctxcanvas = (cdCtxCanvas*)canvas->ctxcanvas;
+ return ctxcanvas->blue;
+}
+
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ int size = ctxcanvas->canvas->w * ctxcanvas->canvas->h;
+ memset(ctxcanvas->red, cdRed(ctxcanvas->canvas->background), size);
+ memset(ctxcanvas->green, cdGreen(ctxcanvas->canvas->background), size);
+ memset(ctxcanvas->blue, cdBlue(ctxcanvas->canvas->background), size);
+ if (ctxcanvas->alpha) memset(ctxcanvas->alpha, cdAlpha(ctxcanvas->canvas->background), size);
+}
+
+static void irgPostProcessIntersect(unsigned char* clip, int size)
+{
+ int i;
+ for(i = 0; i < size; i++)
+ {
+ if (*clip == 2)
+ *clip = 1;
+ else
+ *clip = 0;
+
+ clip++;
+ }
+}
+
+#define _irgSetClipPixel(_clip, _combine_mode) \
+{ \
+ switch (_combine_mode) \
+ { \
+ case CD_INTERSECT: \
+ if (_clip) \
+ _clip = 2; /* fills the intersection \
+ with a value to be post-processed */ \
+ break; \
+ case CD_DIFFERENCE: \
+ if (_clip) \
+ _clip = 0; /* clears the intersection */ \
+ break; \
+ case CD_NOTINTERSECT: /* XOR */ \
+ if (_clip) \
+ _clip = 0; /* clears the intersection */ \
+ else \
+ _clip = 1; /* fills the region */ \
+ break; \
+ default: /* CD_UNION */ \
+ _clip = 1; /* fills the region */ \
+ break; \
+ } \
+}
+
+static void irgbClipTextBitmap(FT_Bitmap* bitmap, int x, int y, int w, unsigned char* clip, int combine_mode)
+{
+ unsigned char *bitmap_data;
+ int width = bitmap->width;
+ int height = bitmap->rows;
+ int i, j;
+
+ /* avoid spaces */
+ if (width == 0 || height == 0)
+ return;
+
+ bitmap_data = bitmap->buffer + (height-1)*width; /* bitmap is top down. */
+
+ clip += y * w + x;
+
+ for (i = 0; i < height; i++)
+ {
+ for (j = 0; j < width; j++)
+ {
+ if (bitmap_data[j] == 255)
+ _irgSetClipPixel(clip[j], combine_mode);
+ }
+ clip += w;
+ bitmap_data -= width;
+ }
+}
+
+static void irgbClipText(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ cdCanvas* canvas = ctxcanvas->canvas;
+ cdSimulation* simulation = canvas->simulation;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ FT_Matrix matrix; /* transformation matrix */
+ FT_Vector pen; /* untransformed origin */
+ FT_Error error;
+
+ if (!simulation->tt_text->face)
+ return;
+
+ face = simulation->tt_text->face;
+ slot = face->glyph;
+
+ /* move the reference point to the baseline-left */
+ simGetPenPos(simulation->canvas, x, y, s, &matrix, &pen);
+
+ while(*s)
+ {
+ /* set transformation */
+ FT_Set_Transform(face, &matrix, &pen);
+
+ /* load glyph image into the slot (erase previous one) */
+ error = FT_Load_Char(face, *(unsigned char*)s, FT_LOAD_RENDER);
+ if (error) {s++; continue;} /* ignore errors */
+
+ x = slot->bitmap_left;
+ y = slot->bitmap_top-slot->bitmap.rows; /* CD image reference point is at bottom-left */
+
+ /* now, draw to our target surface (convert position) */
+ irgbClipTextBitmap(&slot->bitmap, x, y, canvas->w, ctxcanvas->clip_region, canvas->combine_mode);
+
+ /* increment pen position */
+ pen.x += slot->advance.x;
+ pen.y += slot->advance.y;
+
+ s++;
+ }
+
+ if (canvas->combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipFillLine(unsigned char* clip_line, int combine_mode, int x1, int x2, int width)
+{
+ int x;
+ if (x1 < 0) x1 = 0;
+ if (x2 > width-1) x2 = width-1;
+ for (x = x1; x <= x2; x++)
+ {
+ _irgSetClipPixel(clip_line[x], combine_mode);
+ }
+}
+
+static int compare_int(const int* xx1, const int* xx2)
+{
+ return *xx1 - *xx2;
+}
+
+static void irgbClipPoly(cdCtxCanvas* ctxcanvas, unsigned char* clip_region, cdPoint* poly, int n, int combine_mode)
+{
+ cdCanvas* canvas = ctxcanvas->canvas;
+ unsigned char* clip_line;
+ simLineSegment *seg_i;
+ cdPoint* t_poly = NULL;
+ int y_max, y_min, i, y, i1, fill_mode, num_lines,
+ inter_count, width, height;
+
+ int *xx = (int*)malloc((n+1)*sizeof(int));
+ simLineSegment *segment = (simLineSegment *)malloc(n*sizeof(simLineSegment));
+
+ if (canvas->use_matrix)
+ {
+ t_poly = malloc(sizeof(cdPoint)*n);
+ memcpy(t_poly, poly, sizeof(cdPoint)*n);
+ poly = t_poly;
+
+ for(i = 0; i < n; i++)
+ cdMatrixTransformPoint(canvas->matrix, poly[i].x, poly[i].y, &poly[i].x, &poly[i].y);
+ }
+
+ width = canvas->w;
+ height = canvas->h;
+ fill_mode = canvas->fill_mode;
+
+ y_max = poly[0].y;
+ y_min = poly[0].y;
+ for(i = 0; i < n; i++)
+ {
+ i1 = (i+1)%n; /* next point(i+1), next of last(n-1) is first(0) */
+ simAddSegment(segment+i, poly[i].x, poly[i].y, poly[i1].x, poly[i1].y, &y_max, &y_min);
+ }
+
+ if (y_min < 0)
+ y_min = 0;
+
+ if (y_max > height-1)
+ num_lines = height-y_min;
+ else
+ num_lines = y_max-y_min+1;
+
+ /* for all horizontal lines between y_max and y_min */
+ for(y = y_max; y >= y_min; y--)
+ {
+ inter_count = 0;
+
+ /* for all segments, calculates the intervals to be filled. */
+ for(i = 0; i < n; i++)
+ {
+ seg_i = segment + i;
+
+ /* if the minimum Y coordinate of the segment is greater than the current y, then ignore the segment. */
+ /* if it is an horizontal line, then ignore the segment. */
+ if (seg_i->y1 > y ||
+ seg_i->y1 == seg_i->y2)
+ continue;
+
+ if (y == seg_i->y1) /* intersection at the start point (x1,y1) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* always save at least one intersection point for (y1) */
+
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+
+ /* check for missing bottom-corner points (|_|), must duplicate the intersection */
+ if ((seg_i_next->y1 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y1 == y && seg_i_prev->y2 == seg_i_prev->y1)) /* previous is an horizontal line */
+ {
+ xx[inter_count++] = seg_i->x1; /* save the intersection point */
+ }
+ }
+ else if ((y > seg_i->y1) && (y < seg_i->y2)) /* intersection inside the segment, do not include y2 */
+ {
+ xx[inter_count++] = simSegmentInc(seg_i, canvas, y); /* save the intersection point */
+ }
+ else if (y == seg_i->y2) /* intersection at the end point (x2,y2) */
+ {
+ int i_next = (i==n-1)? 0: i+1;
+ int i_prev = (i==0)? n-1: i-1;
+ simLineSegment *seg_i_next = segment + i_next;
+ simLineSegment *seg_i_prev = segment + i_prev;
+
+ /* only save the intersection point for (y2) if not handled by (y1) of another segment */
+
+ /* check for missing top-corner points (^) or (|¯¯|) */
+ if ((seg_i_next->y2 == y && seg_i_next->y2 == seg_i_next->y1) || /* next is an horizontal line */
+ (seg_i_prev->y2 == y && seg_i_prev->y2 == seg_i_prev->y1) || /* previous is an horizontal line */
+ (seg_i_next->y2 == y && seg_i_next->x2 == seg_i->x2 && seg_i_next->x1 != seg_i->x1) ||
+ (seg_i_prev->y2 == y && seg_i_prev->x2 == seg_i->x2 && seg_i_prev->x1 != seg_i->x1))
+ {
+ xx[inter_count++] = seg_i->x2; /* save the intersection point */
+ }
+ }
+ }
+
+ /* if outside the canvas, ignore the intervals and */
+ /* continue since the segments where updated. */
+ if (y > height-1 || inter_count == 0)
+ continue;
+
+ /* sort the intervals */
+ qsort(xx, inter_count, sizeof(int), (int (*)(const void*,const void*))compare_int);
+
+ clip_line = clip_region + y*width;
+
+ /* for all intervals, fill the interval */
+ for(i = 0; i < inter_count; i += 2)
+ {
+ if (fill_mode == CD_EVENODD)
+ {
+ /* since it fills only pairs of intervals, */
+ /* it is the EVENODD fill rule. */
+ irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width);
+ }
+ else
+ {
+ irgbClipFillLine(clip_line, combine_mode, xx[i], xx[i+1], width);
+ if ((i+2 < inter_count) && (xx[i+1] < xx[i+2])) /* avoid point intervals */
+ if (simIsPointInPolyWind(poly, n, (xx[i+1]+xx[i+2])/2, y)) /* if the next interval is inside the polygon then fill it */
+ irgbClipFillLine(clip_line, combine_mode, xx[i+1], xx[i+2], width);
+ }
+ }
+ }
+
+ if (t_poly) free(t_poly);
+ free(xx);
+ free(segment);
+
+ if (combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipElipse(cdCtxCanvas* ctxcanvas, int xc, int yc, int width, int height, double angle1, double angle2, int sector)
+{
+ float c, s, sx, sy, x, y, prev_x, prev_y;
+ double da;
+ int i, p;
+ cdPoint* poly;
+
+ /* number of segments of equivalent poligonal for a full ellipse */
+ int n = simCalcEllipseNumSegments(ctxcanvas->canvas, xc, yc, width, height);
+
+ /* number of segments for the arc */
+ n = cdRound((fabs(angle2-angle1)*n)/360);
+ if (n < 1) n = 1;
+
+ poly = (cdPoint*)malloc(sizeof(cdPoint)*(n+2+1)); /* n+1 points +1 center */
+
+ /* converts degrees into radians */
+ angle1 *= CD_DEG2RAD;
+ angle2 *= CD_DEG2RAD;
+
+ /* generates arc points at origin with axis x and y */
+
+ da = (angle2-angle1)/n;
+ c = (float)cos(da);
+ s = (float)sin(da);
+ sx = -(width*s)/height;
+ sy = (height*s)/width;
+
+ x = xc + (width/2.0f)*(float)cos(angle1);
+ y = yc + (height/2.0f)*(float)sin(angle1);
+ poly[0].x = _cdRound(x);
+ poly[0].y = _cdRound(y);
+ prev_x = x;
+ prev_y = y;
+ p = 1;
+
+ for (i = 1; i < n+1; i++) /* n+1 points */
+ {
+ x = xc + c*(prev_x-xc) + sx*(prev_y-yc);
+ y = yc + sy*(prev_x-xc) + c*(prev_y-yc);
+
+ poly[p].x = _cdRound(x);
+ poly[p].y = _cdRound(y);
+
+ if (poly[p-1].x != poly[p].x || poly[p-1].y != poly[p].y)
+ p++;
+
+ prev_x = x;
+ prev_y = y;
+ }
+
+ if (poly[p-1].x != poly[0].x || poly[p-1].y != poly[0].y)
+ {
+ if (sector) /* cdSector */
+ {
+ /* add center */
+ poly[p].x = xc;
+ poly[p].y = yc;
+ }
+ else /* cdChord */
+ {
+ /* add initial point */
+ poly[p].x = poly[0].x;
+ poly[p].y = poly[0].y;
+ }
+ p++;
+ }
+
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, p, ctxcanvas->canvas->combine_mode);
+
+ free(poly);
+}
+
+static void irgbClipBox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ int combine_mode = ctxcanvas->canvas->combine_mode;
+ unsigned char* clip_line;
+ int x, y, width;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdPoint poly[4];
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, 4, ctxcanvas->canvas->combine_mode);
+ return;
+ }
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+ width = ctxcanvas->canvas->w;
+
+ for(y = ymin; y <= ymax; y++)
+ {
+ clip_line = ctxcanvas->clip_region + y*width;
+ for(x = xmin; x <= xmax; x++)
+ {
+ _irgSetClipPixel(clip_line[x], combine_mode);
+ }
+ }
+
+ if (combine_mode == CD_INTERSECT)
+ irgPostProcessIntersect(ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static void irgbClipArea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ unsigned char* clip_line = ctxcanvas->clip; /* set directly to clip */
+ int y, xsize, ysize, height, width, xrigth;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdPoint poly[4];
+ poly[0].x = xmin; poly[0].y = ymin;
+ poly[1].x = xmin; poly[1].y = ymax;
+ poly[2].x = xmax; poly[2].y = ymax;
+ poly[3].x = xmax; poly[3].y = ymin;
+ memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, 4, CD_UNION);
+ return;
+ }
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+ xsize = xmax-xmin+1;
+ ysize = ymax-ymin+1;
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+ xrigth = width-(xmax+1);
+
+ for(y = 0; y < ymin; y++)
+ {
+ memset(clip_line, 0, width);
+ clip_line += width;
+ }
+
+ for(y = ymin; y <= ymax; y++)
+ {
+ if (xmin)
+ memset(clip_line, 0, xmin);
+
+ memset(clip_line+xmin, 1, xsize);
+
+ if (xrigth)
+ memset(clip_line+xmax+1, 0, xrigth);
+
+ clip_line += width;
+ }
+
+ for(y = ymax+1; y < height; y++)
+ {
+ memset(clip_line, 0, width);
+ clip_line += width;
+ }
+}
+
+static int cdclip(cdCtxCanvas* ctxcanvas, int mode)
+{
+ switch(mode)
+ {
+ case CD_CLIPAREA:
+ irgbClipArea(ctxcanvas, ctxcanvas->canvas->clip_rect.xmin,
+ ctxcanvas->canvas->clip_rect.xmax,
+ ctxcanvas->canvas->clip_rect.ymin,
+ ctxcanvas->canvas->clip_rect.ymax);
+ break;
+ case CD_CLIPPOLYGON:
+ memset(ctxcanvas->clip, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, ctxcanvas->canvas->clip_poly, ctxcanvas->canvas->clip_poly_n, CD_UNION);
+ break;
+ case CD_CLIPREGION:
+ if (ctxcanvas->clip_region)
+ memcpy(ctxcanvas->clip, ctxcanvas->clip_region, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ break;
+ default:
+ memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */
+ break;
+ }
+
+ return mode;
+}
+
+static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ irgbClipArea(ctxcanvas, xmin, xmax, ymin, ymax);
+}
+
+static void cdnewregion(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->clip_region)
+ free(ctxcanvas->clip_region);
+ ctxcanvas->clip_region = malloc(ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+ memset(ctxcanvas->clip_region, 0, ctxcanvas->canvas->w * ctxcanvas->canvas->h);
+}
+
+static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->clip_region)
+ return 0;
+
+ if (x >= 0 && y >= 0 && x < ctxcanvas->canvas->w && y < ctxcanvas->canvas->h)
+ {
+ if (ctxcanvas->clip_region[y*ctxcanvas->canvas->w + x])
+ return 1;
+ }
+
+ return 0;
+}
+
+static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int dx, int dy)
+{
+ unsigned char* clip_region = ctxcanvas->clip_region;
+ int x, y, X, Y, old_X, old_Y, width, height;
+
+ if (!ctxcanvas->clip_region)
+ return;
+
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+
+ for (y = 0; y < height; y++)
+ {
+ if (dy > 0)
+ Y = height-1 - y;
+ else
+ Y = y;
+ old_Y = Y - dy;
+ for(x = 0; x < width; x++)
+ {
+ if (dx > 0)
+ X = width-1 - x;
+ else
+ X = x;
+ old_X = X - dx;
+
+ if (old_X >= 0 && old_Y >= 0 && old_Y < height && old_X < width)
+ clip_region[Y*width + X] = clip_region[old_Y*width + old_X];
+ else
+ clip_region[Y*width + X] = 0;
+ }
+ }
+}
+
+static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ unsigned char* clip_line = ctxcanvas->clip_region;
+ int x, y, width, height;
+
+ if (!ctxcanvas->clip_region)
+ return;
+
+ *xmin = ctxcanvas->canvas->w-1;
+ *xmax = 0;
+ *ymin = ctxcanvas->canvas->h-1;
+ *ymax = 0;
+ height = ctxcanvas->canvas->h;
+ width = ctxcanvas->canvas->w;
+
+ for (y = 0; y < height; y++)
+ {
+ for(x = 0; x < width; x++)
+ {
+ if (*clip_line)
+ {
+ if (x < *xmin)
+ *xmin = x;
+ if (y < *ymin)
+ *ymin = y;
+ if (x > *xmax)
+ *xmax = x;
+ if (y > *ymax)
+ *ymax = y;
+ }
+
+ clip_line++;
+ }
+ }
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipBox(ctxcanvas, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ cdboxSIM(ctxcanvas, xmin, xmax, ymin, ymax);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 1);
+ return;
+ }
+
+ cdsectorSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipElipse(ctxcanvas, xc, yc, w, h, a1, a2, 0);
+ return;
+ }
+
+ cdchordSIM(ctxcanvas, xc, yc, w, h, a1, a2);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipText(ctxcanvas, x, y, s);
+ return;
+ }
+
+ cdtextSIM(ctxcanvas, x, y, s);
+}
+
+static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ if (ctxcanvas->canvas->new_region)
+ {
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip_region, poly, n, ctxcanvas->canvas->combine_mode);
+ return;
+ }
+
+ if (mode == CD_CLIP)
+ {
+ /* set directly to clip */
+ memset(ctxcanvas->clip, 1, ctxcanvas->canvas->w * ctxcanvas->canvas->h); /* CD_CLIPOFF */
+ irgbClipPoly(ctxcanvas, ctxcanvas->clip, poly, n, CD_UNION);
+ }
+ else
+ cdpolySIM(ctxcanvas, mode, poly, n);
+}
+
+static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h)
+{
+ int dst_offset, src_offset, l, xsize, ysize, xpos, ypos;
+ unsigned char *src_red, *src_green, *src_blue;
+
+ if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ /* ajusta parametros de entrada */
+ xpos = _sNormX(ctxcanvas, x);
+ ypos = _sNormY(ctxcanvas, y);
+
+ xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos;
+ ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos;
+
+ /* ajusta posicao inicial em source */
+ src_offset = xpos + ypos * ctxcanvas->canvas->w;
+ src_red = ctxcanvas->red + src_offset;
+ src_green = ctxcanvas->green + src_offset;
+ src_blue = ctxcanvas->blue + src_offset;
+
+ /* offset para source */
+ src_offset = ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = (xpos - x) + (ypos - y) * w;
+ r += dst_offset;
+ g += dst_offset;
+ b += dst_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ memcpy(r, src_red, xsize);
+ memcpy(g, src_green, xsize);
+ memcpy(b, src_blue, xsize);
+
+ src_red += src_offset;
+ src_green += src_offset;
+ src_blue += src_offset;
+
+ r += w;
+ g += w;
+ b += w;
+ }
+}
+
+static void cdputimagerectrgba_matrix(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 t_xmin, t_xmax, t_ymin, t_ymax,
+ t_x, t_y, img_topdown = 0, dst_offset;
+ float i_x, i_y, xfactor, yfactor;
+ unsigned char sr, sg, sb, sa = 255;
+ double inv_matrix[6];
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* calculate the destination limits */
+ cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL);
+
+ /* Setup inverse transform */
+ cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix);
+
+ /* for all pixels in the destiny area */
+ for(t_y = t_ymin; t_y <= t_ymax; t_y++)
+ {
+ dst_offset = t_y * ctxcanvas->canvas->w;
+
+ for(t_x = t_xmin; t_x <= t_xmax; t_x++)
+ {
+ cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix);
+
+ if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1)
+ {
+ if (img_topdown) /* image is top-bottom */
+ i_y = ih-1 - i_y;
+
+ if (t_x == 350 && t_y == 383)
+ t_x = 350;
+
+ sr = cdBilinearInterpolation(iw, ih, r, i_x, i_y);
+ sg = cdBilinearInterpolation(iw, ih, g, i_x, i_y);
+ sb = cdBilinearInterpolation(iw, ih, b, i_x, i_y);
+ if (a) sa = cdBilinearInterpolation(iw, ih, a, i_x, i_y);
+
+ if (sr > 210 && sg > 210 && sb > 210)
+ sr = sr;
+
+ sCombineRGB(ctxcanvas, t_x + dst_offset, sr, sg, sb, sa);
+ }
+ }
+ }
+}
+
+static void cdputimagerectmap_matrix(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 t_xmin, t_xmax, t_ymin, t_ymax,
+ t_x, t_y, img_topdown = 0, dst_offset;
+ float i_x, i_y, xfactor, yfactor;
+ unsigned char si;
+ double inv_matrix[6];
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left (undocumented feature) */
+ }
+
+ /* calculate the destination limits */
+ cdImageRGBCalcDstLimits(ctxcanvas->canvas, x, y, w, h, &t_xmin, &t_xmax, &t_ymin, &t_ymax, NULL);
+
+ /* Setup inverse transform */
+ cdImageRGBInitInverseTransform(w, h, xmin, xmax, ymin, ymax, &xfactor, &yfactor, ctxcanvas->canvas->matrix, inv_matrix);
+
+ /* for all pixels in the destiny area */
+ for(t_y = t_ymin; t_y <= t_ymax; t_y++)
+ {
+ dst_offset = t_y * ctxcanvas->canvas->w;
+
+ for(t_x = t_xmin; t_x <= t_xmax; t_x++)
+ {
+ cdImageRGBInverseTransform(t_x, t_y, &i_x, &i_y, xfactor, yfactor, xmin, ymin, x, y, inv_matrix);
+
+ if (i_x > xmin && i_y > ymin && i_x < xmax+1 && i_y < ymax+1)
+ {
+ if (img_topdown) /* image is top-bottom */
+ i_y = ih-1 - i_y;
+
+ si = cdZeroOrderInterpolation(iw, ih, index, i_x, i_y);
+ sCombineRGBColor(ctxcanvas, t_x + dst_offset, colors[si]);
+ }
+ }
+ }
+}
+
+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 l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rh, rw, img_topdown = 0;
+ const unsigned char *src_red, *src_green, *src_blue;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, NULL, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_red = r + src_offset;
+ src_green = g + src_offset;
+ src_blue = b + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], 255);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ {
+ r -= iw;
+ g -= iw;
+ b -= iw;
+ }
+ else
+ {
+ r += iw;
+ g += iw;
+ b += iw;
+ }
+ }
+ }
+}
+
+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 l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, img_topdown = 0;
+ const unsigned char *src_red, *src_green, *src_blue, *src_alpha;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectrgba_matrix(ctxcanvas, iw, ih, r, g, b, a, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_red = r + src_offset;
+ src_green = g + src_offset;
+ src_blue = b + src_offset;
+ src_alpha = a + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ sCombineRGB(ctxcanvas, c + dst_offset, src_red[src_offset], src_green[src_offset], src_blue[src_offset], src_alpha[src_offset]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+ a += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ {
+ r -= iw;
+ g -= iw;
+ b -= iw;
+ a -= iw;
+ }
+ else
+ {
+ r += iw;
+ g += iw;
+ b += iw;
+ a += iw;
+ }
+ }
+ }
+}
+
+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 l, c, xsize, ysize, xpos, ypos, src_offset, dst_offset, rw, rh, pal_size, idx, img_topdown = 0;
+ const unsigned char *src_index;
+
+ if (ctxcanvas->canvas->use_matrix)
+ {
+ cdputimagerectmap_matrix(ctxcanvas, iw, ih, index, colors, x, y, w, h, xmin, xmax, ymin, ymax);
+ return;
+ }
+
+ if (h < 0)
+ {
+ h = -h;
+ y -= (h - 1); /* y is at top-left, move it to bottom-left */
+ img_topdown = 1; /* image pointer will start at top-left */
+ }
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ (x+w) < 0 || (y+h) < 0)
+ return;
+
+ xpos = x < 0? 0: x;
+ ypos = y < 0? 0: y;
+
+ xsize = (x+w) < (ctxcanvas->canvas->w-1)+1? (x+w) - xpos: (ctxcanvas->canvas->w-1) - xpos + 1;
+ ysize = (y+h) < (ctxcanvas->canvas->h-1)+1? (y+h) - ypos: (ctxcanvas->canvas->h-1) - ypos + 1;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ /* Como nao sabemos o tamanho da palette a priori,
+ teremos que ver qual o maior indice usado na imagem. */
+ pal_size = 0;
+
+ for (l=0; l<ih; l++)
+ {
+ for (c=0; c<iw; c++)
+ {
+ idx = index[l*iw + c];
+ if (idx > pal_size)
+ pal_size = idx;
+ }
+ }
+
+ pal_size++;
+
+ /* testa se tem que fazer zoom */
+ if (rw != w || rh != h)
+ {
+ int* XTab = cdGetZoomTable(w, rw, xmin);
+ int* YTab = cdGetZoomTable(h, rh, ymin);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ for(l = 0; l < ysize; l++)
+ {
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = YTab[(ih - 1) - (l + (ypos - y))] * iw;
+ else
+ src_offset = YTab[l + (ypos - y)] * iw;
+
+ src_index = index + src_offset;
+
+ for(c = 0; c < xsize; c++)
+ {
+ src_offset = XTab[c + (xpos - x)];
+ idx = src_index[src_offset];
+ sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ if (img_topdown)
+ src_offset = (xpos - x + xmin) + ((ih - 1) - (ypos - y + ymin)) * iw;
+ else
+ src_offset = (xpos - x + xmin) + (ypos - y + ymin) * iw;
+
+ index += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ for(c = 0; c < xsize; c++)
+ {
+ idx = index[c];
+ sCombineRGBColor(ctxcanvas, c + dst_offset, colors[idx]);
+ }
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ if (img_topdown)
+ index -= iw;
+ else
+ index += iw;
+ }
+ }
+}
+
+static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int color)
+{
+ int offset;
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdMatrixTransformPoint(ctxcanvas->canvas->matrix, x, y, &x, &y);
+
+ offset = ctxcanvas->canvas->w * y + x;
+
+ /* verifica se esta dentro da area de desenho */
+ if (x < 0 ||
+ x > (ctxcanvas->canvas->w-1) ||
+ y < 0 ||
+ y > (ctxcanvas->canvas->h-1))
+ return;
+
+ sCombineRGBColor(ctxcanvas, offset, color);
+}
+
+static cdCtxImage* cdcreateimage(cdCtxCanvas* ctxcanvas, int w, int h)
+{
+ cdCtxImage* ctximage;
+ int size = w * h;
+ int num_c = ctxcanvas->alpha? 4: 3;
+
+ ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage));
+ memset(ctximage, 0, sizeof(cdCtxImage));
+
+ ctximage->w = w;
+ ctximage->h = h;
+
+ ctximage->red = (unsigned char*) malloc(num_c*size);
+ if (!ctximage->red)
+ {
+ free(ctximage);
+ return NULL;
+ }
+
+ ctximage->green = ctximage->red + size;
+ ctximage->blue = ctximage->red + 2*size;
+ if (ctxcanvas->alpha)
+ ctximage->alpha = ctximage->red + 3*size;
+
+ memset(ctximage->red, 0xFF, 3*size);
+ if (ctximage->alpha) memset(ctximage->alpha, 0, size); /* transparent */
+
+ return ctximage;
+}
+
+static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y)
+{
+ unsigned char *r, *g, *b, *a = NULL;
+ int w, h, dst_offset, src_offset, l, xsize, ysize, xpos, ypos, do_alpha = 0;
+ unsigned char *src_red, *src_green, *src_blue, *src_alpha = NULL;
+
+ w = ctximage->w;
+ h = ctximage->h;
+
+ if (x >= ctxcanvas->canvas->w || y >= ctxcanvas->canvas->h ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ if (ctximage->alpha && ctxcanvas->alpha)
+ do_alpha = 1;
+
+ r = ctximage->red;
+ g = ctximage->green;
+ b = ctximage->blue;
+ if (do_alpha) a = ctximage->alpha;
+
+ /* ajusta parametros de entrada */
+ xpos = _sNormX(ctxcanvas, x);
+ ypos = _sNormY(ctxcanvas, y);
+
+ xsize = w < (ctxcanvas->canvas->w - xpos)? w: ctxcanvas->canvas->w - xpos;
+ ysize = h < (ctxcanvas->canvas->h - ypos)? h: ctxcanvas->canvas->h - ypos;
+
+ /* ajusta posicao inicial em source */
+ src_offset = xpos + ypos * ctxcanvas->canvas->w;
+ src_red = ctxcanvas->red + src_offset;
+ src_green = ctxcanvas->green + src_offset;
+ src_blue = ctxcanvas->blue + src_offset;
+ if (do_alpha) src_alpha = ctxcanvas->alpha + src_offset;
+
+ /* offset para source */
+ src_offset = ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = (xpos - x) + (ypos - y) * w;
+ r += dst_offset;
+ g += dst_offset;
+ b += dst_offset;
+ if (do_alpha) a += dst_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ memcpy(r, src_red, xsize);
+ memcpy(g, src_green, xsize);
+ memcpy(b, src_blue, xsize);
+ if (do_alpha) memcpy(a, src_alpha, xsize);
+
+ src_red += src_offset;
+ src_green += src_offset;
+ src_blue += src_offset;
+ if (do_alpha) src_alpha += src_offset;
+
+ r += w;
+ g += w;
+ b += w;
+ if (do_alpha) a += w;
+ }
+}
+
+static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage* ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax)
+{
+ int iw, ih, w, h;
+ unsigned char *r, *g, *b, *a;
+ int l, xsize, ysize, xpos, ypos, src_offset, dst_offset;
+
+ iw = ctximage->w;
+ ih = ctximage->h;
+
+ r = ctximage->red;
+ g = ctximage->green;
+ b = ctximage->blue;
+ a = ctximage->alpha;
+
+ w = xmax-xmin+1;
+ h = ymax-ymin+1;
+
+ /* verifica se esta dentro da area de desenho */
+ if (x > (ctxcanvas->canvas->w-1) || y > (ctxcanvas->canvas->h-1) ||
+ x + w < 0 || y + h < 0)
+ return;
+
+ xpos = x;
+ ypos = y;
+
+ if (ypos < 0) ypos = 0;
+ if (xpos < 0) xpos = 0;
+
+ xsize = w < ((ctxcanvas->canvas->w-1)+1 - xpos)? w: ((ctxcanvas->canvas->w-1)+1 - xpos);
+ ysize = h < ((ctxcanvas->canvas->h-1)+1 - ypos)? h: ((ctxcanvas->canvas->h-1)+1 - ypos);
+
+ /* ajusta posicao inicial em destine */
+ dst_offset = xpos + ypos * ctxcanvas->canvas->w;
+
+ /* ajusta posicao inicial em source */
+ src_offset = ((xpos - x) + xmin) + ((ypos - y) + ymin) * iw;
+ r += src_offset;
+ g += src_offset;
+ b += src_offset;
+ if (a) a += src_offset;
+
+ for (l = 0; l < ysize; l++)
+ {
+ if (a)
+ sCombineRGBALine(ctxcanvas, dst_offset, r, g, b, a, xsize);
+ else
+ sCombineRGBLine(ctxcanvas, dst_offset, r, g, b, xsize);
+
+ dst_offset += ctxcanvas->canvas->w;
+
+ r += iw;
+ g += iw;
+ b += iw;
+ if (a) a += iw;
+ }
+}
+
+static void cdkillimage(cdCtxImage* ctximage)
+{
+ free(ctximage->red);
+ memset(ctximage, 0, sizeof(cdCtxImage));
+ free(ctximage);
+}
+
+static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy)
+{
+ int l;
+ long src_offset, dst_offset;
+ int incx,incy, xsize, ysize;
+ int dst_xmin, dst_xmax, dst_ymin, dst_ymax;
+
+ /* corrige valores de entrada */
+
+ xmin = _sNormX(ctxcanvas, xmin);
+ ymin = _sNormY(ctxcanvas, ymin);
+ xmax = _sNormX(ctxcanvas, xmax);
+ ymax = _sNormY(ctxcanvas, ymax);
+
+ dst_xmin = xmin + dx;
+ dst_ymin = ymin + dy;
+ dst_xmax = xmax + dx;
+ dst_ymax = ymax + dy;
+
+ /* verifica se esta dentro da area de desenho */
+ if (dst_xmin > (ctxcanvas->canvas->w-1) || dst_ymin > (ctxcanvas->canvas->h-1) ||
+ dst_xmax < 0 || dst_ymax < 0)
+ return;
+
+ if (dst_ymin < 0) dst_ymin = 0;
+ if (dst_xmin < 0) dst_xmin = 0;
+
+ if (dst_ymax > (ctxcanvas->canvas->h-1)) dst_ymax = (ctxcanvas->canvas->h-1);
+ if (dst_xmax > (ctxcanvas->canvas->w-1)) dst_xmax = (ctxcanvas->canvas->w-1);
+
+ if (dst_xmin > dst_xmax || dst_ymin > dst_ymax)
+ return;
+
+ /* Decide de onde vai comecar a copiar, isto e' necessario pois pode haver
+ uma intersecao entre a imagem original e a nova imagem, assim devo
+ garantir que nao estou colocando um ponto, em cima de um ponto ainda nao
+ lido da imagem antiga. */
+
+ xsize = dst_xmax - dst_xmin + 1;
+ ysize = dst_ymax - dst_ymin + 1;
+
+ /* sentido de copia da direita para a esquerda ou ao contrario. */
+ if (dx < 0)
+ {
+ incx = 1;
+ dst_offset = dst_xmin;
+ src_offset = xmin;
+ }
+ else
+ {
+ incx = -1;
+ dst_offset = dst_xmax;
+ src_offset = xmax;
+ }
+
+ /* sentido de copia de cima para baixo ou ao contrario. */
+ if (dy < 0)
+ {
+ incy = ctxcanvas->canvas->w;
+ dst_offset += dst_ymin * ctxcanvas->canvas->w;
+ src_offset += ymin * ctxcanvas->canvas->w;
+ }
+ else
+ {
+ incy = -(ctxcanvas->canvas->w);
+ dst_offset += dst_ymax * ctxcanvas->canvas->w;
+ src_offset += ymax * ctxcanvas->canvas->w;
+ }
+
+ xsize *= incx;
+
+ for (l = 0; l < ysize; l++)
+ {
+ sCombineRGBLine(ctxcanvas, dst_offset, ctxcanvas->red + src_offset, ctxcanvas->green + src_offset, ctxcanvas->blue + src_offset, xsize);
+ dst_offset += incy;
+ src_offset += incy;
+ }
+}
+
+static char* get_green_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->green;
+}
+
+static cdAttribute green_attrib =
+{
+ "GREENIMAGE",
+ NULL,
+ get_green_attrib
+};
+
+static char* get_blue_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->blue;
+}
+
+static cdAttribute blue_attrib =
+{
+ "BLUEIMAGE",
+ NULL,
+ get_blue_attrib
+};
+
+static char* get_red_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->red;
+}
+
+static cdAttribute red_attrib =
+{
+ "REDIMAGE",
+ NULL,
+ get_red_attrib
+};
+
+static char* get_alpha_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return (char*)ctxcanvas->alpha;
+}
+
+static cdAttribute alpha_attrib =
+{
+ "ALPHAIMAGE",
+ NULL,
+ get_alpha_attrib
+};
+
+static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (!data || data[0] == '0')
+ ctxcanvas->canvas->simulation->antialias = 0;
+ else
+ ctxcanvas->canvas->simulation->antialias = 1;
+}
+
+static char* get_aa_attrib(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->canvas->simulation->antialias)
+ return "0";
+ else
+ return "1";
+}
+
+static cdAttribute aa_attrib =
+{
+ "ANTIALIAS",
+ set_aa_attrib,
+ get_aa_attrib
+};
+
+static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle,
+ &ctxcanvas->rotate_center_x,
+ &ctxcanvas->rotate_center_y);
+
+ cdCanvasTransformTranslate(ctxcanvas->canvas, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ cdCanvasTransformRotate(ctxcanvas->canvas, ctxcanvas->rotate_angle);
+ cdCanvasTransformTranslate(ctxcanvas->canvas, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+ else
+ {
+ ctxcanvas->rotate_angle = 0;
+ ctxcanvas->rotate_center_x = 0;
+ ctxcanvas->rotate_center_y = 0;
+
+ cdCanvasTransform(ctxcanvas->canvas, NULL);
+ }
+}
+
+static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas)
+{
+ static char data[100];
+
+ if (!ctxcanvas->rotate_angle)
+ return NULL;
+
+ sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle,
+ ctxcanvas->rotate_center_x,
+ ctxcanvas->rotate_center_y);
+
+ return data;
+}
+
+static cdAttribute rotate_attrib =
+{
+ "ROTATE",
+ set_rotate_attrib,
+ get_rotate_attrib
+};
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ int w = 0, h = 0, use_alpha = 0;
+ float res = (float)3.78;
+ unsigned char *r = NULL, *g = NULL, *b = NULL, *a = NULL;
+ char* str_data = (char*)data;
+ char* res_ptr = NULL;
+
+ if (strstr(str_data, "-a"))
+ use_alpha = 1;
+
+ res_ptr = strstr(str_data, "-r");
+ if (res_ptr)
+ sscanf(res_ptr+2, "%g", &res);
+
+ /* size and rgb */
+#ifdef SunOS_OLD
+ if (use_alpha)
+ sscanf(str_data, "%dx%d %d %d %d %d", &w, &h, &r, &g, &b, &a);
+ else
+ sscanf(str_data, "%dx%d %d %d %d", &w, &h, &r, &g, &b);
+#else
+ if (use_alpha)
+ sscanf(str_data, "%dx%d %p %p %p %p", &w, &h, &r, &g, &b, &a);
+ else
+ sscanf(str_data, "%dx%d %p %p %p", &w, &h, &r, &g, &b);
+#endif
+
+ if (w == 0 || h == 0)
+ return;
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->yres = res;
+ canvas->xres = res;
+ canvas->w_mm = ((double)w) / res;
+ canvas->h_mm = ((double)h) / res;
+ if (use_alpha)
+ canvas->bpp = 32;
+ else
+ canvas->bpp = 24;
+
+ if (r && g && b)
+ {
+ ctxcanvas->user_image = 1;
+
+ ctxcanvas->red = r;
+ ctxcanvas->green = g;
+ ctxcanvas->blue = b;
+ ctxcanvas->alpha = a;
+ }
+ else
+ {
+ int size = w * h;
+ int num_c = use_alpha? 4: 3;
+
+ ctxcanvas->user_image = 0;
+
+ ctxcanvas->red = (unsigned char*)malloc(num_c*size);
+ if (!ctxcanvas->red)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ ctxcanvas->green = ctxcanvas->red + size;
+ ctxcanvas->blue = ctxcanvas->red + 2*size;
+ if (use_alpha)
+ ctxcanvas->alpha = ctxcanvas->red + 3*size;
+
+ memset(ctxcanvas->red, 0xFF, 3*size); /* white */
+ if (ctxcanvas->alpha) memset(ctxcanvas->alpha, 0, size); /* transparent */
+ }
+
+ ctxcanvas->clip = (unsigned char*)malloc(w*h);
+ memset(ctxcanvas->clip, 1, w*h); /* CD_CLIPOFF */
+
+ canvas->ctxcanvas = ctxcanvas;
+ ctxcanvas->canvas = canvas;
+
+ cdSimInitText(canvas->simulation);
+ /* nao preciso inicializar a fonte,
+ pois isso sera' feito na inicializacao dos atributos default do driver */
+
+ canvas->simulation->antialias = 1;
+
+ cdRegisterAttribute(canvas, &red_attrib);
+ cdRegisterAttribute(canvas, &green_attrib);
+ cdRegisterAttribute(canvas, &blue_attrib);
+ cdRegisterAttribute(canvas, &alpha_attrib);
+ cdRegisterAttribute(canvas, &aa_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdSimulation* sim;
+
+ /* initialize function table*/
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxNewRegion = cdnewregion;
+ canvas->cxIsPointInRegion = cdispointinregion;
+ canvas->cxOffsetRegion = cdoffsetregion;
+ canvas->cxGetRegionBox = cdgetregionbox;
+
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxGetImageRGB = cdgetimagergb;
+
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxKillImage = cdkillimage;
+ canvas->cxScrollArea = cdscrollarea;
+
+ canvas->cxClear = cdclear;
+ canvas->cxPixel = cdpixel;
+
+ canvas->cxLine = cdlineSIM;
+ canvas->cxRect = cdrectSIM;
+ canvas->cxBox = cdbox;
+ canvas->cxArc = cdarcSIM;
+ canvas->cxSector = cdsector;
+ canvas->cxChord = cdchord;
+ canvas->cxPoly = cdpoly;
+ canvas->cxText = cdtext;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+
+ /* use simulation */
+ canvas->cxFont = cdfontSIM;
+ canvas->cxGetFontDim = cdgetfontdimSIM;
+ canvas->cxGetTextSize = cdgettextsizeSIM;
+
+ sim = canvas->simulation;
+
+ sim->SolidLine = irgbSolidLine;
+ sim->PatternLine = irgbPatternLine;
+ sim->StippleLine = irgbStippleLine;
+ sim->HatchLine = irgbHatchLine;
+}
+
+static cdContext cdImageRGBContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_FPRIMTIVES |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION |
+ CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextImageRGB(void)
+{
+ return &cdImageRGBContext;
+}
+
+static void cdflushDB(cdCtxCanvas *ctxcanvas)
+{
+ int old_writemode;
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+
+ /* Flush can be affected by Origin and Clipping, but not WriteMode */
+
+ old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE);
+ cdCanvasPutImageRectRGB(canvas_dbuffer, ctxcanvas->canvas->w, ctxcanvas->canvas->h, ctxcanvas->red, ctxcanvas->green, ctxcanvas->blue, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h, 0, 0, 0, 0);
+ cdCanvasWriteMode(canvas_dbuffer, old_writemode);
+}
+
+static void cdcreatecanvasDB(cdCanvas* canvas, cdCanvas* canvas_dbuffer)
+{
+ char rgbdata[100];
+ sprintf(rgbdata, "%dx%d -r%g", canvas_dbuffer->w, canvas_dbuffer->h, canvas_dbuffer->xres);
+ cdcreatecanvas(canvas, rgbdata);
+ if (canvas->ctxcanvas)
+ canvas->ctxcanvas->canvas_dbuffer = canvas_dbuffer;
+}
+
+static int cdactivateDB(cdCtxCanvas *ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+
+ /* this is done in the canvas_dbuffer context */
+ /* this will update canvas size */
+ cdCanvasActivate(canvas_dbuffer);
+
+ /* check if the size changed */
+ if (canvas_dbuffer->w != ctxcanvas->canvas->w ||
+ canvas_dbuffer->h != ctxcanvas->canvas->h)
+ {
+ cdCanvas* canvas = ctxcanvas->canvas;
+ /* save the current, if the rebuild fail */
+ cdCtxCanvas* old_ctxcanvas = ctxcanvas;
+
+ /* if the image is rebuild, the canvas that uses the image must be also rebuild */
+
+ /* rebuild the image and the canvas */
+ canvas->ctxcanvas = NULL;
+ cdcreatecanvasDB(canvas, canvas_dbuffer);
+ if (!canvas->ctxcanvas)
+ {
+ canvas->ctxcanvas = old_ctxcanvas;
+ return CD_ERROR;
+ }
+
+ /* remove the old image and canvas */
+ cdkillcanvas(old_ctxcanvas);
+
+ ctxcanvas = canvas->ctxcanvas;
+
+ /* update canvas attributes */
+ if (canvas->cxBackground) canvas->cxBackground(ctxcanvas, canvas->background);
+ if (canvas->cxForeground) canvas->cxForeground(ctxcanvas, canvas->foreground);
+ if (canvas->cxBackOpacity) canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity);
+ if (canvas->cxWriteMode) canvas->cxWriteMode(ctxcanvas, canvas->write_mode);
+ if (canvas->cxLineStyle) canvas->cxLineStyle(ctxcanvas, canvas->line_style);
+ if (canvas->cxLineWidth) canvas->cxLineWidth(ctxcanvas, canvas->line_width);
+ if (canvas->cxLineCap) canvas->cxLineCap(ctxcanvas, canvas->line_cap);
+ if (canvas->cxLineJoin) canvas->cxLineJoin(ctxcanvas, canvas->line_join);
+ if (canvas->cxHatch) canvas->cxHatch(ctxcanvas, canvas->hatch_style);
+ if (canvas->stipple && canvas->cxStipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple);
+ if (canvas->pattern && canvas->cxPattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern);
+ if (canvas->cxInteriorStyle) canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style);
+ if (canvas->native_font[0] && canvas->cxNativeFont)
+ canvas->cxNativeFont(ctxcanvas, canvas->native_font);
+ else if (canvas->cxFont) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+ if (canvas->cxTextAlignment) canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment);
+ if (canvas->cxTextOrientation) canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation);
+ if (canvas->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix);
+ if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax);
+ if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax);
+ if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n);
+ if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n);
+ if (canvas->clip_mode != CD_CLIPOFF && canvas->cxClip) canvas->cxClip(ctxcanvas, canvas->clip_mode);
+ }
+
+ return CD_OK;
+}
+
+static void cddeactivateDB(cdCtxCanvas *ctxcanvas)
+{
+ cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer;
+ /* this is done in the canvas_dbuffer context */
+ cdCanvasDeactivate(canvas_dbuffer);
+}
+
+static void cdinittableDB(cdCanvas* canvas)
+{
+ cdinittable(canvas);
+
+ canvas->cxActivate = cdactivateDB;
+ canvas->cxDeactivate = cddeactivateDB;
+
+ canvas->cxFlush = cdflushDB;
+}
+
+static cdContext cdDBufferRGBContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_FPRIMTIVES |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN | CD_CAP_REGION |
+ CD_CAP_PALETTE | CD_CAP_TEXTORIENTATION),
+ 0,
+ cdcreatecanvasDB,
+ cdinittableDB,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextDBufferRGB(void)
+{
+ return &cdDBufferRGBContext;
+}
diff --git a/src/drv/cdmf.c b/src/drv/cdmf.c
new file mode 100644
index 0000000..6c2e711
--- /dev/null
+++ b/src/drv/cdmf.c
@@ -0,0 +1,1188 @@
+/** \file
+ * \brief CD Metafile driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "cd.h"
+#include "wd.h"
+#include "cd_private.h"
+#include "cdmf.h"
+#include "cdmf_private.h"
+
+
+/* codes for the primitives and attributes in the metafile
+ Can NOT be changed, only added for backward compatibility.
+*/
+enum
+{
+ CDMF_FLUSH, /* 0 */
+ CDMF_CLEAR, /* 1 */
+ CDMF_CLIP, /* 2 */
+ CDMF_CLIPAREA, /* 3 */
+ CDMF_LINE, /* 4 */
+ CDMF_BOX, /* 5 */
+ CDMF_ARC, /* 6 */
+ CDMF_SECTOR, /* 7 */
+ CDMF_TEXT, /* 8 */
+ CDMF_BEGIN, /* 9 */
+ CDMF_VERTEX, /* 10 */
+ CDMF_END, /* 11 */
+ CDMF_MARK, /* 12 */
+ CDMF_BACKOPACITY, /* 13 */
+ CDMF_WRITEMODE, /* 14 */
+ CDMF_LINESTYLE, /* 15 */
+ CDMF_LINEWIDTH, /* 16 */
+ CDMF_INTERIORSTYLE, /* 17 */
+ CDMF_HATCH, /* 18 */
+ CDMF_STIPPLE, /* 19 */
+ CDMF_PATTERN, /* 20 */
+ CDMF_OLDFONT, /* 21 */
+ CDMF_NATIVEFONT, /* 22 */
+ CDMF_TEXTALIGNMENT, /* 23 */
+ CDMF_MARKTYPE, /* 24 */
+ CDMF_MARKSIZE, /* 25 */
+ CDMF_PALETTE, /* 26 */
+ CDMF_BACKGROUND, /* 27 */
+ CDMF_FOREGROUND, /* 28 */
+ CDMF_PUTIMAGERGB, /* 29 */
+ CDMF_PUTIMAGEMAP, /* 30 */
+ CDMF_PIXEL, /* 31 */
+ CDMF_SCROLLAREA, /* 32 */
+ CDMF_TEXTORIENTATION, /* 33 */
+ CDMF_RECT, /* 34 */
+ CDMF_PUTIMAGERGBA, /* 35 */
+ CDMF_WLINE, /* 36 */
+ CDMF_WRECT, /* 37 */
+ CDMF_WBOX, /* 38 */
+ CDMF_WARC, /* 39 */
+ CDMF_WSECTOR, /* 40 */
+ CDMF_WTEXT, /* 41 */
+ CDMF_WVERTEX, /* 42 */
+ CDMF_WMARK, /* 43 */
+ CDMF_VECTORTEXT, /* 44 */
+ CDMF_MULTILINEVECTORTEXT, /* 45 */
+ CDMF_WVECTORTEXT, /* 46 */
+ CDMF_WMULTILINEVECTORTEXT, /* 47 */
+ CDMF_WINDOW, /* 48 */
+ CDMF_WCLIPAREA, /* 49 */
+ CDMF_VECTORFONT, /* 50 */
+ CDMF_VECTORTEXTDIRECTION, /* 51 */
+ CDMF_VECTORTEXTTRANSFORM, /* 52 */
+ CDMF_VECTORTEXTSIZE, /* 53 */
+ CDMF_VECTORCHARSIZE, /* 54 */
+ CDMF_WVECTORTEXTDIRECTION, /* 55 */
+ CDMF_WVECTORTEXTSIZE, /* 56 */
+ CDMF_WVECTORCHARSIZE, /* 57 */
+ CDMF_FILLMODE, /* 58 */
+ CDMF_LINESTYLEDASHES, /* 59 */
+ CDMF_LINECAP, /* 60 */
+ CDMF_LINEJOIN, /* 61 */
+ CDMF_CHORD, /* 62 */
+ CDMF_WCHORD, /* 63 */
+ CDMF_FLINE, /* 64 */
+ CDMF_FRECT, /* 65 */
+ CDMF_FBOX, /* 66 */
+ CDMF_FARC, /* 67 */
+ CDMF_FSECTOR, /* 68 */
+ CDMF_FTEXT, /* 69 */
+ CDMF_FVERTEX, /* 70 */
+ CDMF_MATRIX, /* 71 */
+ CDMF_FCHORD, /* 72 */
+ CDMF_FCLIPAREA, /* 73 */
+ CDMF_FONT, /* 74 */
+ CDMF_RESETMATRIX /* 75 */
+};
+
+struct _cdCtxCanvas
+{
+ /* public */
+ cdCanvas* canvas;
+ char* filename;
+ void* data; /* used by other drivers */
+
+ /* private */
+ int last_line_style;
+ int last_fill_mode;
+ FILE* file;
+};
+
+void cdkillcanvasMF(cdCanvasMF *mfcanvas)
+{
+ cdCtxCanvas *ctxcanvas = (cdCtxCanvas*)mfcanvas;
+ free(ctxcanvas->filename);
+ fclose(ctxcanvas->file);
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ fflush(ctxcanvas->file);
+ fprintf(ctxcanvas->file, "%d\n", CDMF_FLUSH);
+}
+
+static void cdclear(cdCtxCanvas *ctxcanvas)
+{
+ fprintf(ctxcanvas->file, "%d\n", CDMF_CLEAR);
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_CLIP, mode);
+ return mode;
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_CLIPAREA, xmin, xmax, ymin, ymax);
+}
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FCLIPAREA, xmin, xmax, ymin, ymax);
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ if (matrix)
+ fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_MATRIX, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ else
+ fprintf(ctxcanvas->file, "%d\n", CDMF_RESETMATRIX);
+}
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_LINE, x1, y1, x2, y2);
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FLINE, x1, y1, x2, y2);
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_RECT, xmin, xmax, ymin, ymax);
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FRECT, xmin, xmax, ymin, ymax);
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d\n", CDMF_BOX, xmin, xmax, ymin, ymax);
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g\n", CDMF_FBOX, xmin, xmax, ymin, ymax);
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_ARC, xc, yc, w, h, a1, a2);
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FARC, xc, yc, w, h, a1, a2);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_SECTOR, xc, yc, w, h, a1, a2);
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FSECTOR, xc, yc, w, h, a1, a2);
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %g %g\n", CDMF_CHORD, xc, yc, w, h, a1, a2);
+}
+
+static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %g %g %g %g\n", CDMF_FCHORD, xc, yc, w, h, a1, a2);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_TEXT, x, y, text);
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text)
+{
+ fprintf(ctxcanvas->file, "%d %g %g %s\n", CDMF_FTEXT, x, y, text);
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode)
+ {
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode);
+ ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode;
+ }
+
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode);
+
+ for(i = 0; i<n; i++)
+ fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_VERTEX, poly[i].x, poly[i].y);
+
+ fprintf(ctxcanvas->file, "%d\n", CDMF_END);
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_FILL && ctxcanvas->canvas->fill_mode != ctxcanvas->last_fill_mode)
+ {
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_FILLMODE, ctxcanvas->canvas->fill_mode);
+ ctxcanvas->last_fill_mode = ctxcanvas->canvas->fill_mode;
+ }
+
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_BEGIN, mode);
+
+ for(i = 0; i<n; i++)
+ fprintf(ctxcanvas->file, "%d %g %g\n", CDMF_FVERTEX, poly[i].x, poly[i].y);
+
+ fprintf(ctxcanvas->file, "%d\n", CDMF_END);
+}
+
+static int cdbackopacity(cdCtxCanvas *ctxcanvas, int opacity)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_BACKOPACITY, opacity);
+ return opacity;
+}
+
+static int cdwritemode(cdCtxCanvas *ctxcanvas, int mode)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_WRITEMODE, mode);
+ return mode;
+}
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ if (style == CD_CUSTOM && ctxcanvas->canvas->line_style != ctxcanvas->last_line_style)
+ {
+ int i;
+ fprintf(ctxcanvas->file, "%d %d", CDMF_LINESTYLEDASHES, ctxcanvas->canvas->line_dashes_count);
+ for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++)
+ fprintf(ctxcanvas->file, " %d", ctxcanvas->canvas->line_dashes[i]);
+ fprintf(ctxcanvas->file, "\n");
+ ctxcanvas->last_line_style = ctxcanvas->canvas->line_style;
+ }
+
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINESTYLE, style);
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEWIDTH, width);
+ return width;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINECAP, cap);
+ return cap;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_LINEJOIN, join);
+ return join;
+}
+
+static int cdinteriorstyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_INTERIORSTYLE, style);
+ return style;
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_HATCH, style);
+ return style;
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int w, int h, const unsigned char *stipple)
+{
+ int c, t;
+
+ fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_STIPPLE, w, h);
+
+ t = w * h;
+
+ for (c = 0; c < t; c++)
+ {
+ fprintf(ctxcanvas->file, "%d ", (int)*stipple++);
+ if ((c + 1) % w == 0)
+ fprintf(ctxcanvas->file, "\n");
+ }
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int w, int h, const long int *pattern)
+{
+ int c, t;
+ unsigned char r, g, b;
+
+ fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PATTERN, w, h);
+
+ t = w * h;
+
+ /* stores the pattern with separeted RGB values */
+ for (c = 0; c < t; c++)
+ {
+ cdDecodeColor(*pattern++, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%d %d %d ", (int)r, (int)g, (int)b);
+ if (c % w == 0)
+ fprintf(ctxcanvas->file, "\n");
+ }
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char* type_face, int style, int size)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %s\n", CDMF_FONT, style, size, type_face);
+ return 1;
+}
+
+static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* font)
+{
+ fprintf(ctxcanvas->file, "%d %s\n", CDMF_NATIVEFONT, font);
+ return 1;
+}
+
+static int cdtextalignment(cdCtxCanvas *ctxcanvas, int alignment)
+{
+ fprintf(ctxcanvas->file, "%d %d\n", CDMF_TEXTALIGNMENT, alignment);
+ return alignment;
+}
+
+static double cdtextorientation(cdCtxCanvas *ctxcanvas, double angle)
+{
+ fprintf(ctxcanvas->file, "%d %g\n", CDMF_TEXTORIENTATION, angle);
+ return angle;
+}
+
+static void cdpalette(cdCtxCanvas *ctxcanvas, int n, const long int *palette, int mode)
+{
+ int c;
+ unsigned char r, g, b;
+
+ fprintf(ctxcanvas->file, "%d %d %d\n", CDMF_PALETTE, n, mode);
+
+ for (c = 0; c < n; c++)
+ {
+ cdDecodeColor(*palette++, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b);
+ }
+}
+
+static long cdbackground(cdCtxCanvas *ctxcanvas, long int color)
+{
+ unsigned char r, g, b;
+ cdDecodeColor(color, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_BACKGROUND, (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);
+ fprintf(ctxcanvas->file, "%d %d %d %d\n", CDMF_FOREGROUND, (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 c, l, offset;
+
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGB, iw, ih, x, y, w, h);
+
+ offset = ymin*iw + xmin;
+ r += offset;
+ g += offset;
+ b += offset;
+
+ offset = iw - (xmax-xmin+1);
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ for (c = xmin; c <= xmax; c++)
+ {
+ fprintf(ctxcanvas->file, "%d %d %d ", (int)*r++, (int)*g++, (int)*b++);
+ }
+
+ r += offset;
+ g += offset;
+ b += offset;
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+}
+
+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 c, l, offset;
+
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGERGBA, iw, ih, x, y, w, h);
+
+ offset = ymin*iw + xmin;
+ r += offset;
+ g += offset;
+ b += offset;
+ a += offset;
+
+ offset = iw - (xmax-xmin+1);
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ for (c = xmin; c <= xmax; c++)
+ {
+ fprintf(ctxcanvas->file, "%d %d %d %d ", (int)*r++, (int)*g++, (int)*b++, (int)*a++);
+ }
+
+ r += offset;
+ g += offset;
+ b += offset;
+ a += offset;
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+}
+
+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 c, l, n = 0, offset;
+ unsigned char r, g, b;
+
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_PUTIMAGEMAP, iw, ih, x, y, w, h);
+
+ index += ymin*iw + xmin;
+ offset = iw - (xmax-xmin+1);
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ for (c = xmin; c <= xmax; c++)
+ {
+ if (*index > n)
+ n = *index;
+
+ fprintf(ctxcanvas->file, "%d ", (int)*index++);
+ }
+
+ index += offset;
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+
+ n++;
+
+ for (c = 0; c < n; c++)
+ {
+ cdDecodeColor(*colors++, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%d %d %d\n", (int)r, (int)g, (int)b);
+ }
+}
+
+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, "%d %d %d %d %d %d\n", CDMF_PIXEL, x, y, (int)r, (int)g, (int)b);
+}
+
+static void cdscrollarea(cdCtxCanvas *ctxcanvas, int xmin,int xmax, int ymin,int ymax, int dx,int dy)
+{
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %d %d\n", CDMF_SCROLLAREA, xmin, xmax, ymin, ymax, dx, dy);
+}
+
+
+/**********/
+/* cdPlay */
+/**********/
+
+
+static double factorX = 1;
+static double factorY = 1;
+static int offsetX = 0;
+static int offsetY = 0;
+static double factorS = 1;
+
+static int sScaleX(int x)
+{
+ return cdRound(x * factorX + offsetX);
+}
+
+static int sScaleY(int y)
+{
+ return cdRound(y * factorY + offsetY);
+}
+
+static double sfScaleX(double x)
+{
+ return x * factorX + offsetX;
+}
+
+static double sfScaleY(double y)
+{
+ return y * factorY + offsetY;
+}
+
+static int sScaleW(int w)
+{
+ w = (int)(w * factorX + 0.5); /* always positive */
+ return w == 0? 1: w;
+}
+
+static double sfScaleH(double h)
+{
+ h = h * factorY;
+ return h == 0? 1: h;
+}
+
+static double sfScaleW(double w)
+{
+ w = w * factorX; /* always positive */
+ return w == 0? 1: w;
+}
+
+static int sScaleH(int h)
+{
+ h = (int)(h * factorY + 0.5);
+ return h == 0? 1: h;
+}
+
+static int sScaleS(int s)
+{
+ s = (int)(s * factorS + 0.5);
+ return s == 0? 1: s;
+}
+
+typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm);
+static _cdsizecb cdsizecb = NULL;
+
+static int cdregistercallback(int cb, cdCallback func)
+{
+ switch (cb)
+ {
+ case CD_SIZECB:
+ cdsizecb = (_cdsizecb)func;
+ return CD_OK;
+ }
+
+ return CD_ERROR;
+}
+
+static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ char* filename = (char*)data;
+ FILE* file;
+ char TextBuffer[512];
+ int iparam1, iparam2, iparam3, iparam4, iparam5, iparam6, iparam7, iparam8, iparam9, iparam10;
+ int c, t, n, w, h, func;
+ double dparam1, dparam2, dparam3, dparam4, dparam5, dparam6;
+ unsigned char* stipple, * _stipple, *red, *green, *blue, *_red, *_green, *_blue, *index, *_index, *_alpha, *alpha;
+ long int *pattern, *palette, *_pattern, *_palette, *colors, *_colors;
+ int* dashes;
+ double matrix[6];
+ const char * font_family[] =
+ {
+ "System", /* CD_SYSTEM */
+ "Courier", /* CD_COURIER */
+ "Times", /* CD_TIMES_ROMAN */
+ "Helvetica" /* CD_HELVETICA */
+ };
+
+ file = fopen(filename, "r");
+ if (!file)
+ return CD_ERROR;
+
+ func = -1;
+ w = 0;
+ h = 0;
+
+ factorX = 1;
+ factorY = 1;
+ offsetX = 0;
+ offsetY = 0;
+ factorS = 1;
+
+ fscanf(file, "%s %d %d", TextBuffer, &w, &h);
+
+ if (strcmp(TextBuffer, "CDMF") != 0)
+ {
+ fclose(file);
+ return CD_ERROR;
+ }
+
+ if (w>1 && h>1 && xmax!=0 && ymax!=0)
+ {
+ offsetX = xmin;
+ offsetY = ymin;
+ factorX = ((double)(xmax-xmin)) / (w-1);
+ factorY = ((double)(ymax-ymin)) / (h-1);
+
+ if (factorX < factorY)
+ factorS = factorX;
+ else
+ factorS = factorY;
+ }
+
+ if (cdsizecb)
+ {
+ int err;
+ err = cdsizecb(canvas, w, h, w, h);
+ if (err)
+ return CD_ERROR;
+ }
+
+ while (!feof(file))
+ {
+ fscanf(file, "%d", &func);
+ if (feof(file))
+ break;
+
+ switch (func)
+ {
+ case CDMF_FLUSH:
+ cdCanvasFlush(canvas);
+ break;
+ case CDMF_CLEAR:
+ cdCanvasClear(canvas);
+ break;
+ case CDMF_CLIP:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasClip(canvas, iparam1);
+ break;
+ case CDMF_CLIPAREA:
+ fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4);
+ cdCanvasClipArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4));
+ break;
+ case CDMF_FCLIPAREA:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ cdfCanvasClipArea(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4));
+ break;
+ case CDMF_MATRIX:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]);
+ cdCanvasTransform(canvas, matrix);
+ break;
+ case CDMF_RESETMATRIX:
+ cdCanvasTransform(canvas, NULL);
+ break;
+ case CDMF_WCLIPAREA:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasClipArea(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ case CDMF_LINE:
+ fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4);
+ cdCanvasLine(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleX(iparam3), sScaleY(iparam4));
+ break;
+ case CDMF_FLINE:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ cdfCanvasLine(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleX(dparam3), sfScaleY(dparam4));
+ break;
+ case CDMF_WLINE:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasLine(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ case CDMF_RECT:
+ fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4);
+ cdCanvasRect(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4));
+ break;
+ case CDMF_FRECT:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ cdfCanvasRect(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4));
+ break;
+ case CDMF_WRECT:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasRect(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ case CDMF_BOX:
+ fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4);
+ cdCanvasBox(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4));
+ break;
+ case CDMF_WBOX:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasBox(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ case CDMF_FBOX:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ cdfCanvasBox(canvas, sfScaleX(dparam1), sfScaleX(dparam2), sfScaleY(dparam3), sfScaleY(dparam4));
+ break;
+ case CDMF_ARC:
+ fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2);
+ cdCanvasArc(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2);
+ break;
+ case CDMF_FARC:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ cdfCanvasArc(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6);
+ break;
+ case CDMF_WARC:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ wdCanvasArc(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6);
+ break;
+ case CDMF_SECTOR:
+ fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2);
+ cdCanvasSector(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2);
+ break;
+ case CDMF_FSECTOR:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ cdfCanvasSector(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6);
+ break;
+ case CDMF_WSECTOR:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ wdCanvasSector(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6);
+ break;
+ case CDMF_CHORD:
+ fscanf(file, "%d %d %d %d %lg %lg", &iparam1, &iparam2, &iparam3, &iparam4, &dparam1, &dparam2);
+ cdCanvasChord(canvas, sScaleX(iparam1), sScaleY(iparam2), sScaleW(iparam3), sScaleH(iparam4), dparam1, dparam2);
+ break;
+ case CDMF_FCHORD:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ cdfCanvasChord(canvas, sfScaleX(dparam1), sfScaleY(dparam2), sfScaleW(dparam3), sfScaleH(dparam4), dparam5, dparam6);
+ break;
+ case CDMF_WCHORD:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4, &dparam5, &dparam6);
+ wdCanvasChord(canvas, dparam1, dparam2, dparam3, dparam4, dparam5, dparam6);
+ break;
+ case CDMF_TEXT:
+ fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer);
+ cdCanvasText(canvas, sScaleX(iparam1), sScaleY(iparam2), TextBuffer);
+ break;
+ case CDMF_FTEXT:
+ fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer);
+ cdfCanvasText(canvas, sfScaleX(dparam1), sfScaleY(dparam2), TextBuffer);
+ break;
+ case CDMF_WTEXT:
+ fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer);
+ wdCanvasText(canvas, dparam1, dparam2, TextBuffer);
+ break;
+ case CDMF_BEGIN:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasBegin(canvas, iparam1);
+ break;
+ case CDMF_VERTEX:
+ fscanf(file, "%d %d", &iparam1, &iparam2);
+ cdCanvasVertex(canvas, sScaleX(iparam1), sScaleY(iparam2));
+ break;
+ case CDMF_FVERTEX:
+ fscanf(file, "%lg %lg", &dparam1, &dparam2);
+ cdfCanvasVertex(canvas, sfScaleX(dparam1), sfScaleY(dparam2));
+ break;
+ case CDMF_WVERTEX:
+ fscanf(file, "%lg %lg", &dparam1, &dparam2);
+ wdCanvasVertex(canvas, dparam1, dparam2);
+ break;
+ case CDMF_END:
+ cdCanvasEnd(canvas);
+ break;
+ case CDMF_MARK:
+ fscanf(file, "%d %d", &iparam1, &iparam2);
+ cdCanvasMark(canvas, sScaleX(iparam1), sScaleY(iparam2));
+ break;
+ case CDMF_WMARK:
+ fscanf(file, "%lg %lg", &dparam1, &dparam2);
+ wdCanvasMark(canvas, dparam1, dparam2);
+ break;
+ case CDMF_BACKOPACITY:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasBackOpacity(canvas, iparam1);
+ break;
+ case CDMF_WRITEMODE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasWriteMode(canvas, iparam1);
+ break;
+ case CDMF_LINESTYLE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasLineStyle(canvas, iparam1);
+ break;
+ case CDMF_LINEWIDTH:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasLineWidth(canvas, sScaleS(iparam1));
+ break;
+ case CDMF_LINECAP:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasLineCap(canvas, iparam1);
+ break;
+ case CDMF_LINEJOIN:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasLineJoin(canvas, iparam1);
+ break;
+ case CDMF_LINESTYLEDASHES:
+ fscanf(file, "%d", &iparam1);
+ dashes = (int*)malloc(iparam1*sizeof(int));
+ for (c = 0; c < iparam1; c++)
+ fscanf(file, "%d", &dashes[c]);
+ cdCanvasLineStyleDashes(canvas, dashes, iparam1);
+ free(dashes);
+ break;
+ case CDMF_FILLMODE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasFillMode(canvas, iparam1);
+ break;
+ case CDMF_INTERIORSTYLE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasInteriorStyle(canvas, iparam1);
+ break;
+ case CDMF_HATCH:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasHatch(canvas, iparam1);
+ break;
+ case CDMF_STIPPLE:
+ fscanf(file, "%d %d", &iparam1, &iparam2);
+ t = iparam1 * iparam2;
+ stipple = (unsigned char*)malloc(t);
+ _stipple = stipple;
+ for (c = 0; c < t; c++)
+ {
+ fscanf(file, "%d", &iparam3);
+ *_stipple++ = (unsigned char)iparam3;
+ }
+ cdCanvasStipple(canvas, iparam1, iparam2, stipple);
+ free(stipple);
+ break;
+ case CDMF_PATTERN:
+ fscanf(file, "%d %d", &iparam1, &iparam2);
+ t = iparam1 * iparam2;
+ pattern = (long int*)malloc(t * sizeof(long));
+ _pattern = pattern;
+ for (c = 0; c < t; c++)
+ {
+ fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5);
+ *_pattern++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5);
+ }
+ cdCanvasPattern(canvas, iparam1, iparam2, pattern);
+ free(pattern);
+ break;
+ case CDMF_OLDFONT:
+ fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3);
+ if (iparam1 < 0 || iparam1 > 3) break;
+ if (iparam3 < 0)
+ {
+ iparam3 = -sScaleH(abs(iparam3));
+ if (iparam3 > -5) iparam3 = -5;
+ }
+ else
+ {
+ iparam3 = sScaleH(abs(iparam3));
+ if (iparam3 < 5) iparam3 = 5;
+ }
+ cdCanvasFont(canvas, font_family[iparam1], iparam2, iparam3);
+ break;
+ case CDMF_FONT:
+ fscanf(file, "%d %d %[^\n]", &iparam2, &iparam3, TextBuffer);
+ if (iparam3 < 0)
+ {
+ iparam3 = -sScaleH(abs(iparam3));
+ if (iparam3 > -5) iparam3 = -5;
+ }
+ else
+ {
+ iparam3 = sScaleH(abs(iparam3));
+ if (iparam3 < 5) iparam3 = 5;
+ }
+ cdCanvasFont(canvas, TextBuffer, iparam2, iparam3);
+ break;
+ case CDMF_NATIVEFONT:
+ fscanf(file, "%[^\n]", TextBuffer);
+ cdCanvasNativeFont(canvas, TextBuffer);
+ break;
+ case CDMF_TEXTALIGNMENT:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasTextAlignment(canvas, iparam1);
+ break;
+ case CDMF_TEXTORIENTATION:
+ fscanf(file, "%lg", &dparam1);
+ cdCanvasTextOrientation(canvas, dparam1);
+ break;
+ case CDMF_MARKTYPE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasMarkType(canvas, iparam1);
+ break;
+ case CDMF_MARKSIZE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasMarkSize(canvas, sScaleS(iparam1));
+ break;
+ case CDMF_PALETTE:
+ fscanf(file, "%d %d", &iparam1, &iparam2);
+ _palette = palette = (long int*)malloc(iparam1);
+ for (c = 0; c < iparam1; c++)
+ {
+ fscanf(file, "%d %d %d", &iparam3, &iparam4, &iparam5);
+ *_palette++ = cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5);
+ }
+ cdCanvasPalette(canvas, iparam1, palette, iparam2);
+ free(palette);
+ break;
+ case CDMF_BACKGROUND:
+ fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3);
+ cdCanvasSetBackground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3));
+ break;
+ case CDMF_FOREGROUND:
+ fscanf(file, "%d %d %d", &iparam1, &iparam2, &iparam3);
+ cdCanvasSetForeground(canvas, cdEncodeColor((unsigned char)iparam1, (unsigned char)iparam2, (unsigned char)iparam3));
+ break;
+ case CDMF_PUTIMAGERGB:
+ fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6);
+ t = iparam1 * iparam2;
+ _red = red = (unsigned char*) malloc(t);
+ _green = green = (unsigned char*) malloc(t);
+ _blue = blue = (unsigned char*) malloc(t);
+ for (c = 0; c < t; c++)
+ {
+ fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9);
+ *_red++ = (unsigned char)iparam7;
+ *_green++ = (unsigned char)iparam8;
+ *_blue++ = (unsigned char)iparam9;
+ }
+ cdCanvasPutImageRectRGB(canvas, iparam1, iparam2, red, green, blue, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0);
+ free(red);
+ free(green);
+ free(blue);
+ break;
+ case CDMF_PUTIMAGERGBA:
+ fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6);
+ t = iparam1 * iparam2;
+ _red = red = (unsigned char*) malloc(t);
+ _green = green = (unsigned char*) malloc(t);
+ _blue = blue = (unsigned char*) malloc(t);
+ _alpha = alpha = (unsigned char*) malloc(t);
+ for (c = 0; c < t; c++)
+ {
+ fscanf(file, "%d %d %d %d", &iparam7, &iparam8, &iparam9, &iparam10);
+ *_red++ = (unsigned char)iparam7;
+ *_green++ = (unsigned char)iparam8;
+ *_blue++ = (unsigned char)iparam9;
+ *_alpha++ = (unsigned char)iparam10;
+ }
+ cdCanvasPutImageRectRGBA(canvas, iparam1, iparam2, red, green, blue, alpha, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0);
+ free(red);
+ free(green);
+ free(blue);
+ free(alpha);
+ break;
+ case CDMF_PUTIMAGEMAP:
+ fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6);
+ t = iparam1 * iparam2;
+ n = 0;
+ _index = index = (unsigned char*) malloc(t);
+ for (c = 0; c < t; c++)
+ {
+ fscanf(file, "%d", &iparam7);
+ *_index++ = (unsigned char)iparam7;
+ if (iparam7 > n)
+ n = iparam7;
+ }
+ _colors = colors = (long int*)malloc(n);
+ for (c = 0; c < n; c++)
+ {
+ fscanf(file, "%d %d %d", &iparam7, &iparam8, &iparam9);
+ *_colors++ = cdEncodeColor((unsigned char)iparam7, (unsigned char)iparam8, (unsigned char)iparam9);
+ }
+ cdCanvasPutImageRectMap(canvas, iparam1, iparam2, index, colors, sScaleX(iparam3), sScaleY(iparam4), sScaleW(iparam5), sScaleH(iparam6), 0, 0, 0, 0);
+ free(index);
+ free(colors);
+ break;
+ case CDMF_PIXEL:
+ fscanf(file, "%d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5);
+ cdCanvasPixel(canvas, sScaleX(iparam1), sScaleY(iparam2), cdEncodeColor((unsigned char)iparam3, (unsigned char)iparam4, (unsigned char)iparam5));
+ break;
+ case CDMF_SCROLLAREA:
+ fscanf(file, "%d %d %d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4, &iparam5, &iparam6);
+ cdCanvasScrollArea(canvas, sScaleX(iparam1), sScaleX(iparam2), sScaleY(iparam3), sScaleY(iparam4), sScaleX(iparam5), sScaleY(iparam6));
+ break;
+ case CDMF_WVECTORTEXT:
+ fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer);
+ wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer);
+ break;
+ case CDMF_WMULTILINEVECTORTEXT:
+ fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer);
+ wdCanvasVectorText(canvas, dparam1, dparam2, TextBuffer);
+ break;
+ case CDMF_VECTORTEXT:
+ fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer);
+ cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer);
+ break;
+ case CDMF_MULTILINEVECTORTEXT:
+ fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer);
+ cdCanvasVectorText(canvas, iparam1, iparam2, TextBuffer);
+ break;
+ case CDMF_WVECTORCHARSIZE:
+ fscanf(file, "%lg", &dparam1);
+ wdCanvasVectorCharSize(canvas, dparam1);
+ break;
+ case CDMF_WVECTORTEXTSIZE:
+ fscanf(file, "%lg %lg %[^\n]", &dparam1, &dparam2, TextBuffer);
+ wdCanvasVectorTextSize(canvas, dparam1, dparam2, TextBuffer);
+ break;
+ case CDMF_WVECTORTEXTDIRECTION:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasVectorTextDirection(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ case CDMF_VECTORCHARSIZE:
+ fscanf(file, "%d", &iparam1);
+ cdCanvasVectorCharSize(canvas, iparam1);
+ break;
+ case CDMF_VECTORTEXTSIZE:
+ fscanf(file, "%d %d %[^\n]", &iparam1, &iparam2, TextBuffer);
+ cdCanvasVectorTextSize(canvas, iparam1, iparam2, TextBuffer);
+ break;
+ case CDMF_VECTORTEXTDIRECTION:
+ fscanf(file, "%d %d %d %d", &iparam1, &iparam2, &iparam3, &iparam4);
+ cdCanvasVectorTextDirection(canvas, iparam1, iparam2, iparam3, iparam4);
+ break;
+ case CDMF_VECTORFONT:
+ fscanf(file, "%[^\n]", TextBuffer);
+ cdCanvasVectorFont(canvas, TextBuffer);
+ break;
+ case CDMF_VECTORTEXTTRANSFORM:
+ fscanf(file, "%lg %lg %lg %lg %lg %lg", &matrix[0], &matrix[1], &matrix[2], &matrix[3], &matrix[4], &matrix[5]);
+ cdCanvasVectorTextTransform(canvas, matrix);
+ break;
+ case CDMF_WINDOW:
+ fscanf(file, "%lg %lg %lg %lg", &dparam1, &dparam2, &dparam3, &dparam4);
+ wdCanvasWindow(canvas, dparam1, dparam2, dparam3, dparam4);
+ break;
+ default:
+ fclose(file);
+ return CD_ERROR;
+ }
+ }
+
+ fclose(file);
+
+ return CD_OK;
+}
+
+/*******************/
+/* Canvas Creation */
+/*******************/
+
+void cdcreatecanvasMF(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);
+
+ 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->ctxcanvas = ctxcanvas;
+
+ ctxcanvas->last_line_style = -1;
+ ctxcanvas->last_fill_mode = -1;
+
+ fprintf(ctxcanvas->file, "CDMF %d %d\n", canvas->w, canvas->h);
+}
+
+void cdinittableMF(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ canvas->cxClear = cdclear;
+ 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->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxScrollArea = cdscrollarea;
+ 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->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxBackOpacity = cdbackopacity;
+ canvas->cxWriteMode = cdwritemode;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxLineCap = cdlinecap;
+ canvas->cxLineJoin = cdlinejoin;
+ canvas->cxInteriorStyle = cdinteriorstyle;
+ canvas->cxHatch = cdhatch;
+ canvas->cxStipple = cdstipple;
+ canvas->cxPattern = cdpattern;
+ canvas->cxFont = cdfont;
+ canvas->cxNativeFont = cdnativefont;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxTextOrientation = cdtextorientation;
+ canvas->cxPalette = cdpalette;
+ canvas->cxBackground = cdbackground;
+ canvas->cxForeground = cdforeground;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxTransform = cdtransform;
+
+ canvas->cxKillCanvas = (void (*)(cdCtxCanvas*))cdkillcanvasMF;
+}
+
+static cdContext cdMetafileContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE),
+ 0,
+ cdcreatecanvasMF,
+ cdinittableMF,
+ cdplay,
+ cdregistercallback,
+};
+
+cdContext* cdContextMetafile(void)
+{
+ return &cdMetafileContext;
+}
diff --git a/src/drv/cdpdf.c b/src/drv/cdpdf.c
new file mode 100644
index 0000000..24509f6
--- /dev/null
+++ b/src/drv/cdpdf.c
@@ -0,0 +1,1491 @@
+/** \file
+ * \brief PDF Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cdpdf.h"
+
+#include "pdflib.h"
+
+
+/*
+** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1.
+*/
+#define get_red(_) (((double)cdRed(_))/255.)
+#define get_green(_) (((double)cdGreen(_))/255.)
+#define get_blue(_) (((double)cdBlue(_))/255.)
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ PDF *pdf; /* Arquivo PDF */
+ int res; /* Resolucao - DPI */
+ int pages; /* Numero total de paginas */
+ double width_pt; /* Largura do papel (points) */
+ double height_pt; /* Altura do papel (points) */
+ double width_mm; /* Largura do papel (mm) */
+ double height_mm; /* Altura do papel (mm) */
+ double scale; /* Fator de conversao de coordenadas (pixel2points) */
+ int landscape; /* page orientation */
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ int font;
+ int underline;
+ int strikeover;
+
+ int hatchboxsize;
+ int pattern;
+ int opacity;
+ int opacity_states[256];
+
+ int poly_holes[500];
+ int holes;
+};
+
+
+/*
+%F Ajusta o tamanho do papel em points.
+*/
+static void setpdfpapersize(cdCtxCanvas* ctxcanvas, int size)
+{
+ static struct
+ {
+ int width;
+ int height;
+ } paper[] =
+ {
+ { 2393, 3391 }, /* A0 */
+ { 1689, 2393 }, /* A1 */
+ { 1192, 1689 }, /* A2 */
+ { 842, 1192 }, /* A3 */
+ { 595, 842 }, /* A4 */
+ { 420, 595 }, /* A5 */
+ { 612, 792 }, /* LETTER */
+ { 612, 1008 } /* LEGAL */
+ };
+
+ if (size<CD_A0 || size>CD_LEGAL)
+ return;
+
+ ctxcanvas->width_pt = paper[size].width;
+ ctxcanvas->height_pt = paper[size].height;
+ ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT;
+ ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT;
+}
+
+/*
+%F Registra os valores default para impressao.
+*/
+static void setpdfdefaultvalues(cdCtxCanvas* ctxcanvas)
+{
+ int i;
+
+ /* all the other values are set to 0 */
+ setpdfpapersize(ctxcanvas, CD_A4);
+ ctxcanvas->res = 300;
+ ctxcanvas->hatchboxsize = 8;
+ ctxcanvas->opacity = 255; /* full opaque */
+
+ for (i=0; i<256; i++)
+ ctxcanvas->opacity_states[i] = -1;
+}
+
+static void update_state(cdCtxCanvas *ctxcanvas)
+{
+ cdCanvas* canvas = ctxcanvas->canvas;
+
+ if (!canvas->cxFont) /* just check if the first time */
+ return;
+
+ /* must set the current transform and line style if different from the default */
+
+ if (canvas->line_style != CD_CONTINUOUS)
+ canvas->cxLineStyle(ctxcanvas, canvas->line_style);
+ if (canvas->line_width != 1)
+ canvas->cxLineWidth(ctxcanvas, canvas->line_width);
+ if (canvas->line_cap != CD_CAPFLAT)
+ canvas->cxLineCap(ctxcanvas, canvas->line_cap);
+ if (canvas->line_join != CD_MITER)
+ canvas->cxLineJoin(ctxcanvas, canvas->line_join);
+ if (canvas->use_matrix)
+ canvas->cxTransform(ctxcanvas, canvas->matrix);
+ canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size);
+}
+
+static void begin_page(cdCtxCanvas *ctxcanvas)
+{
+ PDF_begin_page_ext(ctxcanvas->pdf, ctxcanvas->width_pt, ctxcanvas->height_pt, "");
+
+ /* default coordinate system is in points, change it to pixels. */
+ PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale);
+
+ PDF_save(ctxcanvas->pdf); /* save the initial configuration, to be used when clipping is reset. */
+
+ update_state(ctxcanvas);
+}
+
+static void init_pdf(cdCtxCanvas *ctxcanvas)
+{
+ ctxcanvas->scale = 72.0/ctxcanvas->res;
+
+ /* Converte p/ unidades do usuario */
+ ctxcanvas->canvas->w = (int)(ctxcanvas->width_pt/ctxcanvas->scale + 0.5);
+ ctxcanvas->canvas->h = (int)(ctxcanvas->height_pt/ctxcanvas->scale + 0.5);
+
+ /* Passa o valor em milimetros para o canvas CD */
+ ctxcanvas->canvas->w_mm = ctxcanvas->width_mm;
+ ctxcanvas->canvas->h_mm = ctxcanvas->height_mm;
+
+ ctxcanvas->canvas->bpp = 24;
+ ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm;
+ ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm;
+
+ begin_page(ctxcanvas);
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration. */
+ PDF_end_page_ext(ctxcanvas->pdf, "");
+ PDF_end_document(ctxcanvas->pdf, "");
+ PDF_delete(ctxcanvas->pdf);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void update_fill(cdCtxCanvas *ctxcanvas, int fill)
+{
+ if (fill == 0)
+ {
+ /* called before a NON filled primitive */
+ PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", get_red(ctxcanvas->canvas->foreground),
+ get_green(ctxcanvas->canvas->foreground),
+ get_blue(ctxcanvas->canvas->foreground), 0);
+
+ }
+ else
+ {
+ /* called before a filled primitive */
+ if (ctxcanvas->canvas->interior_style == CD_SOLID)
+ {
+ PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground),
+ get_green(ctxcanvas->canvas->foreground),
+ get_blue(ctxcanvas->canvas->foreground), 0);
+ }
+ else
+ PDF_setcolor(ctxcanvas->pdf, "fill", "pattern", (float)ctxcanvas->pattern, 0, 0, 0);
+ }
+}
+
+/*
+%F Comeca uma nova pagina.
+*/
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ PDF_restore(ctxcanvas->pdf); /* restore to match the save of the initial configuration */
+
+ PDF_end_page_ext(ctxcanvas->pdf, "");
+
+ begin_page(ctxcanvas);
+}
+
+
+/******************************************************/
+/* coordinate transformation */
+/******************************************************/
+
+static void resetcliprect(cdCtxCanvas* ctxcanvas)
+{
+ /* clipping is reset, by restoring the initial state */
+ /* this will also reset the current transformation and line style */
+ PDF_restore(ctxcanvas->pdf);
+ PDF_save(ctxcanvas->pdf);
+
+ update_state(ctxcanvas);
+}
+
+static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax)
+{
+ resetcliprect(ctxcanvas);
+
+ PDF_moveto(ctxcanvas->pdf, xmin, ymin);
+ PDF_lineto(ctxcanvas->pdf, xmax, ymin);
+ PDF_lineto(ctxcanvas->pdf, xmax, ymax);
+ PDF_lineto(ctxcanvas->pdf, xmin, ymax);
+
+ PDF_clip(ctxcanvas->pdf);
+}
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA)
+ return;
+
+ setcliprect(ctxcanvas, xmin, ymin, xmax, ymax);
+}
+
+static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ cdfcliparea(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax);
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ if (mode == CD_CLIPAREA)
+ {
+ ctxcanvas->canvas->clip_mode = CD_CLIPAREA;
+
+ setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin,
+ (double)ctxcanvas->canvas->clip_rect.ymin,
+ (double)ctxcanvas->canvas->clip_rect.xmax,
+ (double)ctxcanvas->canvas->clip_rect.ymax);
+ }
+ else if (mode == CD_CLIPPOLYGON)
+ {
+ int hole_index = 0;
+ int i;
+
+ resetcliprect(ctxcanvas);
+
+ if (ctxcanvas->canvas->clip_poly)
+ {
+ cdPoint *poly = ctxcanvas->canvas->clip_poly;
+
+ PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y);
+
+ for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ }
+ }
+ else if (ctxcanvas->canvas->clip_fpoly)
+ {
+ cdfPoint *poly = ctxcanvas->canvas->clip_fpoly;
+
+ PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y);
+
+ for (i=1; i<ctxcanvas->canvas->clip_poly_n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ }
+ }
+
+ PDF_clip(ctxcanvas->pdf);
+ }
+ else if (mode == CD_CLIPOFF)
+ {
+ resetcliprect(ctxcanvas);
+ }
+
+ return mode;
+}
+
+/******************************************************/
+/* primitives */
+/******************************************************/
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ update_fill(ctxcanvas, 0);
+
+ PDF_moveto(ctxcanvas->pdf, x1, y1);
+ PDF_lineto(ctxcanvas->pdf, x2, y2);
+ PDF_stroke(ctxcanvas->pdf);
+}
+
+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)
+{
+ update_fill(ctxcanvas, 0);
+
+ PDF_rect(ctxcanvas->pdf, xmin, ymin, xmax-xmin, ymax-ymin);
+ PDF_stroke(ctxcanvas->pdf);
+}
+
+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)
+{
+ update_fill(ctxcanvas, 1);
+
+ PDF_moveto(ctxcanvas->pdf, xmin, ymin);
+ PDF_lineto(ctxcanvas->pdf, xmax, ymin);
+ PDF_lineto(ctxcanvas->pdf, xmax, ymax);
+ PDF_lineto(ctxcanvas->pdf, xmin, ymax);
+ PDF_fill(ctxcanvas->pdf);
+}
+
+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)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (w==h)
+ {
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2);
+ PDF_stroke(ctxcanvas->pdf);
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ PDF_save(ctxcanvas->pdf); /* save to use the local transform */
+
+ PDF_translate(ctxcanvas->pdf, xc, yc);
+ PDF_scale(ctxcanvas->pdf, w/h, 1);
+ PDF_translate(ctxcanvas->pdf, -xc, -yc);
+
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2);
+ PDF_stroke(ctxcanvas->pdf);
+
+ PDF_restore(ctxcanvas->pdf); /* restore from local */
+ }
+}
+
+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)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h)
+ {
+ PDF_moveto(ctxcanvas->pdf, xc, yc);
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2);
+ PDF_fill(ctxcanvas->pdf);
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ PDF_save(ctxcanvas->pdf); /* save to use the local transform */
+
+ PDF_translate(ctxcanvas->pdf, xc, yc);
+ PDF_scale(ctxcanvas->pdf, w/h, 1);
+ PDF_translate(ctxcanvas->pdf, -xc, -yc);
+
+ PDF_moveto(ctxcanvas->pdf, xc, yc);
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*h, a1, a2);
+
+ if (ctxcanvas->canvas->interior_style == CD_SOLID ||
+ ctxcanvas->canvas->interior_style == CD_PATTERN)
+ PDF_fill(ctxcanvas->pdf);
+ else
+ {
+ PDF_lineto(ctxcanvas->pdf, xc, yc);
+ PDF_stroke(ctxcanvas->pdf);
+ }
+
+ PDF_restore(ctxcanvas->pdf); /* restore from local */
+ }
+}
+
+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)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h)
+ {
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2);
+ PDF_fill_stroke(ctxcanvas->pdf);
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ PDF_save(ctxcanvas->pdf); /* save to use the local transform */
+
+ /* local transform */
+ PDF_translate(ctxcanvas->pdf, xc, yc);
+ PDF_scale(ctxcanvas->pdf, 1, w/h);
+
+ PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2);
+ PDF_fill_stroke(ctxcanvas->pdf);
+
+ PDF_restore(ctxcanvas->pdf); /* restore from local */
+ }
+}
+
+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 cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent)
+{
+ double fontsize, a, d, linegap;
+
+ if (ctxcanvas->font<0)
+ return;
+
+ fontsize = PDF_get_value(ctxcanvas->pdf, "fontsize", 0);
+ a = PDF_get_value(ctxcanvas->pdf, "ascender", 0);
+ d = PDF_get_value(ctxcanvas->pdf, "descender", 0);
+
+ /* linegap = PDF_info_font(ctxcanvas->pdf, 1, "linegap", ""); - not supported call */
+ linegap = 0.23 * a; /* use default value for linegap */
+ a += linegap;
+ d += linegap; /* since d<0, it is a subtraction */
+
+ a *= fontsize;
+ d *= fontsize;
+
+ if (ascent) *ascent = (int)a;
+ if (descent) *descent = (int)(-d);
+ if (height) *height = (int)(a - d);
+ if (max_width) *max_width = (int)(PDF_info_textline(ctxcanvas->pdf, "W", 0, "width", "")/ctxcanvas->scale);
+}
+
+static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int *width, int *height)
+{
+ if (ctxcanvas->font<0)
+ return;
+ if (height) cdgetfontdim(ctxcanvas, NULL, height, NULL, NULL);
+ if (width) *width = (int)(PDF_info_textline(ctxcanvas->pdf, s, 0, "width", "")/ctxcanvas->scale);
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s)
+{
+ char temp[200], options[200];
+
+ PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground),
+ get_green(ctxcanvas->canvas->foreground),
+ get_blue(ctxcanvas->canvas->foreground), 0);
+
+ strcpy(options, "");
+
+ sprintf(temp, "rotate=%g ", ctxcanvas->canvas->text_orientation);
+ strcat(options, temp);
+
+ if (ctxcanvas->underline != 0)
+ strcat(options, "underline=true ");
+ else
+ strcat(options, "underline=false ");
+
+ if (ctxcanvas->strikeover != 0)
+ strcat(options, "strikeout=true ");
+ else
+ strcat(options, "strikeout=false ");
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_NORTH:
+ sprintf(temp, "position={50 100} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_NORTH_EAST:
+ sprintf(temp, "position={100 100} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_NORTH_WEST:
+ sprintf(temp, "position={0 100} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_EAST:
+ sprintf(temp, "position={100 50} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_WEST:
+ sprintf(temp, "position={0 50} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_CENTER:
+ sprintf(temp, "position={50 50} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_SOUTH_EAST:
+ sprintf(temp, "position={100 0} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_SOUTH:
+ sprintf(temp, "position={50 0} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_SOUTH_WEST:
+ sprintf(temp, "position={0 0} matchbox { boxheight={ascender descender} }");
+ strcat(options, temp);
+ break;
+ case CD_BASE_RIGHT:
+ sprintf(temp, "position={100 0} matchbox { boxheight={ascender none} }");
+ strcat(options, temp);
+ break;
+ case CD_BASE_CENTER:
+ sprintf(temp, "position={50 0} matchbox { boxheight={ascender none} }");
+ strcat(options, temp);
+ break;
+ case CD_BASE_LEFT:
+ sprintf(temp, "position={0 0} matchbox { boxheight={ascender none} }");
+ strcat(options, temp);
+ break;
+ }
+
+ PDF_fit_textline(ctxcanvas->pdf, s, 0, x, y, options);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ cdftext(ctxcanvas, (double)x, (double)y, s);
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ return;
+
+ if (mode == CD_FILL)
+ update_fill(ctxcanvas, 1);
+ else
+ update_fill(ctxcanvas, 0);
+
+ if (mode==CD_FILL)
+ {
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd");
+ else
+ PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding");
+ }
+
+ PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y);
+
+ if (mode == CD_BEZIER)
+ {
+ for (i=1; i<n; i+=3)
+ PDF_curveto(ctxcanvas->pdf, poly[i].x, poly[i].y,
+ poly[i+1].x, poly[i+1].y,
+ poly[i+2].x, poly[i+2].y);
+ }
+ else
+ {
+ int hole_index = 0;
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ }
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ PDF_closepath_stroke(ctxcanvas->pdf);
+ break;
+ case CD_OPEN_LINES :
+ PDF_stroke(ctxcanvas->pdf);
+ break;
+ case CD_BEZIER :
+ PDF_stroke(ctxcanvas->pdf);
+ break;
+ case CD_FILL :
+ PDF_fill(ctxcanvas->pdf);
+ break;
+ }
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ return;
+
+ if (mode == CD_FILL)
+ update_fill(ctxcanvas, 1);
+ else
+ update_fill(ctxcanvas, 0);
+
+ if (mode==CD_FILL)
+ {
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ PDF_set_parameter(ctxcanvas->pdf, "fillrule", "evenodd");
+ else
+ PDF_set_parameter(ctxcanvas->pdf, "fillrule", "winding");
+ }
+
+ PDF_moveto(ctxcanvas->pdf, poly[0].x, poly[0].y);
+
+ if (mode == CD_BEZIER)
+ {
+ for (i=1; i<n; i+=3)
+ PDF_curveto(ctxcanvas->pdf, poly[i].x, poly[i].y,
+ poly[i+1].x, poly[i+1].y,
+ poly[i+2].x, poly[i+2].y);
+ }
+ else
+ {
+ int hole_index = 0;
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ PDF_moveto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ PDF_lineto(ctxcanvas->pdf, poly[i].x, poly[i].y);
+ }
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ PDF_closepath_stroke(ctxcanvas->pdf);
+ break;
+ case CD_OPEN_LINES :
+ PDF_stroke(ctxcanvas->pdf);
+ break;
+ case CD_BEZIER :
+ PDF_stroke(ctxcanvas->pdf);
+ break;
+ case CD_FILL :
+ PDF_fill(ctxcanvas->pdf);
+ break;
+ }
+}
+
+/******************************************************/
+/* attributes */
+/******************************************************/
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ double mm = (72.0/25.4) / ctxcanvas->scale;
+ char options[80];
+
+ switch (style)
+ {
+ case CD_CONTINUOUS : /* empty dash */
+ PDF_setdash(ctxcanvas->pdf, 0, 0);
+ break;
+ case CD_DASHED :
+ PDF_setdash(ctxcanvas->pdf, 3*mm, mm);
+ break;
+ case CD_DOTTED :
+ PDF_setdash(ctxcanvas->pdf, mm, mm);
+ break;
+ case CD_DASH_DOT :
+ sprintf(options, "dasharray={%g %g %g %g}", 3*mm, mm, mm, mm);
+ PDF_setdashpattern(ctxcanvas->pdf, options);
+ break;
+ case CD_DASH_DOT_DOT :
+ sprintf(options, "dasharray={%g %g %g %g %g %g}", 3*mm, mm, mm, mm, mm, mm);
+ PDF_setdashpattern(ctxcanvas->pdf, options);
+ break;
+ case CD_CUSTOM :
+ {
+ int i;
+
+ strcpy(options, "dasharray={");
+ for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++)
+ {
+ char tmp[80];
+ sprintf(tmp, "%g ", ctxcanvas->canvas->line_dashes[i]*mm);
+ strcat(options, tmp);
+ }
+ strcat(options, "}");
+ PDF_setdashpattern(ctxcanvas->pdf, options);
+ }
+ break;
+ }
+
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ if (width==0) width = 1;
+
+ PDF_setlinewidth(ctxcanvas->pdf, width);
+
+ return width;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ int cd2ps_join[] = {0, 2, 1};
+ PDF_setlinejoin(ctxcanvas->pdf, cd2ps_join[join]);
+ return join;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ int cd2pdf_cap[] = {0, 2, 1};
+ PDF_setlinecap(ctxcanvas->pdf, cd2pdf_cap[cap]);
+ return cap;
+}
+
+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;
+
+ PDF_suspend_page(ctxcanvas->pdf, "");
+ ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m,
+ ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1);
+
+ PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale);
+
+ 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;
+ PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0);
+ PDF_rect(ctxcanvas->pdf, i, j, 1, 1);
+ PDF_fill(ctxcanvas->pdf);
+ }
+ }
+
+ PDF_end_pattern(ctxcanvas->pdf);
+ PDF_resume_page(ctxcanvas->pdf, "");
+}
+
+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)
+{
+ 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)
+{
+ make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb);
+}
+
+static void make_hatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ unsigned char r, g, b;
+ int hsize = ctxcanvas->hatchboxsize - 1;
+ int hhalf = hsize / 2;
+
+ PDF_suspend_page(ctxcanvas->pdf, "");
+ ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, hsize + 1, hsize + 1,
+ ((double)hsize)*ctxcanvas->scale, ((double)hsize)*ctxcanvas->scale, 1);
+
+ PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale);
+
+ if (ctxcanvas->canvas->back_opacity==CD_OPAQUE)
+ {
+ cdDecodeColor(ctxcanvas->canvas->background, &r, &g, &b);
+ PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0);
+ PDF_rect(ctxcanvas->pdf, 0, 0, hsize, hsize);
+ PDF_fill(ctxcanvas->pdf);
+ }
+
+ cdDecodeColor(ctxcanvas->canvas->foreground, &r, &g, &b);
+ PDF_setcolor(ctxcanvas->pdf, "stroke", "rgb", ((double)r)/255, ((double)g)/255, ((double)b)/255, 0);
+
+ switch(style)
+ {
+ case CD_HORIZONTAL:
+ PDF_moveto(ctxcanvas->pdf, 0, hhalf);
+ PDF_lineto(ctxcanvas->pdf, hsize, hhalf);
+ break;
+ case CD_VERTICAL:
+ PDF_moveto(ctxcanvas->pdf, hhalf, 0);
+ PDF_lineto(ctxcanvas->pdf, hhalf, hsize);
+ break;
+ case CD_BDIAGONAL:
+ PDF_moveto(ctxcanvas->pdf, 0, hsize);
+ PDF_lineto(ctxcanvas->pdf, hsize, 0);
+ break;
+ case CD_FDIAGONAL:
+ PDF_moveto(ctxcanvas->pdf, 0, 0);
+ PDF_lineto(ctxcanvas->pdf, hsize, hsize);
+ break;
+ case CD_CROSS:
+ PDF_moveto(ctxcanvas->pdf, hsize, 0);
+ PDF_lineto(ctxcanvas->pdf, hsize, hsize);
+ PDF_moveto(ctxcanvas->pdf, 0, hhalf);
+ PDF_lineto(ctxcanvas->pdf, hsize, hhalf);
+ break;
+ case CD_DIAGCROSS:
+ PDF_moveto(ctxcanvas->pdf, 0, 0);
+ PDF_lineto(ctxcanvas->pdf, hsize, hsize);
+ PDF_moveto(ctxcanvas->pdf, hsize, 0);
+ PDF_lineto(ctxcanvas->pdf, 0, hsize);
+ break;
+ }
+
+ PDF_stroke(ctxcanvas->pdf);
+
+ PDF_end_pattern(ctxcanvas->pdf);
+ PDF_resume_page(ctxcanvas->pdf, "");
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ make_hatch(ctxcanvas, style);
+ return style;
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ int newfont, sizepixel;
+ char nativefontname[1024];
+ const char* options = "";
+
+ if (cdStrEqualNoCase(type_face, "System"))
+ type_face = "Courier";
+
+ strcpy(nativefontname, type_face);
+
+ if (cdStrEqualNoCase(type_face, "Courier") ||
+ cdStrEqualNoCase(type_face, "Helvetica"))
+ {
+ if (style&CD_BOLD && style&CD_ITALIC)
+ strcat(nativefontname, "-BoldOblique");
+ else
+ {
+ if (style&CD_BOLD)
+ strcat(nativefontname, "-Bold");
+
+ if (style&CD_ITALIC)
+ strcat(nativefontname, "-Oblique");
+ }
+ }
+ else if (cdStrEqualNoCase(type_face, "Times"))
+ {
+ if ((style&3) == CD_PLAIN)
+ strcat(nativefontname, "-Roman");
+ if (style&CD_BOLD && style&CD_ITALIC)
+ strcat(nativefontname, "-BoldItalic");
+ else
+ {
+ if (style&CD_BOLD)
+ strcat(nativefontname, "-Bold");
+
+ if (style&CD_ITALIC)
+ strcat(nativefontname, "-Italic");
+ }
+ }
+ else
+ {
+ switch(style&3)
+ {
+ case CD_PLAIN:
+ options = "fontstyle=normal";
+ break;
+ case CD_BOLD:
+ options = "fontstyle=bold";
+ break;
+ case CD_ITALIC:
+ options = "fontstyle=italic";
+ break;
+ case CD_BOLD_ITALIC:
+ options = "fontstyle=bolditalic";
+ break;
+ }
+ }
+
+ newfont = PDF_load_font(ctxcanvas->pdf, nativefontname, 0, "auto", options);
+ if (newfont<0)
+ {
+ /* must reload the previous one */
+ return 0;
+ }
+ ctxcanvas->font = newfont;
+
+ sizepixel = cdGetFontSizePixels(ctxcanvas->canvas, size);
+ PDF_setfont(ctxcanvas->pdf, ctxcanvas->font, sizepixel);
+
+ if (style&CD_UNDERLINE)
+ ctxcanvas->underline = 1;
+ else
+ ctxcanvas->underline = 0;
+
+ if (style&CD_STRIKEOUT)
+ ctxcanvas->strikeover = 1;
+ else
+ ctxcanvas->strikeover = 0;
+
+ return 1;
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0);
+
+ /* default coordinate system is in points, change it to pixels. */
+ PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale);
+
+ if (matrix)
+ {
+ PDF_concat(ctxcanvas->pdf, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ }
+ else if (ctxcanvas->rotate_angle)
+ {
+ /* rotation = translate to point + rotation + translate back */
+ PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle);
+ PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+}
+
+/******************************************************/
+/* client images */
+/******************************************************/
+
+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, image, rw, rh, rgb_size;
+ char options[80];
+ unsigned char* rgb_data;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ rgb_size = 3*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++;
+ }
+
+ PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, "");
+
+ sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh);
+ image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options);
+
+ sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h);
+ PDF_fit_image(ctxcanvas->pdf, image, x, y, options);
+
+ PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0);
+ free(rgb_data);
+}
+
+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, image, image_mask, rw, rh, alpha_size, rgb_size;
+ char options[80];
+ unsigned char *rgb_data, *alpha_data;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ rgb_size = 3*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++;
+ }
+
+ alpha_size = rw*rh;
+ alpha_data = (unsigned char*)malloc(alpha_size);
+ if (!alpha_data) return;
+
+ d = 0;
+ for (i=ymax; i>=ymin; i--)
+ for (j=xmin; j<=xmax; j++)
+ {
+ alpha_data[d] = a[i*iw+j]; d++;
+ }
+
+ PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, "");
+ PDF_create_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0, alpha_data, alpha_size, "");
+
+ sprintf(options, "width=%d height=%d components=1 bpc=8 imagewarning=true", rw, rh);
+ image_mask = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_alpha", 0, options);
+
+ sprintf(options, "width=%d height=%d components=3 bpc=8 masked=%d", rw, rh, image_mask);
+ image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options);
+
+ sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h);
+ PDF_fit_image(ctxcanvas->pdf, image, x, y, options);
+
+ PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_alpha", 0);
+ free(alpha_data);
+ PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0);
+ free(rgb_data);
+}
+
+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, image, rgb_size;
+ char options[80];
+ unsigned char* rgb_data;
+
+ if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ rgb_size = 3*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++;
+ }
+
+ PDF_create_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0, rgb_data, rgb_size, "");
+
+ sprintf(options, "width=%d height=%d components=3 bpc=8", rw, rh);
+ image = PDF_load_image(ctxcanvas->pdf, "raw", "cd_raw_rgb", 0, options);
+
+ sprintf(options, "boxsize={%d %d} fitmethod=meet", w, h);
+ PDF_fit_image(ctxcanvas->pdf, image, x, y, options);
+
+ PDF_delete_pvf(ctxcanvas->pdf, "cd_raw_rgb", 0);
+ free(rgb_data);
+}
+
+/******************************************************/
+/* server images */
+/******************************************************/
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(color), get_green(color), get_blue(color), 0);
+
+ PDF_moveto(ctxcanvas->pdf, x, y);
+ PDF_circle(ctxcanvas->pdf, x, y, .5);
+
+ PDF_fill(ctxcanvas->pdf);
+}
+
+/******************************************************/
+/* custom attributes */
+/******************************************************/
+
+static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int hole;
+
+ if (data == NULL)
+ {
+ ctxcanvas->holes = 0;
+ return;
+ }
+
+ sscanf(data, "%d", &hole);
+ ctxcanvas->poly_holes[ctxcanvas->holes] = hole;
+ ctxcanvas->holes++;
+}
+
+static char* get_poly_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char holes[10];
+ sprintf(holes, "%d", ctxcanvas->holes);
+ return holes;
+}
+
+static cdAttribute poly_attrib =
+{
+ "POLYHOLE",
+ set_poly_attrib,
+ get_poly_attrib
+};
+
+static void set_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int hatchboxsize;
+
+ if (data == NULL)
+ {
+ ctxcanvas->hatchboxsize = 8;
+ return;
+ }
+
+ sscanf(data, "%d", &hatchboxsize);
+ ctxcanvas->hatchboxsize = hatchboxsize;
+}
+
+static char* get_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char size[10];
+ sprintf(size, "%d", ctxcanvas->hatchboxsize);
+ return size;
+}
+
+static cdAttribute hatchboxsize_attrib =
+{
+ "HATCHBOXSIZE",
+ set_hatchboxsize_attrib,
+ get_hatchboxsize_attrib
+};
+
+static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ /* ignore ROTATE if transform is set */
+ if (ctxcanvas->canvas->use_matrix)
+ return;
+
+ if (data)
+ {
+ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle,
+ &ctxcanvas->rotate_center_x,
+ &ctxcanvas->rotate_center_y);
+ }
+ else
+ {
+ ctxcanvas->rotate_angle = 0;
+ ctxcanvas->rotate_center_x = 0;
+ ctxcanvas->rotate_center_y = 0;
+ }
+
+ PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0);
+
+ if (ctxcanvas->rotate_angle)
+ {
+ /* rotation = translate to point + rotation + translate back */
+ PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle);
+ PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+}
+
+static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char data[100];
+
+ if (!ctxcanvas->rotate_angle)
+ return NULL;
+
+ sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle,
+ ctxcanvas->rotate_center_x,
+ ctxcanvas->rotate_center_y);
+
+ return data;
+}
+
+static cdAttribute rotate_attrib =
+{
+ "ROTATE",
+ set_rotate_attrib,
+ get_rotate_attrib
+};
+
+static void set_pattern_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ if (data)
+ {
+ int n, m;
+ sscanf(data, "%dx%d", &n, &m);
+
+ PDF_suspend_page(ctxcanvas->pdf, "");
+ ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m,
+ ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1);
+ PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale);
+ }
+ else
+ {
+ PDF_end_pattern(ctxcanvas->pdf);
+ PDF_resume_page(ctxcanvas->pdf, "");
+ ctxcanvas->canvas->interior_style = CD_PATTERN;
+ }
+}
+
+static cdAttribute pattern_attrib =
+{
+ "PATTERN",
+ set_pattern_attrib,
+ NULL
+};
+
+static void set_opacity_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int state;
+
+ if (data)
+ {
+ sscanf(data, "%d", &ctxcanvas->opacity);
+ if (ctxcanvas->opacity < 0) ctxcanvas->opacity = 0;
+ if (ctxcanvas->opacity > 255) ctxcanvas->opacity = 255;
+ }
+ else
+ ctxcanvas->opacity = 255;
+
+ /* reuse the extended graphics state if the opacity is the same */
+ if (ctxcanvas->opacity_states[ctxcanvas->opacity] == -1)
+ {
+ char options[50];
+ sprintf(options, "opacityfill=%g opacitystroke=%g", ctxcanvas->opacity/255.0, ctxcanvas->opacity/255.0);
+ state = PDF_create_gstate(ctxcanvas->pdf, options);
+ ctxcanvas->opacity_states[ctxcanvas->opacity] = state;
+ }
+ else
+ state = ctxcanvas->opacity_states[ctxcanvas->opacity];
+
+ PDF_set_gstate(ctxcanvas->pdf, state);
+}
+
+static char* get_opacity_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char data[50];
+ sprintf(data, "%d", ctxcanvas->opacity);
+ return data;
+}
+
+static cdAttribute opacity_attrib =
+{
+ "OPACITY",
+ set_opacity_attrib,
+ get_opacity_attrib
+};
+
+static char* get_pdf_attrib(cdCtxCanvas *ctxcanvas)
+{
+ return (char*)ctxcanvas->pdf;
+}
+
+static cdAttribute pdf_attrib =
+{
+ "PDF",
+ NULL,
+ get_pdf_attrib
+};
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char *line = (char *)data;
+ cdCtxCanvas *ctxcanvas;
+ char filename[10240] = "";
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ line += cdGetFileName(line, filename);
+ if (filename[0] == 0)
+ return;
+
+ ctxcanvas->pdf = PDF_new();
+ if (!ctxcanvas->pdf)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ if (PDF_begin_document(ctxcanvas->pdf, filename, 0, "") == -1)
+ {
+ PDF_delete(ctxcanvas->pdf);
+ free(ctxcanvas);
+ return;
+ }
+
+ PDF_set_parameter(ctxcanvas->pdf, "fontwarning", "false");
+ PDF_set_parameter(ctxcanvas->pdf, "errorpolicy", "return");
+
+ cdRegisterAttribute(canvas, &poly_attrib);
+ cdRegisterAttribute(canvas, &hatchboxsize_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+ cdRegisterAttribute(canvas, &opacity_attrib);
+ cdRegisterAttribute(canvas, &pattern_attrib);
+ cdRegisterAttribute(canvas, &pdf_attrib);
+
+ setpdfdefaultvalues(ctxcanvas);
+
+ while (*line != '\0')
+ {
+ while (*line != '\0' && *line != '-')
+ line++;
+
+ if (*line != '\0')
+ {
+ float num;
+ line++;
+ switch (*line++)
+ {
+ case 'p':
+ {
+ int paper;
+ sscanf(line, "%d", &paper);
+ setpdfpapersize(ctxcanvas, paper);
+ break;
+ }
+ case 'w':
+ sscanf(line, "%g", &num);
+ ctxcanvas->width_mm = num;
+ ctxcanvas->width_pt = CD_MM2PT*ctxcanvas->width_mm;
+ break;
+ case 'h':
+ sscanf(line, "%g", &num);
+ ctxcanvas->height_mm = num;
+ ctxcanvas->height_pt = CD_MM2PT*ctxcanvas->height_mm;
+ break;
+ case 's':
+ sscanf(line, "%d", &(ctxcanvas->res));
+ break;
+ case 'o':
+ ctxcanvas->landscape = 1;
+ break;
+ }
+ }
+
+ while (*line != '\0' && *line != ' ')
+ line++;
+ }
+
+ /* store the base canvas */
+ ctxcanvas->canvas = canvas;
+
+ /* update canvas context */
+ canvas->ctxcanvas = ctxcanvas;
+
+ if (ctxcanvas->landscape == 1)
+ {
+ _cdSwapDouble(ctxcanvas->width_pt, ctxcanvas->height_pt);
+ _cdSwapDouble(ctxcanvas->width_mm, ctxcanvas->height_mm);
+ }
+
+ init_pdf(ctxcanvas);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ 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->cxFLine = cdfline;
+ canvas->cxFPoly = cdfpoly;
+ canvas->cxFRect = cdfrect;
+ canvas->cxFBox = cdfbox;
+ canvas->cxFArc = cdfarc;
+ canvas->cxFSector = cdfsector;
+ canvas->cxFChord = cdfchord;
+ canvas->cxFText = cdftext;
+ canvas->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxLineCap = cdlinecap;
+ canvas->cxLineJoin = cdlinejoin;
+ canvas->cxPattern = cdpattern;
+ canvas->cxStipple = cdstipple;
+ canvas->cxHatch = cdhatch;
+ canvas->cxFont = cdfont;
+ canvas->cxTransform = cdtransform;
+
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdPDFContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE |
+ CD_CAP_REGION | CD_CAP_IMAGESRV | CD_CAP_TEXTSIZE |
+ CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextPDF(void)
+{
+ return &cdPDFContext;
+}
+
+/*
+p.set_info("Creator", "PDFlib Cookbook")
+*/
diff --git a/src/drv/cdpicture.c b/src/drv/cdpicture.c
new file mode 100644
index 0000000..9bc5104
--- /dev/null
+++ b/src/drv/cdpicture.c
@@ -0,0 +1,1133 @@
+/** \file
+ * \brief CD Picture driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <math.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cdpicture.h"
+
+
+/* codes for the primitives.
+*/
+typedef enum _tPrim
+{
+ CDPIC_LINE,
+ CDPIC_RECT,
+ CDPIC_BOX,
+ CDPIC_ARC,
+ CDPIC_SECTOR,
+ CDPIC_CHORD,
+ CDPIC_TEXT,
+ CDPIC_POLY,
+ CDPIC_FLINE,
+ CDPIC_FRECT,
+ CDPIC_FBOX,
+ CDPIC_FARC,
+ CDPIC_FSECTOR,
+ CDPIC_FCHORD,
+ CDPIC_FTEXT,
+ CDPIC_FPOLY,
+ CDPIC_PIXEL,
+ CDPIC_IMAGEMAP,
+ CDPIC_IMAGERGB,
+ CDPIC_IMAGERGBA,
+} tPrim;
+
+typedef struct _tFillAttrib
+{
+ long foreground, background;
+ int back_opacity;
+ int interior_style, hatch_style;
+ int fill_mode;
+ int pattern_w, pattern_h;
+ long* pattern;
+ int stipple_w, stipple_h;
+ unsigned char* stipple;
+} tFillAttrib;
+
+typedef struct _tLineAttrib
+{
+ long foreground, background;
+ int back_opacity;
+ int line_style, line_width;
+ int line_cap, line_join;
+ int* line_dashes;
+ int line_dashes_count;
+} tLineAttrib;
+
+typedef struct _tTextAttrib
+{
+ long foreground;
+ char* font_type_face;
+ int font_style, font_size;
+ int text_alignment;
+ double text_orientation;
+ char* native_font;
+} tTextAttrib;
+
+typedef struct _tLBR
+{
+ int x1, y1, x2, y2;
+} tLBR; /* Line or Box or Rect */
+
+typedef struct _tfLBR
+{
+ double x1, y1, x2, y2;
+} tfLBR; /* Line or Box or Rect */
+
+typedef struct _tASC
+{
+ int xc, yc, w, h;
+ double angle1, angle2;
+} tASC; /* Arc or Sector or Chord */
+
+typedef struct _tfASC
+{
+ double xc, yc, w, h;
+ double angle1, angle2;
+} tfASC; /* Arc or Sector or Chord */
+
+typedef struct _tPoly
+{
+ int mode;
+ int n;
+ cdPoint* points;
+} tPoly; /* Begin, Vertex and End */
+
+typedef struct _tfPoly
+{
+ int mode;
+ int n;
+ cdfPoint* points;
+} tfPoly; /* Begin, Vertex and End */
+
+typedef struct _tText
+{
+ int x, y;
+ char *s;
+} tText; /* Text */
+
+typedef struct _tfText
+{
+ double x, y;
+ char *s;
+} tfText; /* Text */
+
+typedef struct _tPixel
+{
+ int x, y;
+ long color;
+} tPixel; /* Pixel */
+
+typedef struct _tImageMap
+{
+ int iw, ih;
+ unsigned char *index;
+ long int *colors;
+ int x, y, w, h;
+} tImageMap;
+
+typedef struct _tImageRGBA
+{
+ int iw, ih;
+ unsigned char *r;
+ unsigned char *g;
+ unsigned char *b;
+ unsigned char *a;
+ int x, y, w, h;
+} tImageRGBA;
+
+typedef struct _tPrimNode
+{
+ tPrim type;
+ void* param_buffer; /* dinamically allocated memory for the parameter */
+ union {
+ tLBR lineboxrect;
+ tfLBR lineboxrectf;
+ tASC arcsectorchord;
+ tfASC arcsectorchordf;
+ tPoly poly;
+ tfPoly polyf;
+ tText text;
+ tfText textf;
+ tPixel pixel;
+ tImageMap imagemap;
+ tImageRGBA imagergba;
+ } param;
+ void* attrib_buffer; /* dinamically allocated memory for the attributes */
+ union {
+ tLineAttrib line;
+ tFillAttrib fill;
+ tTextAttrib text;
+ } attrib;
+ struct _tPrimNode *next;
+} tPrimNode;
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ /* primitives list */
+ tPrimNode *prim_first,
+ *prim_last;
+ int prim_n;
+
+ /* bounding box */
+ int xmin, xmax,
+ ymin, ymax;
+};
+
+static void picUpdateSize(cdCtxCanvas *ctxcanvas)
+{
+ ctxcanvas->canvas->w = ctxcanvas->xmax-ctxcanvas->xmin+1;
+ ctxcanvas->canvas->h = ctxcanvas->ymax-ctxcanvas->ymin+1;
+ ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres;
+ ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres;
+}
+
+static void picUpdateBBox(cdCtxCanvas *ctxcanvas, int x, int y, int ew)
+{
+ if (x+ew > ctxcanvas->xmax)
+ ctxcanvas->xmax = x+ew;
+ if (y+ew > ctxcanvas->ymax)
+ ctxcanvas->ymax = y+ew;
+ if (x-ew < ctxcanvas->xmin)
+ ctxcanvas->xmin = x-ew;
+ if (y-ew < ctxcanvas->ymin)
+ ctxcanvas->ymin = y-ew;
+
+ picUpdateSize(ctxcanvas);
+}
+
+static void picUpdateBBoxF(cdCtxCanvas *ctxcanvas, double x, double y, int ew)
+{
+ if ((int)ceil(x+ew) > ctxcanvas->xmax)
+ ctxcanvas->xmax = (int)ceil(x+ew);
+ if ((int)ceil(y+ew) > ctxcanvas->ymax)
+ ctxcanvas->ymax = (int)ceil(y+ew);
+ if ((int)floor(x-ew) < ctxcanvas->xmin)
+ ctxcanvas->xmin = (int)floor(x-ew);
+ if ((int)floor(y-ew) < ctxcanvas->ymin)
+ ctxcanvas->ymin = (int)floor(y-ew);
+
+ picUpdateSize(ctxcanvas);
+}
+
+static void picAddPrim(cdCtxCanvas *ctxcanvas, tPrimNode *prim)
+{
+ if (ctxcanvas->prim_n == 0)
+ ctxcanvas->prim_first = prim;
+ else
+ ctxcanvas->prim_last->next = prim;
+
+ ctxcanvas->prim_last = prim;
+ ctxcanvas->prim_n++;
+}
+
+static tPrimNode* primCreate(tPrim type)
+{
+ tPrimNode *prim = malloc(sizeof(tPrimNode));
+ memset(prim, 0, sizeof(tPrimNode));
+ prim->type = type;
+ return prim;
+}
+
+static void primDestroy(tPrimNode *prim)
+{
+ if (prim->param_buffer)
+ free(prim->param_buffer);
+ if (prim->attrib_buffer)
+ free(prim->attrib_buffer);
+ free(prim);
+}
+
+static void primAddAttrib_Line(tPrimNode *prim, cdCanvas *canvas)
+{
+ prim->attrib.line.foreground = canvas->foreground;
+ prim->attrib.line.background = canvas->background;
+ prim->attrib.line.back_opacity = canvas->back_opacity;
+ prim->attrib.line.line_style = canvas->line_style;
+ prim->attrib.line.line_width = canvas->line_width;
+ prim->attrib.line.line_cap = canvas->line_cap;
+ prim->attrib.line.line_join = canvas->line_join;
+
+ if (canvas->line_style==CD_CUSTOM && canvas->line_dashes)
+ {
+ prim->attrib.line.line_dashes_count = canvas->line_dashes_count;
+ prim->attrib_buffer = malloc(canvas->line_dashes_count*sizeof(int));
+ prim->attrib.line.line_dashes = prim->attrib_buffer;
+ memcpy(prim->attrib.line.line_dashes, canvas->line_dashes, canvas->line_dashes_count*sizeof(int));
+ }
+}
+
+static void primAddAttrib_Fill(tPrimNode *prim, cdCanvas *canvas)
+{
+ prim->attrib.fill.foreground = canvas->foreground;
+ prim->attrib.fill.background = canvas->background;
+ prim->attrib.fill.back_opacity = canvas->back_opacity;
+ prim->attrib.fill.interior_style = canvas->interior_style;
+ prim->attrib.fill.hatch_style = canvas->hatch_style;
+ prim->attrib.fill.fill_mode = canvas->fill_mode;
+ prim->attrib.fill.pattern_w = canvas->pattern_w;
+ prim->attrib.fill.pattern_h = canvas->pattern_h;
+ prim->attrib.fill.stipple_w = canvas->stipple_w;
+ prim->attrib.fill.stipple_h = canvas->stipple_h;
+
+ if (canvas->interior_style==CD_PATTERN && canvas->pattern)
+ {
+ prim->attrib_buffer = malloc(canvas->pattern_size*sizeof(long));
+ prim->attrib.fill.pattern = prim->attrib_buffer;
+ memcpy(prim->attrib.fill.pattern, canvas->pattern, canvas->pattern_size*sizeof(long));
+ }
+
+ if (canvas->interior_style==CD_STIPPLE && canvas->stipple)
+ {
+ prim->attrib_buffer = malloc(canvas->stipple_size*sizeof(long));
+ prim->attrib.fill.stipple = prim->attrib_buffer;
+ memcpy(prim->attrib.fill.stipple, canvas->stipple, canvas->stipple_size*sizeof(long));
+ }
+}
+
+static void primAddAttrib_Text(tPrimNode *prim, cdCanvas *canvas)
+{
+ prim->attrib.text.foreground = canvas->foreground;
+
+ prim->attrib.text.font_style = canvas->font_style;
+ prim->attrib.text.font_size = canvas->font_size;
+ prim->attrib.text.text_alignment = canvas->text_alignment;
+ prim->attrib.text.text_orientation = canvas->text_orientation;
+
+ if (canvas->native_font[0])
+ {
+ prim->attrib_buffer = strdup(canvas->native_font);
+ prim->attrib.text.native_font = prim->attrib_buffer;
+ }
+ else
+ {
+ prim->attrib_buffer = strdup(canvas->font_type_face);
+ prim->attrib.text.font_type_face = prim->attrib_buffer;
+ }
+}
+
+static void primUpdateAttrib_Line(tPrimNode *prim, cdCanvas *canvas)
+{
+ cdCanvasSetBackground(canvas, prim->attrib.line.background);
+ cdCanvasSetForeground(canvas, prim->attrib.line.foreground);
+ cdCanvasBackOpacity(canvas, prim->attrib.line.back_opacity);
+ cdCanvasLineStyle(canvas, prim->attrib.line.line_style);
+ cdCanvasLineWidth(canvas, prim->attrib.line.line_width);
+ cdCanvasLineCap(canvas, prim->attrib.line.line_cap);
+ cdCanvasLineJoin(canvas, prim->attrib.line.line_join);
+
+ if (prim->attrib.line.line_style==CD_CUSTOM && prim->attrib.line.line_dashes)
+ cdCanvasLineStyleDashes(canvas, prim->attrib.line.line_dashes, prim->attrib.line.line_dashes_count);
+}
+
+void primUpdateAttrib_Fill(tPrimNode *prim, cdCanvas *canvas)
+{
+ cdCanvasSetBackground(canvas, prim->attrib.fill.background);
+ cdCanvasSetForeground(canvas, prim->attrib.fill.foreground);
+ cdCanvasBackOpacity(canvas, prim->attrib.fill.back_opacity);
+ cdCanvasFillMode(canvas, prim->attrib.fill.fill_mode);
+
+ if (prim->attrib.fill.interior_style==CD_HATCH)
+ cdCanvasHatch(canvas, prim->attrib.fill.hatch_style);
+ else if (prim->attrib.fill.interior_style==CD_PATTERN && prim->attrib.fill.pattern)
+ cdCanvasPattern(canvas, prim->attrib.fill.pattern_w, prim->attrib.fill.pattern_h, prim->attrib.fill.pattern);
+ else if (prim->attrib.fill.interior_style==CD_STIPPLE && prim->attrib.fill.stipple)
+ cdCanvasStipple(canvas, prim->attrib.fill.stipple_w, prim->attrib.fill.stipple_h, prim->attrib.fill.stipple);
+
+ cdCanvasInteriorStyle(canvas, prim->attrib.fill.interior_style);
+}
+
+void primUpdateAttrib_Text(tPrimNode *prim, cdCanvas *canvas)
+{
+ cdCanvasSetForeground(canvas, prim->attrib.text.foreground);
+ cdCanvasTextAlignment(canvas, prim->attrib.text.text_alignment);
+ cdCanvasTextOrientation(canvas, prim->attrib.text.text_orientation);
+
+ if (canvas->native_font[0])
+ cdCanvasNativeFont(canvas, prim->attrib.text.native_font);
+ else
+ cdCanvasFont(canvas, prim->attrib.text.font_type_face, prim->attrib.text.font_style, prim->attrib.text.font_size);
+}
+
+static void cdclear(cdCtxCanvas *ctxcanvas)
+{
+ tPrimNode *prim;
+ int i;
+ for (i = 0; i < ctxcanvas->prim_n; i++)
+ {
+ prim = ctxcanvas->prim_first;
+ ctxcanvas->prim_first = prim->next;
+
+ primDestroy(prim);
+ }
+
+ ctxcanvas->prim_n = 0;
+ ctxcanvas->prim_first = NULL;
+ ctxcanvas->prim_last = NULL;
+}
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ tPrimNode *prim = primCreate(CDPIC_PIXEL);
+ prim->param.pixel.x = x;
+ prim->param.pixel.y = y;
+ prim->param.pixel.color = color;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBox(ctxcanvas, x, y, 0);
+}
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ tPrimNode *prim = primCreate(CDPIC_LINE);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.lineboxrect.x1 = x1;
+ prim->param.lineboxrect.y1 = y1;
+ prim->param.lineboxrect.x2 = x2;
+ prim->param.lineboxrect.y2 = y2;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBox(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width);
+ picUpdateBBox(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width);
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ tPrimNode *prim = primCreate(CDPIC_FLINE);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.lineboxrectf.x1 = x1;
+ prim->param.lineboxrectf.y1 = y1;
+ prim->param.lineboxrectf.x2 = x2;
+ prim->param.lineboxrectf.y2 = y2;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBoxF(ctxcanvas, x1, y1, ctxcanvas->canvas->line_width);
+ picUpdateBBoxF(ctxcanvas, x2, y2, ctxcanvas->canvas->line_width);
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ tPrimNode *prim = primCreate(CDPIC_RECT);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.lineboxrect.x1 = xmin;
+ prim->param.lineboxrect.y1 = ymin;
+ prim->param.lineboxrect.x2 = xmax;
+ prim->param.lineboxrect.y2 = ymax;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width);
+ picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width);
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ tPrimNode *prim = primCreate(CDPIC_FRECT);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.lineboxrectf.x1 = xmin;
+ prim->param.lineboxrectf.y1 = ymin;
+ prim->param.lineboxrectf.x2 = xmax;
+ prim->param.lineboxrectf.y2 = ymax;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBoxF(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width);
+ picUpdateBBoxF(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width);
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ tPrimNode *prim = primCreate(CDPIC_BOX);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.lineboxrect.x1 = xmin;
+ prim->param.lineboxrect.y1 = ymin;
+ prim->param.lineboxrect.x2 = xmax;
+ prim->param.lineboxrect.y2 = ymax;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ tPrimNode *prim = primCreate(CDPIC_FBOX);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.lineboxrectf.x1 = xmin;
+ prim->param.lineboxrectf.y1 = ymin;
+ prim->param.lineboxrectf.x2 = xmax;
+ prim->param.lineboxrectf.y2 = ymax;
+ picAddPrim(ctxcanvas, prim);
+ picUpdateBBoxF(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBoxF(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_ARC);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchord.xc = xc;
+ prim->param.arcsectorchord.yc = yc;
+ prim->param.arcsectorchord.w = w;
+ prim->param.arcsectorchord.h = h;
+ prim->param.arcsectorchord.angle1 = a1;
+ prim->param.arcsectorchord.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width);
+ picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width);
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_FARC);
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchordf.xc = xc;
+ prim->param.arcsectorchordf.yc = yc;
+ prim->param.arcsectorchordf.w = w;
+ prim->param.arcsectorchordf.h = h;
+ prim->param.arcsectorchordf.angle1 = a1;
+ prim->param.arcsectorchordf.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, ctxcanvas->canvas->line_width);
+ picUpdateBBox(ctxcanvas, xmax, ymax, ctxcanvas->canvas->line_width);
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_SECTOR);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchord.xc = xc;
+ prim->param.arcsectorchord.yc = yc;
+ prim->param.arcsectorchord.w = w;
+ prim->param.arcsectorchord.h = h;
+ prim->param.arcsectorchord.angle1 = a1;
+ prim->param.arcsectorchord.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+ picUpdateBBox(ctxcanvas, xc, yc, 0);
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_FSECTOR);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchordf.xc = xc;
+ prim->param.arcsectorchordf.yc = yc;
+ prim->param.arcsectorchordf.w = w;
+ prim->param.arcsectorchordf.h = h;
+ prim->param.arcsectorchordf.angle1 = a1;
+ prim->param.arcsectorchordf.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+ picUpdateBBox(ctxcanvas, _cdRound(xc), _cdRound(yc), 0);
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_CHORD);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchord.xc = xc;
+ prim->param.arcsectorchord.yc = yc;
+ prim->param.arcsectorchord.w = w;
+ prim->param.arcsectorchord.h = h;
+ prim->param.arcsectorchord.angle1 = a1;
+ prim->param.arcsectorchord.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_FCHORD);
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ prim->param.arcsectorchordf.xc = xc;
+ prim->param.arcsectorchordf.yc = yc;
+ prim->param.arcsectorchordf.w = w;
+ prim->param.arcsectorchordf.h = h;
+ prim->param.arcsectorchordf.angle1 = a1;
+ prim->param.arcsectorchordf.angle2 = a2;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *text)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_TEXT);
+ primAddAttrib_Text(prim, ctxcanvas->canvas);
+ prim->param.text.x = x;
+ prim->param.text.y = y;
+ prim->param.text.s = strdup(text);
+ prim->param_buffer = prim->param.text.s;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetTextBox(ctxcanvas->canvas, x, y, text, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *text)
+{
+ int xmin, xmax, ymin, ymax;
+ tPrimNode *prim = primCreate(CDPIC_FTEXT);
+ primAddAttrib_Text(prim, ctxcanvas->canvas);
+ prim->param.textf.x = x;
+ prim->param.textf.y = y;
+ prim->param.textf.s = strdup(text);
+ prim->param_buffer = prim->param.textf.s;
+ picAddPrim(ctxcanvas, prim);
+ cdCanvasGetTextBox(ctxcanvas->canvas, _cdRound(x), _cdRound(y), text, &xmin, &xmax, &ymin, &ymax);
+ picUpdateBBox(ctxcanvas, xmin, ymin, 0);
+ picUpdateBBox(ctxcanvas, xmax, ymax, 0);
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+ tPrimNode *prim;
+ if (mode == CD_CLIP || mode == CD_REGION) return;
+ prim = primCreate(CDPIC_POLY);
+ if (mode == CD_FILL)
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ else
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.poly.n = n;
+ prim->param.poly.points = malloc(n * sizeof(cdPoint));
+ memcpy(prim->param.poly.points, poly, n * sizeof(cdPoint));
+ prim->param_buffer = prim->param.poly.points;
+ picAddPrim(ctxcanvas, prim);
+
+ for (i = 0; i < n; i++)
+ {
+ if (mode == CD_FILL)
+ picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, 0);
+ else
+ picUpdateBBox(ctxcanvas, poly[i].x, poly[i].y, ctxcanvas->canvas->line_width);
+ }
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i;
+ tPrimNode *prim;
+ if (mode == CD_CLIP || mode == CD_REGION) return;
+ prim = primCreate(CDPIC_FPOLY);
+ if (mode == CD_FILL)
+ primAddAttrib_Fill(prim, ctxcanvas->canvas);
+ else
+ primAddAttrib_Line(prim, ctxcanvas->canvas);
+ prim->param.polyf.n = n;
+ prim->param.polyf.points = malloc(n * sizeof(cdPoint));
+ memcpy(prim->param.polyf.points, poly, n * sizeof(cdPoint));
+ prim->param_buffer = prim->param.polyf.points;
+ picAddPrim(ctxcanvas, prim);
+
+ for (i = 0; i < n; i++)
+ {
+ if (mode == CD_FILL)
+ picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), 0);
+ else
+ picUpdateBBox(ctxcanvas, _cdRound(poly[i].x), _cdRound(poly[i].y), ctxcanvas->canvas->line_width);
+ }
+}
+
+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 l, offset, size;
+ unsigned char *dr, *dg, *db;
+
+ tPrimNode *prim = primCreate(CDPIC_IMAGERGB);
+ prim->param.imagergba.iw = xmax-xmin+1;
+ prim->param.imagergba.ih = ymax-ymin+1;
+ prim->param.imagergba.x = x;
+ prim->param.imagergba.y = y;
+ prim->param.imagergba.w = w;
+ prim->param.imagergba.h = h;
+
+ size = prim->param.imagergba.iw*prim->param.imagergba.ih;
+ prim->param_buffer = malloc(3*size);
+ prim->param.imagergba.r = prim->param_buffer;
+ prim->param.imagergba.g = prim->param.imagergba.r + size;
+ prim->param.imagergba.b = prim->param.imagergba.g + size;
+
+ offset = ymin*iw + xmin;
+ r += offset;
+ g += offset;
+ b += offset;
+
+ dr = prim->param.imagergba.r;
+ dg = prim->param.imagergba.g;
+ db = prim->param.imagergba.b;
+ offset = prim->param.imagergba.iw;
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ memcpy(dr, r, offset);
+ memcpy(dg, g, offset);
+ memcpy(db, b, offset);
+
+ r += iw;
+ g += iw;
+ b += iw;
+ dr += offset;
+ dg += offset;
+ db += offset;
+ }
+
+ picUpdateBBox(ctxcanvas, x, y, 0);
+ picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0);
+}
+
+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 l, offset, size;
+ unsigned char *dr, *dg, *db, *da;
+
+ tPrimNode *prim = primCreate(CDPIC_IMAGERGBA);
+ prim->param.imagergba.iw = xmax-xmin+1;
+ prim->param.imagergba.ih = ymax-ymin+1;
+ prim->param.imagergba.x = x;
+ prim->param.imagergba.y = y;
+ prim->param.imagergba.w = w;
+ prim->param.imagergba.h = h;
+
+ size = prim->param.imagergba.iw*prim->param.imagergba.ih;
+ prim->param_buffer = malloc(4*size);
+ prim->param.imagergba.r = prim->param_buffer;
+ prim->param.imagergba.g = prim->param.imagergba.r + size;
+ prim->param.imagergba.b = prim->param.imagergba.g + size;
+ prim->param.imagergba.a = prim->param.imagergba.b + size;
+
+ offset = ymin*iw + xmin;
+ r += offset;
+ g += offset;
+ b += offset;
+ a += offset;
+
+ dr = prim->param.imagergba.r;
+ dg = prim->param.imagergba.g;
+ db = prim->param.imagergba.b;
+ da = prim->param.imagergba.a;
+ offset = prim->param.imagergba.iw;
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ memcpy(dr, r, offset);
+ memcpy(dg, g, offset);
+ memcpy(db, b, offset);
+ memcpy(da, a, offset);
+
+ r += iw;
+ g += iw;
+ b += iw;
+ a += iw;
+ dr += offset;
+ dg += offset;
+ db += offset;
+ da += offset;
+ }
+
+ picUpdateBBox(ctxcanvas, x, y, 0);
+ picUpdateBBox(ctxcanvas, x+prim->param.imagergba.iw-1, y+prim->param.imagergba.ih-1, 0);
+}
+
+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 c, l, n = 0, offset, size;
+ unsigned char *dindex;
+ long *dcolors;
+
+ tPrimNode *prim = primCreate(CDPIC_IMAGEMAP);
+ prim->param.imagemap.iw = xmax-xmin+1;
+ prim->param.imagemap.ih = ymax-ymin+1;
+ prim->param.imagemap.x = x;
+ prim->param.imagemap.y = y;
+ prim->param.imagemap.w = w;
+ prim->param.imagemap.h = h;
+
+ size = prim->param.imagemap.iw*prim->param.imagemap.ih;
+ prim->param_buffer = malloc(size + 256);
+ prim->param.imagemap.index = prim->param_buffer;
+ prim->param.imagemap.colors = (long*)(prim->param.imagemap.index + size);
+
+ offset = ymin*iw + xmin;
+ index += offset;
+
+ dindex = prim->param.imagemap.index;
+ dcolors = prim->param.imagemap.colors;
+ offset = iw - prim->param.imagemap.iw;
+
+ for (l = ymin; l <= ymax; l++)
+ {
+ for (c = xmin; c <= xmax; c++)
+ {
+ if (*index > n)
+ n = *index;
+
+ *dindex++ = *index++;
+ }
+
+ index += offset;
+ }
+
+ n++;
+
+ for (c = 0; c < n; c++)
+ dcolors[c] = colors[c];
+
+ picUpdateBBox(ctxcanvas, x, y, 0);
+ picUpdateBBox(ctxcanvas, x+prim->param.imagemap.iw-1, y+prim->param.imagemap.ih-1, 0);
+}
+
+
+/**********/
+/* cdPlay */
+/**********/
+
+typedef int(*_cdsizecb)(cdCanvas* canvas, int w, int h, double w_mm, double h_mm);
+static _cdsizecb cdsizecb = NULL;
+
+static int cdregistercallback(int cb, cdCallback func)
+{
+ switch (cb)
+ {
+ case CD_SIZECB:
+ cdsizecb = (_cdsizecb)func;
+ return CD_OK;
+ }
+
+ return CD_ERROR;
+}
+
+#define sMin1(_v) (_v == 0? 1: _v)
+
+#define sScaleX(_x) cdRound((_x - pic_xmin) * factorX + xmin)
+#define sScaleY(_y) cdRound((_y - pic_ymin) * factorY + ymin)
+#define sScaleW(_w) sMin1(cdRound(_w * factorX))
+#define sScaleH(_h) sMin1(cdRound(_h * factorY))
+
+#define sfScaleX(_x) ((_x - pic_xmin) * factorX + xmin)
+#define sfScaleY(_y) ((_y - pic_ymin) * factorY + ymin)
+#define sfScaleW(_w) (_w * factorX)
+#define sfScaleH(_h) (_h * factorY)
+
+static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ tPrimNode *prim;
+ cdCanvas* pic_canvas = (cdCanvas*)data;
+ cdCtxCanvas* ctxcanvas = pic_canvas->ctxcanvas;
+ int p, i, scale = 0,
+ pic_xmin = ctxcanvas->xmin,
+ pic_ymin = ctxcanvas->ymin;
+ double factorX = 1, factorY = 1;
+
+ if ((ctxcanvas->xmax-ctxcanvas->xmin)!=0 &&
+ (ctxcanvas->ymax-ctxcanvas->ymin)!=0 &&
+ (xmax-xmin)!=0 &&
+ (ymax-ymin)!=0)
+ {
+ scale = 1;
+ factorX = ((double)(xmax-xmin)) / (ctxcanvas->xmax-ctxcanvas->xmin);
+ factorY = ((double)(ymax-ymin)) / (ctxcanvas->ymax-ctxcanvas->ymin);
+ }
+
+ if (cdsizecb)
+ {
+ int err;
+ err = cdsizecb(canvas, pic_canvas->w, pic_canvas->h, pic_canvas->w_mm, pic_canvas->h_mm);
+ if (err)
+ return CD_ERROR;
+ }
+
+ prim = ctxcanvas->prim_first;
+ for (i = 0; i < ctxcanvas->prim_n; i++)
+ {
+ if (scale)
+ {
+ switch (prim->type)
+ {
+ case CDPIC_LINE:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasLine(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleY(prim->param.lineboxrect.y1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y2));
+ break;
+ case CDPIC_FLINE:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasLine(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleY(prim->param.lineboxrectf.y1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y2));
+ break;
+ case CDPIC_RECT:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasRect(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2));
+ break;
+ case CDPIC_FRECT:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasRect(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2));
+ break;
+ case CDPIC_BOX:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasBox(canvas, sScaleX(prim->param.lineboxrect.x1), sScaleX(prim->param.lineboxrect.x2), sScaleY(prim->param.lineboxrect.y1), sScaleY(prim->param.lineboxrect.y2));
+ break;
+ case CDPIC_FBOX:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasBox(canvas, sfScaleX(prim->param.lineboxrectf.x1), sfScaleX(prim->param.lineboxrectf.x2), sfScaleY(prim->param.lineboxrectf.y1), sfScaleY(prim->param.lineboxrectf.y2));
+ break;
+ case CDPIC_ARC:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasArc(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FARC:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasArc(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_SECTOR:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasSector(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FSECTOR:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasSector(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_CHORD:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasChord(canvas, sScaleX(prim->param.arcsectorchord.xc), sScaleY(prim->param.arcsectorchord.yc), sScaleW(prim->param.arcsectorchord.w), sScaleH(prim->param.arcsectorchord.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FCHORD:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasChord(canvas, sfScaleX(prim->param.arcsectorchordf.xc), sfScaleY(prim->param.arcsectorchordf.yc), sfScaleW(prim->param.arcsectorchordf.w), sfScaleH(prim->param.arcsectorchordf.h), prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_TEXT:
+ primUpdateAttrib_Text(prim, canvas);
+ cdCanvasText(canvas, sScaleX(prim->param.text.x), sScaleY(prim->param.text.y), prim->param.text.s);
+ break;
+ case CDPIC_FTEXT:
+ primUpdateAttrib_Text(prim, canvas);
+ cdfCanvasText(canvas, sfScaleX(prim->param.textf.x), sfScaleY(prim->param.textf.y), prim->param.text.s);
+ break;
+ case CDPIC_POLY:
+ if (prim->param.poly.mode == CD_FILL)
+ primUpdateAttrib_Fill(prim, canvas);
+ else
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasBegin(canvas, prim->param.poly.mode);
+ for (p = 0; p < prim->param.poly.n; p++)
+ cdCanvasVertex(canvas, sScaleX(prim->param.poly.points[p].x), sScaleY(prim->param.poly.points[p].y));
+ cdCanvasEnd(canvas);
+ break;
+ case CDPIC_FPOLY:
+ if (prim->param.poly.mode == CD_FILL)
+ primUpdateAttrib_Fill(prim, canvas);
+ else
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasBegin(canvas, prim->param.polyf.mode);
+ for (p = 0; p < prim->param.polyf.n; p++)
+ cdfCanvasVertex(canvas, sfScaleX(prim->param.polyf.points[p].x), sfScaleY(prim->param.polyf.points[p].y));
+ cdCanvasEnd(canvas);
+ break;
+ case CDPIC_IMAGERGB:
+ cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0);
+ break;
+ case CDPIC_IMAGERGBA:
+ cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, sScaleX(prim->param.imagergba.x), sScaleY(prim->param.imagergba.y), sScaleW(prim->param.imagergba.w), sScaleH(prim->param.imagergba.h), 0, 0, 0, 0);
+ break;
+ case CDPIC_IMAGEMAP:
+ cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, sScaleX(prim->param.imagemap.x), sScaleY(prim->param.imagemap.y), sScaleW(prim->param.imagemap.w), sScaleH(prim->param.imagemap.h), 0, 0, 0, 0);
+ break;
+ case CDPIC_PIXEL:
+ cdCanvasPixel(canvas, sScaleX(prim->param.pixel.x), sScaleY(prim->param.pixel.y), prim->param.pixel.color);
+ break;
+ }
+ }
+ else
+ {
+ switch (prim->type)
+ {
+ case CDPIC_LINE:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasLine(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.y1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y2);
+ break;
+ case CDPIC_FLINE:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasLine(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y2);
+ break;
+ case CDPIC_RECT:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasRect(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2);
+ break;
+ case CDPIC_FRECT:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasRect(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2);
+ break;
+ case CDPIC_BOX:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasBox(canvas, prim->param.lineboxrect.x1, prim->param.lineboxrect.x2, prim->param.lineboxrect.y1, prim->param.lineboxrect.y2);
+ break;
+ case CDPIC_FBOX:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasBox(canvas, prim->param.lineboxrectf.x1, prim->param.lineboxrectf.x2, prim->param.lineboxrectf.y1, prim->param.lineboxrectf.y2);
+ break;
+ case CDPIC_ARC:
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasArc(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FARC:
+ primUpdateAttrib_Line(prim, canvas);
+ cdfCanvasArc(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_SECTOR:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasSector(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FSECTOR:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasSector(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_CHORD:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdCanvasChord(canvas, prim->param.arcsectorchord.xc, prim->param.arcsectorchord.yc, prim->param.arcsectorchord.w, prim->param.arcsectorchord.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_FCHORD:
+ primUpdateAttrib_Fill(prim, canvas);
+ cdfCanvasChord(canvas, prim->param.arcsectorchordf.xc, prim->param.arcsectorchordf.yc, prim->param.arcsectorchordf.w, prim->param.arcsectorchordf.h, prim->param.arcsectorchord.angle1, prim->param.arcsectorchord.angle2);
+ break;
+ case CDPIC_TEXT:
+ primUpdateAttrib_Text(prim, canvas);
+ cdCanvasText(canvas, prim->param.text.x, prim->param.text.y, prim->param.text.s);
+ break;
+ case CDPIC_FTEXT:
+ primUpdateAttrib_Text(prim, canvas);
+ cdfCanvasText(canvas, prim->param.textf.x, prim->param.textf.y, prim->param.text.s);
+ break;
+ case CDPIC_POLY:
+ if (prim->param.poly.mode == CD_FILL)
+ primUpdateAttrib_Fill(prim, canvas);
+ else
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasBegin(canvas, prim->param.poly.mode);
+ for (p = 0; p < prim->param.poly.n; p++)
+ cdCanvasVertex(canvas, prim->param.poly.points[p].x, prim->param.poly.points[p].y);
+ cdCanvasEnd(canvas);
+ break;
+ case CDPIC_FPOLY:
+ if (prim->param.poly.mode == CD_FILL)
+ primUpdateAttrib_Fill(prim, canvas);
+ else
+ primUpdateAttrib_Line(prim, canvas);
+ cdCanvasBegin(canvas, prim->param.polyf.mode);
+ for (p = 0; p < prim->param.polyf.n; p++)
+ cdfCanvasVertex(canvas, prim->param.polyf.points[p].x, prim->param.polyf.points[p].y);
+ cdCanvasEnd(canvas);
+ break;
+ case CDPIC_IMAGERGB:
+ cdCanvasPutImageRectRGB(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0);
+ break;
+ case CDPIC_IMAGERGBA:
+ cdCanvasPutImageRectRGBA(canvas, prim->param.imagergba.iw, prim->param.imagergba.ih, prim->param.imagergba.r, prim->param.imagergba.g, prim->param.imagergba.b, prim->param.imagergba.a, prim->param.imagergba.x, prim->param.imagergba.y, prim->param.imagergba.w, prim->param.imagergba.h, 0, 0, 0, 0);
+ break;
+ case CDPIC_IMAGEMAP:
+ cdCanvasPutImageRectMap(canvas, prim->param.imagemap.iw, prim->param.imagemap.ih, prim->param.imagemap.index, prim->param.imagemap.colors, prim->param.imagemap.x, prim->param.imagemap.y, prim->param.imagemap.w, prim->param.imagemap.h, 0, 0, 0, 0);
+ break;
+ case CDPIC_PIXEL:
+ cdCanvasPixel(canvas, prim->param.pixel.x, prim->param.pixel.y, prim->param.pixel.color);
+ break;
+ }
+ }
+
+ prim = prim->next;
+ }
+
+ return CD_OK;
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cdclear(ctxcanvas);
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/*******************/
+/* Canvas Creation */
+/*******************/
+
+static void cdcreatecanvas(cdCanvas *canvas, void *data)
+{
+ char* strdata = (char*)data;
+ double res = 3.78;
+ cdCtxCanvas* ctxcanvas;
+
+ sscanf(strdata, "%lg", &res);
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ ctxcanvas->canvas = canvas;
+ canvas->ctxcanvas = ctxcanvas;
+
+ /* update canvas context */
+ canvas->w = 0;
+ canvas->h = 0;
+ canvas->w_mm = 0;
+ canvas->h_mm = 0;
+ canvas->bpp = 24;
+ canvas->xres = res;
+ canvas->yres = res;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxClear = cdclear;
+ canvas->cxPixel = cdpixel;
+ canvas->cxLine = cdline;
+ canvas->cxFLine = cdfline;
+ canvas->cxRect = cdrect;
+ canvas->cxFRect = cdfrect;
+ canvas->cxBox = cdbox;
+ canvas->cxFBox = cdfbox;
+ canvas->cxArc = cdarc;
+ canvas->cxFArc = cdfarc;
+ canvas->cxSector = cdsector;
+ canvas->cxFSector = cdfsector;
+ canvas->cxChord = cdchord;
+ canvas->cxFChord = cdfchord;
+ canvas->cxText = cdtext;
+ canvas->cxFText = cdftext;
+ canvas->cxPoly = cdpoly;
+ canvas->cxFPoly = cdfpoly;
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdPictureContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_REGION | CD_CAP_FONTDIM | CD_CAP_TEXTSIZE),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ cdplay,
+ cdregistercallback,
+};
+
+cdContext* cdContextPicture(void)
+{
+ return &cdPictureContext;
+}
diff --git a/src/drv/cdps.c b/src/drv/cdps.c
new file mode 100644
index 0000000..0d23608
--- /dev/null
+++ b/src/drv/cdps.c
@@ -0,0 +1,1836 @@
+/** \file
+ * \brief PS driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include "cd.h"
+#include "cd_private.h"
+#include "cdps.h"
+
+
+#define mm2pt(x) (CD_MM2PT*(x))
+
+#ifndef min
+#define min(a, b) ((a)<(b)?(a):(b))
+#endif
+#ifndef max
+#define max(a, b) ((a)>(b)?(a):(b))
+#endif
+
+/*
+** dada uma cor do CD, obtem uma de suas componentes, na faixa 0-1.
+*/
+#define get_red(_) (((double)cdRed(_))/255.)
+#define get_green(_) (((double)cdGreen(_))/255.)
+#define get_blue(_) (((double)cdBlue(_))/255.)
+
+/* ATENTION: currentmatrix/setmatrix
+ Remeber that there is a tranformation set just after file open, to define margins and pixel scale.
+ So use transformations carefully.
+*/
+
+static unsigned char HatchBits[6][8] = { /* [style][y] (8x8) */
+ {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00}, /* CD_HORIZONTAL */
+ {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, /* CD_VERTICAL */
+ {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, /* CD_BDIAGONAL */
+ {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, /* CD_FDIAGONAL */
+ {0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10}, /* CD_CROSS */
+ {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}};/* CD_DIAGCROSS */
+
+
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ FILE *file; /* Arquivo PS */
+ int res; /* Resolucao */
+ int pages; /* Numero total de paginas */
+ double width; /* Largura do papel (points) */
+ double height; /* Altura do papel (points) */
+ double xmin, ymin; /* Definem as margens esquerda e inferior (points) */
+ double xmax, ymax; /* Definem as margens direita e superior (points) */
+ double bbxmin, bbymin; /* Definem a bounding box */
+ double bbxmax, bbymax; /* Definem a bounding box */
+ double bbmargin; /* Define a margem para a bounding box */
+ double scale; /* Fator de conversao de coordenadas (pixel2points) */
+ int eps; /* Postscrip encapsulado? */
+ int level1; /* if true generates level 1 only function calls */
+ int landscape; /* page orientation */
+ int debug; /* print debug strings in the file */
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ char *nativefontname[100]; /* Registra as fontes usadas */
+ int num_native_font;
+
+ int poly_holes[500];
+ int holes;
+
+};
+
+
+/*
+%F Ajusta o tamanho do papel em points.
+*/
+static void setpspapersize(cdCtxCanvas *ctxcanvas, int size)
+{
+ static struct
+ {
+ int width;
+ int height;
+ } paper[] =
+ {
+ { 2393, 3391 }, /* A0 */
+ { 1689, 2393 }, /* A1 */
+ { 1192, 1689 }, /* A2 */
+ { 842, 1192 }, /* A3 */
+ { 595, 842 }, /* A4 */
+ { 420, 595 }, /* A5 */
+ { 612, 792 }, /* LETTER */
+ { 612, 1008 } /* LEGAL */
+ };
+
+ if (size<CD_A0 || size>CD_LEGAL)
+ return;
+
+ ctxcanvas->width = (double)paper[size].width;
+ ctxcanvas->height = (double)paper[size].height;
+}
+
+/*
+%F Registra os valores default para impressao.
+*/
+static void setpsdefaultvalues(cdCtxCanvas *ctxcanvas)
+{
+ /* all the other values are set to 0 */
+ setpspapersize(ctxcanvas, CD_A4);
+ ctxcanvas->xmin = 25.4; /* ainda em mm, sera' convertido para points na init_ps */
+ ctxcanvas->xmax = 25.4;
+ ctxcanvas->ymin = 25.4;
+ ctxcanvas->ymax = 25.4;
+ ctxcanvas->res = 300;
+}
+
+/*
+%F Insere o ponto (x, y) na BoundingBox corrente.
+Nao leva em consideracao a espessura das linhas.
+*/
+static void insertpoint(cdCtxCanvas *ctxcanvas, int x, int y)
+{
+ double xmin = x*ctxcanvas->scale + ctxcanvas->xmin - ctxcanvas->bbmargin;
+ double ymin = y*ctxcanvas->scale + ctxcanvas->ymin - ctxcanvas->bbmargin;
+
+ double xmax = x*ctxcanvas->scale + ctxcanvas->xmin + ctxcanvas->bbmargin;
+ double ymax = y*ctxcanvas->scale + ctxcanvas->ymin + ctxcanvas->bbmargin;
+
+ if (!ctxcanvas->bbxmin && !ctxcanvas->bbxmax && !ctxcanvas->bbymin && !ctxcanvas->bbymax)
+ {
+ ctxcanvas->bbxmin = xmin;
+ ctxcanvas->bbymin = ymin;
+
+ ctxcanvas->bbxmax = xmax;
+ ctxcanvas->bbymax = ymax;
+ }
+ else
+ {
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA)
+ {
+ ctxcanvas->bbxmin = max(ctxcanvas->canvas->clip_rect.xmin*ctxcanvas->scale + ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin));
+ ctxcanvas->bbymin = max(ctxcanvas->canvas->clip_rect.ymin*ctxcanvas->scale + ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin));
+
+ ctxcanvas->bbxmax = min(ctxcanvas->canvas->clip_rect.xmax*ctxcanvas->scale + ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax));
+ ctxcanvas->bbymax = min(ctxcanvas->canvas->clip_rect.ymax*ctxcanvas->scale + ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax));
+ }
+ else
+ {
+ ctxcanvas->bbxmin = max(ctxcanvas->xmin, min(ctxcanvas->bbxmin, xmin));
+ ctxcanvas->bbymin = max(ctxcanvas->ymin, min(ctxcanvas->bbymin, ymin));
+
+ ctxcanvas->bbxmax = min(ctxcanvas->xmax, max(ctxcanvas->bbxmax, xmax));
+ ctxcanvas->bbymax = min(ctxcanvas->ymax, max(ctxcanvas->bbymax, ymax));
+ }
+ }
+}
+
+/*
+%F Ajusta a BoundingBox para conter o ponto (x,y).
+Leva em consideracao a espessura das linhas.
+*/
+static void bbox(cdCtxCanvas *ctxcanvas, int x, int y)
+{
+ if (ctxcanvas->canvas->line_width > 1)
+ {
+ insertpoint(ctxcanvas, x-ctxcanvas->canvas->line_width, y-ctxcanvas->canvas->line_width);
+ insertpoint(ctxcanvas, x+ctxcanvas->canvas->line_width, y+ctxcanvas->canvas->line_width);
+ }
+ else
+ insertpoint(ctxcanvas, x, y);
+}
+
+static void fbbox(cdCtxCanvas *ctxcanvas, double x, double y)
+{
+ if (ctxcanvas->canvas->line_width > 1)
+ {
+ insertpoint(ctxcanvas, (int)(x-ctxcanvas->canvas->line_width), (int)(y-ctxcanvas->canvas->line_width));
+ insertpoint(ctxcanvas, (int)(x+ctxcanvas->canvas->line_width), (int)(y+ctxcanvas->canvas->line_width));
+ }
+ else
+ insertpoint(ctxcanvas, (int)x, (int)y);
+}
+
+static char new_codes[] = {"\
+/newcodes % foreign character encodings\n\
+[\n\
+160/space 161/exclamdown 162/cent 163/sterling 164/currency\n\
+165/yen 166/brokenbar 167/section 168/dieresis 169/copyright\n\
+170/ordfeminine 171/guillemotleft 172/logicalnot 173/hyphen 174/registered\n\
+175/macron 176/degree 177/plusminus 178/twosuperior 179/threesuperior\n\
+180/acute 181/mu 182/paragraph 183/periodcentered 184/cedilla\n\
+185/onesuperior 186/ordmasculine 187/guillemotright 188/onequarter\n\
+189/onehalf 190/threequarters 191/questiondown 192/Agrave 193/Aacute\n\
+194/Acircumflex 195/Atilde 196/Adieresis 197/Aring 198/AE 199/Ccedilla\n\
+200/Egrave 201/Eacute 202/Ecircumflex 203/Edieresis 204/Igrave 205/Iacute\n\
+206/Icircumflex 207/Idieresis 208/Eth 209/Ntilde 210/Ograve 211/Oacute\n\
+212/Ocircumflex 213/Otilde 214/Odieresis 215/multiply 216/Oslash\n\
+217/Ugrave 218/Uacute 219/Ucircumflex 220/Udieresis 221/Yacute 222/Thorn\n\
+223/germandbls 224/agrave 225/aacute 226/acircumflex 227/atilde\n\
+228/adieresis 229/aring 230/ae 231/ccedilla 232/egrave 233/eacute\n\
+234/ecircumflex 235/edieresis 236/igrave 237/iacute 238/icircumflex\n\
+239/idieresis 240/eth 241/ntilde 242/ograve 243/oacute 244/ocircumflex\n\
+245/otilde 246/odieresis 247/divide 248/oslash 249/ugrave 250/uacute\n\
+251/ucircumflex 252/udieresis 253/yacute 254/thorn 255/ydieresis\n\
+] def\n\
+"};
+
+static char change_font[] = {"\
+% change fonts using ISO Latin1 characters\n\
+/ChgFnt % size psname natname => font\n\
+{\n\
+ dup FontDirectory exch known % is re-encoded name known?\n\
+ { exch pop } % yes, get rid of long name\n\
+ { dup 3 1 roll ReEncode } ifelse % no, re-encode it\n\
+ findfont exch scalefont setfont\n\
+} def\n\
+"};
+
+static char re_encode[] = {"\
+/ReEncode %\n\
+{\n\
+ 12 dict begin\n\
+ /newname exch def\n\
+ /basename exch def\n\
+ /basedict basename findfont def\n\
+ /newfont basedict maxlength dict def\n\
+ basedict\n\
+ { exch dup /FID ne\n\
+ { dup /Encoding eq\n\
+ { exch dup length array copy newfont 3 1 roll put }\n\
+ { exch newfont 3 1 roll put } ifelse\n\
+ }\n\
+ { pop pop } ifelse\n\
+ } forall\n\
+ newfont /FontName newname put\n\
+ newcodes aload pop newcodes length 2 idiv\n\
+ { newfont /Encoding get 3 1 roll put } repeat\n\
+ newname newfont definefont pop\n\
+ end\n\
+} def\n\
+"};
+
+static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax)
+{
+ if (ctxcanvas->eps) /* initclip not allowed in EPS */
+ return;
+
+ fprintf(ctxcanvas->file, "initclip\n");
+
+ /* cliping geral para a margem */
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin);
+ fprintf(ctxcanvas->file, "C\n");
+ fprintf(ctxcanvas->file, "clip\n");
+ fprintf(ctxcanvas->file, "N\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%g %g %g %g rectclip\n", xmin, ymin, xmax-xmin, ymax-ymin);
+}
+
+static void set_default_matrix(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->eps)
+ fprintf(ctxcanvas->file, "oldmatrix setmatrix\n"); /* reset to current */
+ else
+ {
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] defaultmatrix\n"); /* reset to default */
+ fprintf(ctxcanvas->file, "setmatrix\n");
+ }
+
+ /* margin and scale */
+ fprintf(ctxcanvas->file, "%g %g translate\n", ctxcanvas->xmin, ctxcanvas->ymin);
+ fprintf(ctxcanvas->file, "%g %g scale\n", ctxcanvas->scale, ctxcanvas->scale);
+}
+
+/*
+%F Inicializa o arquivo PS.
+*/
+static void init_ps(cdCtxCanvas *ctxcanvas)
+{
+ double w, h;
+
+ time_t now = time(NULL);
+
+ ctxcanvas->scale = 72.0/ctxcanvas->res;
+ ctxcanvas->xmin = mm2pt(ctxcanvas->xmin);
+ ctxcanvas->xmax = ctxcanvas->width - mm2pt(ctxcanvas->xmax);
+ ctxcanvas->ymin = mm2pt(ctxcanvas->ymin);
+ ctxcanvas->ymax = ctxcanvas->height - mm2pt(ctxcanvas->ymax);
+ ctxcanvas->bbmargin = mm2pt(ctxcanvas->bbmargin);
+
+ fprintf(ctxcanvas->file, "%%!PS-Adobe-3.0 %s\n", ctxcanvas->eps ? "EPSF-3.0":"");
+ fprintf(ctxcanvas->file, "%%%%Title: CanvasDraw\n");
+ fprintf(ctxcanvas->file, "%%%%Creator: CanvasDraw\n");
+ fprintf(ctxcanvas->file, "%%%%CreationDate: %s", asctime(localtime(&now)));
+ fprintf(ctxcanvas->file, "%%%%DocumentFonts: (atend)\n"); /* attend means at the end of the file, */
+ fprintf(ctxcanvas->file, "%%%%Pages: (atend)\n"); /* see killcanvas */
+ fprintf(ctxcanvas->file, "%%%%PageOrder: Ascend\n");
+ fprintf(ctxcanvas->file, "%%%%LanguageLevel: %d\n", ctxcanvas->level1 ? 1: 2);
+ fprintf(ctxcanvas->file, "%%%%Orientation: %s\n", ctxcanvas->landscape ? "Landscape": "Portrait");
+
+ if (ctxcanvas->eps)
+ {
+ fprintf(ctxcanvas->file, "%%%%BoundingBox: (atend)\n");
+ ctxcanvas->bbxmin = ctxcanvas->bbxmax = ctxcanvas->bbymin = ctxcanvas->bbymax = 0;
+ /* BoundingBox==Empty */
+ }
+
+ fprintf(ctxcanvas->file, "%%%%EndComments\n");
+ fprintf(ctxcanvas->file, "%%%%BeginProlog\n");
+
+ fprintf(ctxcanvas->file, "/N {newpath} bind def\n");
+ fprintf(ctxcanvas->file, "/C {closepath} bind def\n");
+ fprintf(ctxcanvas->file, "/M {moveto} bind def\n");
+ fprintf(ctxcanvas->file, "/L {lineto} bind def\n");
+ fprintf(ctxcanvas->file, "/B {curveto} bind def\n");
+ fprintf(ctxcanvas->file, "/S {stroke} bind def\n");
+ fprintf(ctxcanvas->file, "/LL {moveto lineto stroke} bind def\n");
+
+ if (!ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "/RF {rectfill} bind def\n");
+ fprintf(ctxcanvas->file, "/RS {rectstroke} bind def\n");
+ }
+
+ fprintf(ctxcanvas->file, "%%%%EndProlog\n");
+ fprintf(ctxcanvas->file, "%%%%BeginSetup\n");
+
+ if (!ctxcanvas->eps && !ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "%%%%IncludeFeature: *Resolution %d\n", ctxcanvas->res);
+ fprintf(ctxcanvas->file, "%%%%BeginFeature: *PageSize\n");
+ fprintf(ctxcanvas->file, "<< /PageSize [%g %g] >> setpagedevice\n", ctxcanvas->width, ctxcanvas->height); /* setpagedevice not allowed in EPS */
+ fprintf(ctxcanvas->file, "%%%%EndFeature\n");
+ }
+
+ fprintf(ctxcanvas->file, "%%%%EndSetup\n");
+
+ fputs(new_codes, ctxcanvas->file);
+ fputs(change_font, ctxcanvas->file);
+ fputs(re_encode, ctxcanvas->file);
+
+ w = ctxcanvas->xmax - ctxcanvas->xmin;
+ h = ctxcanvas->ymax - ctxcanvas->ymin;
+
+ ctxcanvas->canvas->w = (int)(w/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */
+ ctxcanvas->canvas->h = (int)(h/ctxcanvas->scale + 0.5); /* Converte p/ unidades do usuario */
+ ctxcanvas->canvas->w_mm = w/CD_MM2PT; /* Converte p/ milimetros */
+ ctxcanvas->canvas->h_mm = h/CD_MM2PT; /* Converte p/ milimetros */
+ ctxcanvas->canvas->bpp = 24;
+ ctxcanvas->canvas->xres = ctxcanvas->canvas->w / ctxcanvas->canvas->w_mm;
+ ctxcanvas->canvas->yres = ctxcanvas->canvas->h / ctxcanvas->canvas->h_mm;
+
+ fprintf(ctxcanvas->file, "%%%%Page: 1 1\n");
+ ctxcanvas->pages = 1;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdCreateCanvas: Margin Begin\n");
+
+ if (ctxcanvas->eps)
+ fprintf(ctxcanvas->file, "/oldmatrix [0 0 0 0 0 0] currentmatrix def\n"); /* save current matrix */
+
+ set_default_matrix(ctxcanvas);
+
+ /* cliping geral para a margem */
+ setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdCreateCanvas: MarginEnd\n");
+}
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ int i;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdKillCanvas\n");
+
+ fprintf(ctxcanvas->file, "showpage\n");
+ fprintf(ctxcanvas->file, "%%%%Trailer\n");
+ fprintf(ctxcanvas->file, "%%%%Pages: %d 1\n", ctxcanvas->pages);
+
+ if (ctxcanvas->eps)
+ {
+ int xmin = (int)ctxcanvas->bbxmin;
+ int xmax = (int)ctxcanvas->bbxmax;
+ int ymin = (int)ctxcanvas->bbymin;
+ int ymax = (int)ctxcanvas->bbymax;
+ if (xmax < ctxcanvas->bbxmax) xmax++;
+ if (ymax < ctxcanvas->bbymax) ymax++;
+ fprintf(ctxcanvas->file,"%%%%BoundingBox: %5d %5d %5d %5d\n",xmin,ymin,xmax,ymax);
+ }
+
+ fprintf(ctxcanvas->file, "%%%%DocumentFonts:");
+
+ for (i = 0; i < ctxcanvas->num_native_font; i++)
+ {
+ fprintf(ctxcanvas->file, " %s", ctxcanvas->nativefontname[i]);
+ free(ctxcanvas->nativefontname[i]);
+ }
+
+ putc('\n', ctxcanvas->file);
+ fprintf(ctxcanvas->file,"%%%%EOF");
+
+ fclose(ctxcanvas->file);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cddeactivate(cdCtxCanvas *ctxcanvas)
+{
+ fflush(ctxcanvas->file);
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style);
+static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple);
+static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern);
+
+static void update_fill(cdCtxCanvas *ctxcanvas, int fill)
+{
+ if (fill == 0)
+ {
+ /* called before a NON filled primitive */
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill);
+
+ fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground),
+ get_green(ctxcanvas->canvas->foreground),
+ get_blue(ctxcanvas->canvas->foreground));
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill);
+ }
+ else
+ {
+ /* called before a filled primitive */
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsUpdateFill %d Begin\n", fill);
+
+ if (ctxcanvas->canvas->interior_style == CD_SOLID)
+ {
+ fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n", get_red(ctxcanvas->canvas->foreground),
+ get_green(ctxcanvas->canvas->foreground),
+ get_blue(ctxcanvas->canvas->foreground));
+ }
+ else if (!ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "cd_pattern\n");
+ fprintf(ctxcanvas->file, "setpattern\n");
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsUpdateFill %dEnd\n", fill);
+ }
+}
+
+/*
+%F Comeca uma nova pagina.
+*/
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdFlush Begin\n");
+
+ if (!ctxcanvas->eps)
+ {
+ fprintf(ctxcanvas->file, "gsave\n");
+
+ fprintf(ctxcanvas->file, "showpage\n");
+ ctxcanvas->pages++;
+ fprintf(ctxcanvas->file, "%%%%Page: %d %d\n", ctxcanvas->pages, ctxcanvas->pages);
+
+ fprintf(ctxcanvas->file, "grestore\n");
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdFlushEnd\n");
+}
+
+
+/******************************************************/
+/* coordinate transformation */
+/******************************************************/
+
+static void cdfcliparea(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA)
+ return;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfClipArea Begin\n");
+
+ setcliprect(ctxcanvas, xmin, ymin, xmax, ymax);
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfClipAreaEnd\n");
+}
+
+static int cdclip(cdCtxCanvas *ctxcanvas, int mode)
+{
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdClip %d Begin\n", mode);
+
+ if (mode == CD_CLIPAREA)
+ {
+ ctxcanvas->canvas->clip_mode = CD_CLIPAREA;
+
+ setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin,
+ (double)ctxcanvas->canvas->clip_rect.ymin,
+ (double)ctxcanvas->canvas->clip_rect.xmax,
+ (double)ctxcanvas->canvas->clip_rect.ymax);
+ }
+ else if (mode == CD_CLIPPOLYGON)
+ {
+ fprintf(ctxcanvas->file, "clip_polygon\n");
+ }
+ else
+ {
+ /* margin clipping only */
+ setcliprect(ctxcanvas, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdClip %dEnd\n", mode);
+
+ return mode;
+}
+
+/******************************************************/
+/* primitives */
+/******************************************************/
+
+static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2)
+{
+ update_fill(ctxcanvas, 0);
+
+ fprintf(ctxcanvas->file, "N %d %d %d %d LL\n", x1, y1, x2, y2);
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, x1, y1);
+ bbox(ctxcanvas, x2, y2);
+ }
+}
+
+static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2)
+{
+ update_fill(ctxcanvas, 0);
+
+ fprintf(ctxcanvas->file, "N %g %g %g %g LL\n", x1, y1, x2, y2);
+
+ if (ctxcanvas->eps)
+ {
+ fbbox(ctxcanvas, x1, y1);
+ fbbox(ctxcanvas, x2, y2);
+ }
+}
+
+static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin);
+ fprintf(ctxcanvas->file, "C S\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%d %d %d %d RS\n", xmin, ymin, xmax - xmin, ymax - ymin);
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin);
+ fprintf(ctxcanvas->file, "C S\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%g %g %g %g RS\n", xmin, ymin, xmax - xmin, ymax - ymin);
+
+ if (ctxcanvas->eps)
+ {
+ fbbox(ctxcanvas, xmin, ymin);
+ fbbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d M\n", xmin, ymin);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmin, ymax);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymax);
+ fprintf(ctxcanvas->file, "%d %d L\n", xmax, ymin);
+ fprintf(ctxcanvas->file, "C fill\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%d %d %d %d RF\n", xmin, ymin, xmax - xmin, ymax - ymin);
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g M\n", xmin, ymin);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmin, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymax);
+ fprintf(ctxcanvas->file, "%g %g L\n", xmax, ymin);
+ fprintf(ctxcanvas->file, "C fill\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%g %g %g %g RF\n", xmin, ymin, xmax - xmin, ymax - ymin);
+
+ if (ctxcanvas->eps)
+ {
+ fbbox(ctxcanvas, xmin, ymin);
+ fbbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ fprintf(ctxcanvas->file, "N %d %d %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2);
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdArc Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n"); /* fill new matrix from CTM */
+ fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "S\n");
+ fprintf(ctxcanvas->file, "setmatrix\n"); /* back to CTM */
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdArc EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 0);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ fprintf(ctxcanvas->file, "N %g %g %g %g %g arc S\n", xc, yc, 0.5*w, a1, a2);
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfArc Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", h/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "S\n");
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfArc EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Circle Begin\n");
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d M\n", xc, yc);
+ fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector CircleEnd\n");
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdSector Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 M\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdSector EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ bbox(ctxcanvas, xc, yc);
+ }
+}
+
+static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Circle Begin\n");
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g M\n", xc, yc);
+ fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector CircleEnd\n");
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfSector Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", h/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 M\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfSector EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ fbbox(ctxcanvas, xc, yc);
+ }
+}
+
+static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Circle Begin\n");
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d %g %g %g arc\n", xc, yc, 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord CircleEnd\n");
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdChord Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%d %d translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", ((double)h)/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdChord EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(xc, yc, w, h, a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2)
+{
+ update_fill(ctxcanvas, 1);
+
+ if (w==h) /* Circulo: PS implementa direto */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Circle Begin\n");
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g %g %g %g arc\n", xc, yc, 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord CircleEnd\n");
+ }
+ else /* Elipse: mudar a escala p/ criar a partir do circulo */
+ {
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfChord Ellipse Begin\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%g %g translate\n", xc, yc);
+ fprintf(ctxcanvas->file, "1 %g scale\n", h/w);
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "0 0 %g %g %g arc\n", 0.5*w, a1, a2);
+ fprintf(ctxcanvas->file, "C fill\n");
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfChord EllipseEnd\n");
+ }
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetEllipseBox(_cdRound(xc), _cdRound(yc), _cdRound(w), _cdRound(h), a1, a2, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix);
+
+static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s)
+{
+ int i, length;
+ int ascent, height, baseline;
+
+ update_fill(ctxcanvas, 0);
+
+ cdCanvasGetFontDim(ctxcanvas->canvas, NULL, &height, &ascent, NULL);
+ baseline = height - ascent;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdText Begin\n");
+
+ if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle)
+ set_default_matrix(ctxcanvas);
+
+ fprintf(ctxcanvas->file, "N 0 0 M\n");
+ putc('(', ctxcanvas->file);
+
+ for (length = (int)strlen(s), i=0; i<length; i++)
+ {
+ if (s[i]=='(' || s[i]==')')
+ putc('\\', ctxcanvas->file);
+ putc(s[i], ctxcanvas->file);
+ }
+
+ fprintf(ctxcanvas->file, ")\n");
+ fprintf(ctxcanvas->file, "dup true charpath\n");
+ fprintf(ctxcanvas->file, "flattenpath\n");
+ fprintf(ctxcanvas->file, "pathbbox\n"); /* bbox na pilha: llx lly urx ury */
+ fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: llx lly ury urx */
+ fprintf(ctxcanvas->file, "4 1 roll\n"); /* roda: urx llx lly ury */
+ fprintf(ctxcanvas->file, "exch\n"); /* troca o topo: urx llx ury lly */
+ fprintf(ctxcanvas->file, "sub\n"); /* subtrai: urx llx h */
+ fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: h urx llx */
+ fprintf(ctxcanvas->file, "sub\n"); /* subtrai: h w */
+ fprintf(ctxcanvas->file, "0 0\n"); /* empilha: h w 0 0 */
+ fprintf(ctxcanvas->file, "4 -1 roll\n"); /* roda: w 0 0 h */
+
+ if (ctxcanvas->canvas->use_matrix || ctxcanvas->rotate_angle)
+ cdtransform(ctxcanvas, ctxcanvas->canvas->use_matrix? ctxcanvas->canvas->matrix: NULL);
+
+ fprintf(ctxcanvas->file, "gsave\n"); /* save to use local transform */
+ fprintf(ctxcanvas->file, "%d %d translate\n", x, y);
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ fprintf(ctxcanvas->file, "%g rotate\n", ctxcanvas->canvas->text_orientation);
+
+ switch (ctxcanvas->canvas->text_alignment) /* Operacao em Y. topo da pilha: w x y h */
+ {
+ case CD_NORTH:
+ case CD_NORTH_EAST:
+ case CD_NORTH_WEST:
+ fprintf(ctxcanvas->file, "%d sub sub\n", baseline); /* empilha, subtrai, subtrai: w x y-(h-baseline) */
+ break;
+ case CD_EAST:
+ case CD_WEST:
+ case CD_CENTER:
+ fprintf(ctxcanvas->file, "2 div %d sub sub\n", baseline); /* empilha, divide, empilha, subtrai, subtrai: w x y-(h/2-baseline) */
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH:
+ case CD_SOUTH_WEST:
+ fprintf(ctxcanvas->file, "pop %d add\n", baseline); /* desempilha, empilha, adiciona: w x y+baseline */
+ break;
+ case CD_BASE_RIGHT:
+ case CD_BASE_CENTER:
+ case CD_BASE_LEFT:
+ fprintf(ctxcanvas->file, "pop\n"); /* desempilha h: w x y */
+ break;
+ }
+
+ fprintf(ctxcanvas->file, "3 1 roll\n"); /* roda: y' w x */
+ fprintf(ctxcanvas->file, "exch\n"); /* inverte: y' x w */
+
+ switch (ctxcanvas->canvas->text_alignment) /* Operacao em X, topo da pilha: x w */
+ {
+ case CD_NORTH:
+ case CD_SOUTH:
+ case CD_CENTER:
+ case CD_BASE_CENTER:
+ fprintf(ctxcanvas->file, "2 div sub\n"); /* empilha, divide, subtrai: y' x-w/2 */
+ break;
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ case CD_BASE_RIGHT:
+ fprintf(ctxcanvas->file, "sub\n"); /* subtrai: y' x-w */
+ break;
+ case CD_SOUTH_WEST:
+ case CD_WEST:
+ case CD_NORTH_WEST:
+ case CD_BASE_LEFT:
+ fprintf(ctxcanvas->file, "pop\n"); /* desempilha: y' x */
+ break;
+ }
+
+ fprintf(ctxcanvas->file, "exch\n"); /* inverte: x' y' */
+ fprintf(ctxcanvas->file, "M\n"); /* moveto */
+
+ fprintf(ctxcanvas->file, "show\n");
+
+ if (ctxcanvas->eps)
+ {
+ int xmin, xmax, ymin, ymax;
+ cdCanvasGetTextBox(ctxcanvas->canvas, x, y, s, &xmin, &xmax, &ymin, &ymax);
+ bbox(ctxcanvas, xmin, ymin);
+ bbox(ctxcanvas, xmax, ymax);
+ }
+
+ fprintf(ctxcanvas->file, "grestore\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdTextEnd\n");
+}
+
+static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i;
+
+ if (mode == CD_CLIP)
+ {
+ if (ctxcanvas->eps) /* initclip not allowed in EPS */
+ return;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode);
+
+ fprintf(ctxcanvas->file, "/clip_polygon {\n");
+ fprintf(ctxcanvas->file, "initclip\n");
+ }
+ else
+ {
+ if (mode == CD_FILL)
+ update_fill(ctxcanvas, 1);
+ else
+ update_fill(ctxcanvas, 0);
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPoly %d Begin\n", mode);
+ }
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d M\n", poly[0].x, poly[0].y);
+
+ if (ctxcanvas->eps)
+ bbox(ctxcanvas, poly[0].x, poly[0].y);
+
+ if (mode == CD_BEZIER)
+ {
+ for (i=1; i<n; i+=3)
+ {
+ fprintf(ctxcanvas->file, "%d %d %d %d %d %d B\n", poly[i].x, poly[i].y,
+ poly[i+1].x, poly[i+1].y,
+ poly[i+2].x, poly[i+2].y);
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, poly[i].x, poly[i].y);
+ bbox(ctxcanvas, poly[i+2].x, poly[i+2].y);
+ bbox(ctxcanvas, poly[i+3].x, poly[i+3].y);
+ }
+ }
+ }
+ else
+ {
+ int hole_index = 0;
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ fprintf(ctxcanvas->file, "%d %d M\n", poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ fprintf(ctxcanvas->file, "%d %d L\n", poly[i].x, poly[i].y);
+
+ if (ctxcanvas->eps)
+ bbox(ctxcanvas, poly[i].x, poly[i].y);
+ }
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ fprintf(ctxcanvas->file, "C S\n");
+ break;
+ case CD_OPEN_LINES :
+ fprintf(ctxcanvas->file, "S\n");
+ break;
+ case CD_BEZIER :
+ fprintf(ctxcanvas->file, "S\n");
+ break;
+ case CD_FILL :
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ fprintf(ctxcanvas->file, "eofill\n");
+ else
+ fprintf(ctxcanvas->file, "fill\n");
+ break;
+ case CD_CLIP :
+ if (ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ fprintf(ctxcanvas->file, "C eoclip\n");
+ else
+ fprintf(ctxcanvas->file, "C clip\n");
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "} bind def\n");
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ fprintf(ctxcanvas->file, "clip_polygon\n");
+ break;
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPoly %dEnd\n", mode);
+}
+
+static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n)
+{
+ int i, hole_index = 0;
+
+ if (mode == CD_CLIP)
+ {
+ if (ctxcanvas->eps) /* initclip not allowed in EPS */
+ return;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode);
+
+ fprintf(ctxcanvas->file, "/clip_polygon {\n");
+ fprintf(ctxcanvas->file, "initclip\n");
+ }
+ else
+ {
+ if (mode == CD_FILL)
+ update_fill(ctxcanvas, 1);
+ else
+ update_fill(ctxcanvas, 0);
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdfPoly %d Begin\n", mode);
+ }
+
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%g %g M\n", poly[0].x, poly[0].y);
+
+ if (ctxcanvas->eps)
+ fbbox(ctxcanvas, poly[0].x, poly[0].y);
+
+ for (i=1; i<n; i++)
+ {
+ if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index])
+ {
+ fprintf(ctxcanvas->file, "%g %g M\n", poly[i].x, poly[i].y);
+ hole_index++;
+ }
+ else
+ fprintf(ctxcanvas->file, "%g %g L\n", poly[i].x, poly[i].y);
+
+ if (ctxcanvas->eps)
+ fbbox(ctxcanvas, poly[i].x, poly[i].y);
+ }
+
+ switch (mode)
+ {
+ case CD_CLOSED_LINES :
+ fprintf(ctxcanvas->file, "C S\n");
+ break;
+ case CD_OPEN_LINES :
+ fprintf(ctxcanvas->file, "S\n");
+ break;
+ case CD_FILL :
+ if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ fprintf(ctxcanvas->file, "eofill\n");
+ else
+ fprintf(ctxcanvas->file, "fill\n");
+ break;
+ case CD_CLIP :
+ if (ctxcanvas->canvas->fill_mode==CD_EVENODD)
+ fprintf(ctxcanvas->file, "C eoclip\n");
+ else
+ fprintf(ctxcanvas->file, "C clip\n");
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "} bind def\n");
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ fprintf(ctxcanvas->file, "clip_polygon\n");
+ break;
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdfPoly %dEnd\n", mode);
+}
+
+
+/******************************************************/
+/* attributes */
+/******************************************************/
+
+static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style)
+{
+ double mm = (72.0/25.4) / ctxcanvas->scale;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdLineStyle %d Begin\n", style);
+
+ fprintf(ctxcanvas->file, "[");
+
+ switch (style)
+ {
+ case CD_CONTINUOUS : /* empty dash */
+ fprintf(ctxcanvas->file, " ");
+ break;
+ case CD_DASHED :
+ fprintf(ctxcanvas->file, "%g %g", 3*mm, mm);
+ break;
+ case CD_DOTTED :
+ fprintf(ctxcanvas->file, "%g %g", mm, mm);
+ break;
+ case CD_DASH_DOT :
+ fprintf(ctxcanvas->file, "%g %g %g %g", 3*mm, mm, mm, mm);
+ break;
+ case CD_DASH_DOT_DOT :
+ fprintf(ctxcanvas->file, "%g %g %g %g %g %g", 3*mm, mm, mm, mm, mm, mm);
+ break;
+ case CD_CUSTOM :
+ {
+ int i;
+ for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++)
+ fprintf(ctxcanvas->file, "%g ", ctxcanvas->canvas->line_dashes[i]*mm);
+ }
+ break;
+ }
+
+ fprintf(ctxcanvas->file, "] 0 setdash\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdLineStyle %dEnd\n", style);
+
+ return style;
+}
+
+static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width)
+{
+ fprintf(ctxcanvas->file, "%d setlinewidth\n", width);
+ return width;
+}
+
+static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join)
+{
+ int cd2ps_join[] = {0, 2, 1};
+ fprintf(ctxcanvas->file, "%d setlinejoin\n", cd2ps_join[join]);
+ return join;
+}
+
+static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap)
+{
+ int cd2ps_cap[] = {0, 2, 1};
+ fprintf(ctxcanvas->file, "%d setlinecap\n", cd2ps_cap[cap]);
+ return cap;
+}
+
+static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, void (*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;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "\n%%cdPsMakePattern Begin\n");
+
+ fprintf(ctxcanvas->file, "/cd_pattern\n");
+ fprintf(ctxcanvas->file, "currentfile %d string readhexstring\n", n*m*3);
+
+ for (j=0; j<m; j++)
+ {
+ for (i=0; i<n; i++)
+ {
+ data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b);
+ fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r, (int)g, (int)b);
+ }
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+
+ fprintf(ctxcanvas->file, "pop\n");
+ fprintf(ctxcanvas->file, "/Pat exch def\n");
+ fprintf(ctxcanvas->file, "<<\n");
+ fprintf(ctxcanvas->file, " /PatternType 1\n");
+ fprintf(ctxcanvas->file, " /PaintType 1\n");
+ fprintf(ctxcanvas->file, " /TilingType 1\n");
+ fprintf(ctxcanvas->file, " /BBox [0 0 %d %d]\n", n, m);
+ fprintf(ctxcanvas->file, " /XStep %d /YStep %d\n", n, m);
+ fprintf(ctxcanvas->file, " /PaintProc {\n");
+ fprintf(ctxcanvas->file, " pop\n");
+ fprintf(ctxcanvas->file, " %d %d 8\n", n, m);
+ fprintf(ctxcanvas->file, " matrix\n");
+ fprintf(ctxcanvas->file, " Pat\n");
+ fprintf(ctxcanvas->file, " false 3\n");
+ fprintf(ctxcanvas->file, " colorimage\n");
+ fprintf(ctxcanvas->file, " }\n");
+ fprintf(ctxcanvas->file, ">>\n");
+ fprintf(ctxcanvas->file, "matrix\n");
+ fprintf(ctxcanvas->file, "makepattern\n");
+ fprintf(ctxcanvas->file, "def\n");
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPsMakePatternEnd\n");
+}
+
+static void 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);
+}
+
+static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern)
+{
+ if (ctxcanvas->level1)
+ return;
+
+ make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb);
+}
+
+static void uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)
+{
+ unsigned char* uchar_data = (unsigned char*)data;
+ if (uchar_data[j*n+i])
+ cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b);
+ else
+ cdDecodeColor(ctxcanvas->canvas->background, r, g, b);
+}
+
+static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple)
+{
+ if (ctxcanvas->level1)
+ return;
+
+ make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb);
+}
+
+static void ucharh2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b)
+{
+ unsigned char* uchar_data = (unsigned char*)data;
+ static unsigned char hatch;
+ (void)n;
+ if (i == 0) hatch = uchar_data[j];
+ if (hatch & 0x80)
+ cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b);
+ else
+ cdDecodeColor(ctxcanvas->canvas->background, r, g, b);
+ _cdRotateHatch(hatch);
+}
+
+static int cdhatch(cdCtxCanvas *ctxcanvas, int style)
+{
+ if (ctxcanvas->level1)
+ return ctxcanvas->canvas->hatch_style;
+
+ make_pattern(ctxcanvas, 8, 8, (void*)HatchBits[style], ucharh2rgb);
+
+ return style;
+}
+
+static void add_font_name(cdCtxCanvas *ctxcanvas, char *nativefontname)
+{
+ int size, i;
+ for (i = 0; i < ctxcanvas->num_native_font; i++)
+ {
+ if (cdStrEqualNoCase(ctxcanvas->nativefontname[i], nativefontname))
+ return;
+ }
+
+ size = strlen(nativefontname)+1;
+ ctxcanvas->nativefontname[ctxcanvas->num_native_font] = (char*)malloc(size);
+ memcpy(ctxcanvas->nativefontname[ctxcanvas->num_native_font], nativefontname, size);
+ ctxcanvas->num_native_font++;
+}
+
+static char *findfont(const char* type_face, int style)
+{
+ static char font[1024];
+
+ static char *type[] =
+ {
+ "", /* CD_PLAIN */
+ "-Bold", /* CD_BOLD */
+ "-Oblique", /* CD_ITALIC */
+ "-BoldOblique", /* CD_BOLD_ITALIC */
+
+ "-Roman", /* Plain p/ Times */
+ "-Bold", /* Bold p/ Times */
+ "-Italic", /* Italic p/ Times */
+ "-BoldItalic" /* BoldItalic p/ Times */
+ };
+
+ if (cdStrEqualNoCase(type_face, "System"))
+ type_face = "Courier";
+
+ if (cdStrEqualNoCase(type_face, "Times"))
+ style += 4;
+
+ sprintf(font, "%s%s", type_face, type[style]);
+
+ return font;
+}
+
+static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int size)
+{
+ char *nativefontname = findfont(type_face, style&3); /* no underline or strikeout support */
+ int size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size);
+ fprintf(ctxcanvas->file, "%d /%s /%s-Latin1 ChgFnt\n", size_pixel, nativefontname, nativefontname);
+ add_font_name(ctxcanvas, nativefontname);
+ return 1;
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ set_default_matrix(ctxcanvas);
+
+ if (matrix)
+ {
+ fprintf(ctxcanvas->file, "[%g %g %g %g %g %g] concat\n", matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
+ }
+ else
+ {
+ if (ctxcanvas->rotate_angle)
+ {
+ /* rotation = translate to point + rotation + translate back */
+ fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle);
+ fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+ }
+}
+
+/******************************************************/
+/* client images */
+/******************************************************/
+
+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, rw, rh;
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+ (void)ih;
+
+ if (ctxcanvas->level1)
+ return;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGB Start\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%d %d translate\n", x, y);
+ fprintf(ctxcanvas->file, "%d %d scale\n", w, h);
+
+ fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh);
+ fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh);
+ fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw);
+ fprintf(ctxcanvas->file, "false 3\n");
+ fprintf(ctxcanvas->file, "colorimage\n");
+
+ for (j=ymin; j<=ymax; j++)
+ {
+ for (i=xmin; i<=xmax; i++)
+ {
+ int pos = j*iw+i;
+ fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r[pos], (int)g[pos], (int)b[pos]);
+ }
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, x, y);
+ bbox(ctxcanvas, x+rw-1, y+rh-1);
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectRGBEnd\n");
+}
+
+static int isgray(int size, const unsigned char *index, const long int *colors)
+{
+ int i, pal_size = 0;
+ unsigned char r, g, b;
+
+ for (i = 0; i < size; i++)
+ {
+ if (index[i] > pal_size)
+ pal_size = index[i];
+ }
+
+ pal_size++;
+
+ for (i = 0; i < pal_size; i++)
+ {
+ cdDecodeColor(colors[i], &r, &g, &b);
+
+ if (i != r || r != g || g != b)
+ return 0;
+ }
+
+ return 1;
+}
+
+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, rw, rh, is_gray;
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+ (void)ih;
+
+ is_gray = isgray(iw*ih, index, colors);
+
+ if (!is_gray && ctxcanvas->level1)
+ return;
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMap Start\n");
+
+ fprintf(ctxcanvas->file, "[0 0 0 0 0 0] currentmatrix\n");
+ fprintf(ctxcanvas->file, "%d %d translate\n", x, y);
+ fprintf(ctxcanvas->file, "%d %d scale\n", w, h);
+
+ fprintf(ctxcanvas->file, "%d %d 8\n", rw, rh);
+ fprintf(ctxcanvas->file, "[%d 0 0 %d 0 0]\n", rw, rh);
+ fprintf(ctxcanvas->file, "{currentfile %d string readhexstring pop}\n", rw);
+
+ if (is_gray)
+ {
+ fprintf(ctxcanvas->file, "image\n");
+
+ for (j=ymin; j<=ymax; j++)
+ {
+ for (i=xmin; i<=xmax; i++)
+ {
+ int pos = j*iw+i;
+ fprintf(ctxcanvas->file, "%02x", (int)index[pos]);
+ }
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+ }
+ else
+ {
+ fprintf(ctxcanvas->file, "false 3\n");
+ fprintf(ctxcanvas->file, "colorimage\n");
+
+ for (j=ymin; j<=ymax; j++)
+ {
+ for (i=xmin; i<=xmax; i++)
+ {
+ int pos = j*iw+i;
+ unsigned char r, g, b;
+ cdDecodeColor(colors[index[pos]], &r, &g, &b);
+ fprintf(ctxcanvas->file, "%02x%02x%02x", (int)r, (int)g, (int)b);
+ }
+
+ fprintf(ctxcanvas->file, "\n");
+ }
+ }
+
+ fprintf(ctxcanvas->file, "setmatrix\n");
+
+ if (ctxcanvas->eps)
+ {
+ bbox(ctxcanvas, x, y);
+ bbox(ctxcanvas, x+rw-1, y+rh-1);
+ }
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPutImageRectMapEnd\n");
+}
+
+/******************************************************/
+/* server images */
+/******************************************************/
+
+static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color)
+{
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixel Start\n");
+
+ fprintf(ctxcanvas->file, "%g %g %g setrgbcolor\n",
+ get_red(color), get_green(color), get_blue(color));
+
+ if (ctxcanvas->level1)
+ {
+ fprintf(ctxcanvas->file, "N\n");
+ fprintf(ctxcanvas->file, "%d %d 1 0 360 arc\n", x, y);
+ fprintf(ctxcanvas->file, "C fill\n");
+ }
+ else
+ fprintf(ctxcanvas->file, "%d %d 1 1 RF\n", x, y);
+
+ if (ctxcanvas->eps)
+ bbox(ctxcanvas, x, y);
+
+ if (ctxcanvas->debug) fprintf(ctxcanvas->file, "%%cdPixelEnd\n");
+}
+
+/******************************************************/
+/* custom attributes */
+/******************************************************/
+
+static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ /* ignore ROTATE if transform is set */
+ if (ctxcanvas->canvas->use_matrix)
+ return;
+
+ if (data)
+ {
+ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle,
+ &ctxcanvas->rotate_center_x,
+ &ctxcanvas->rotate_center_y);
+ }
+ else
+ {
+ ctxcanvas->rotate_angle = 0;
+ ctxcanvas->rotate_center_x = 0;
+ ctxcanvas->rotate_center_y = 0;
+ }
+
+ set_default_matrix(ctxcanvas);
+
+ if (ctxcanvas->rotate_angle)
+ {
+ /* rotation = translate to point + rotation + translate back */
+ fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y);
+ fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle);
+ fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y);
+ }
+}
+
+static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char data[100];
+
+ if (!ctxcanvas->rotate_angle)
+ return NULL;
+
+ sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle,
+ ctxcanvas->rotate_center_x,
+ ctxcanvas->rotate_center_y);
+
+ return data;
+}
+
+static cdAttribute rotate_attrib =
+{
+ "ROTATE",
+ set_rotate_attrib,
+ get_rotate_attrib
+};
+
+static void set_cmd_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ fprintf(ctxcanvas->file, data);
+}
+
+static cdAttribute cmd_attrib =
+{
+ "CMD",
+ set_cmd_attrib,
+ NULL
+};
+
+static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data)
+{
+ int hole;
+
+ if (data == NULL)
+ {
+ ctxcanvas->holes = 0;
+ return;
+ }
+
+ sscanf(data, "%d", &hole);
+ ctxcanvas->poly_holes[ctxcanvas->holes] = hole;
+ ctxcanvas->holes++;
+}
+
+static char* get_poly_attrib(cdCtxCanvas *ctxcanvas)
+{
+ static char holes[10];
+ sprintf(holes, "%d", ctxcanvas->holes);
+ return holes;
+}
+
+static cdAttribute poly_attrib =
+{
+ "POLYHOLE",
+ set_poly_attrib,
+ get_poly_attrib
+};
+
+/*
+%F Cria um novo canvas PS
+Parametros passados em data:
+nome nome do arquivo de saida <= 255 caracteres
+-p[num] tamanho do papel (A0-5, LETTER, LEGAL)
+-w[num] largura do papel em milimetros
+-h[num] altura do papel em milimetros
+-l[num] margem esquerda em milimetros
+-r[num] margem direita em milimetros
+-b[num] margem inferior em milimetros
+-t[num] margem superior em milimetros
+-s[num] resolucao em dpi
+-e encapsulated postscript
+-1 level 1 operators only
+-d[num] margem da bbox em milimetros para eps
+*/
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char *line = (char *)data;
+ cdCtxCanvas *ctxcanvas;
+ char filename[10240] = "";
+
+ ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ line += cdGetFileName(line, filename);
+ if (filename[0] == 0)
+ return;
+
+ if ((ctxcanvas->file = fopen(filename, "w")) == NULL)
+ {
+ free(ctxcanvas);
+ return;
+ }
+
+ ctxcanvas->holes = 0;
+ cdRegisterAttribute(canvas, &poly_attrib);
+ cdRegisterAttribute(canvas, &cmd_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+
+ setpsdefaultvalues(ctxcanvas);
+
+ while (*line != '\0')
+ {
+ while (*line != '\0' && *line != '-')
+ line++;
+
+ if (*line != '\0')
+ {
+ float num;
+ line++;
+ switch (*line++)
+ {
+ case 'p':
+ {
+ int paper;
+ sscanf(line, "%d", &paper);
+ setpspapersize(ctxcanvas, paper);
+ break;
+ }
+ case 'w':
+ sscanf(line, "%g", &num);
+ ctxcanvas->width = mm2pt(num);
+ break;
+ case 'h':
+ sscanf(line, "%g", &num);
+ ctxcanvas->height = mm2pt(num);
+ break;
+ case 'l':
+ sscanf(line, "%g", &num);
+ ctxcanvas->xmin = num;
+ break;
+ case 'r':
+ sscanf(line, "%g", &num);
+ ctxcanvas->xmax = num; /* right margin, must be converted to xmax */
+ break;
+ case 'b':
+ sscanf(line, "%g", &num);
+ ctxcanvas->ymin = num;
+ break;
+ case 't':
+ sscanf(line, "%g", &num);
+ ctxcanvas->ymax = num; /* top margin, must be converted to ymax */
+ break;
+ case 's':
+ sscanf(line, "%d", &(ctxcanvas->res));
+ break;
+ case 'e':
+ ctxcanvas->eps = 1;
+ break;
+ case 'o':
+ ctxcanvas->landscape = 1;
+ break;
+ case '1':
+ ctxcanvas->level1 = 1;
+ break;
+ case 'g':
+ ctxcanvas->debug = 1;
+ break;
+ case 'd':
+ sscanf(line, "%g", &num);
+ ctxcanvas->bbmargin = num;
+ break;
+ }
+ }
+
+ while (*line != '\0' && *line != ' ')
+ line++;
+ }
+
+ /* store the base canvas */
+ ctxcanvas->canvas = canvas;
+
+ /* update canvas context */
+ canvas->ctxcanvas = ctxcanvas;
+
+ if (ctxcanvas->landscape == 1)
+ {
+ _cdSwapDouble(ctxcanvas->width, ctxcanvas->height);
+ _cdSwapDouble(ctxcanvas->xmin, ctxcanvas->ymin);
+ _cdSwapDouble(ctxcanvas->xmax, ctxcanvas->ymax);
+ }
+
+ init_ps(ctxcanvas);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ canvas->cxFlush = cdflush;
+ 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->cxPutImageRectRGB = cdputimagerectrgb;
+ 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->cxClip = cdclip;
+ canvas->cxFClipArea = cdfcliparea;
+ canvas->cxLineStyle = cdlinestyle;
+ canvas->cxLineWidth = cdlinewidth;
+ canvas->cxLineCap = cdlinecap;
+ canvas->cxLineJoin = cdlinejoin;
+ canvas->cxPattern = cdpattern;
+ canvas->cxStipple = cdstipple;
+ canvas->cxHatch = cdhatch;
+ canvas->cxFont = cdfont;
+ canvas->cxTransform = cdtransform;
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+static cdContext cdPSContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_PALETTE |
+ CD_CAP_REGION | CD_CAP_IMAGESRV |
+ CD_CAP_BACKGROUND | CD_CAP_BACKOPACITY | CD_CAP_WRITEMODE |
+ CD_CAP_FONTDIM | CD_CAP_TEXTSIZE |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextPS(void)
+{
+ return &cdPSContext;
+}
diff --git a/src/drv/cgm.c b/src/drv/cgm.c
new file mode 100644
index 0000000..55461cb
--- /dev/null
+++ b/src/drv/cgm.c
@@ -0,0 +1,2281 @@
+/** \file
+ * \brief CGM library
+ * Extracted from GKS/PUC
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <float.h>
+#include <limits.h>
+
+#include "cgm.h"
+
+
+struct _cgmFunc
+{
+ /* write command header */
+ void (*wch)( CGM *, int, int, int );
+
+ /* put colour index at colour index precision */
+ void (*ci)( CGM *, unsigned long );
+
+ /* put color direct at colour direct precision */
+ void (*cd)( CGM *, double );
+
+ /* put color direct at colour direct precision */
+ void (*rgb)( CGM *, double, double, double );
+
+ /* put index at index precision */
+ void (*ix)( CGM *, long );
+
+ /* put enum ( int*2 ) */
+ void (*e)( CGM *, int, const char *l[] );
+
+ /* put int ( integer precision ) */
+ void (*i)( CGM *, long );
+
+ /* put unsigned int ( integer precision ) */
+ void (*u)( CGM *, unsigned long );
+
+ /* put real ( real precision ) */
+ void (*r)( CGM *, double );
+
+ /* put string */
+ void (*s)( CGM *, const char * );
+
+ /* put VDC at VDC mode and precision */
+ void (*vdc)( CGM *, double );
+
+ /* put point at VDC mode and precision */
+ void (*p)( CGM *, double, double );
+
+ /* put colour at colour mode and precision */
+ void (*co)( CGM *, const void * );
+
+ /* put separator */
+ void (*sep)( CGM *, const char * );
+
+ /* get column position */
+ int (*get_col)( CGM * );
+
+ /* align at column number */
+ void (*align)( CGM *, int );
+
+ /* nova linha */
+ void (*nl)( CGM * );
+
+ /* terminate element */
+ int (*term)( CGM * );
+};
+
+typedef struct _cgmCommand
+{
+ const char *ct;
+ const char *c;
+} cgmCommand;
+
+/************************************************
+* *
+* Dados para nao-binario *
+* *
+************************************************/
+
+/* delimiter elements */
+
+static const cgmCommand _cgmX_NULL = { "" , "" };
+static const cgmCommand _cgmX_BEGMF = { "BEGMF" , "\x30\x20" };
+static const cgmCommand _cgmX_ENDMF = { "ENDMF" , "\x30\x21" };
+static const cgmCommand _cgmX_BEG_PIC = { "BEG_PIC" , "\x30\x22" };
+static const cgmCommand _cgmX_BEG_PIC_BODY = { "BEG_PIC_BODY" , "\x30\x23" };
+static const cgmCommand _cgmX_END_PIC = { "END_PIC" , "\x30\x24" };
+
+/* metafile descriptor elements */
+
+static const cgmCommand _cgmX_MF_VERSION = { "MF_VERSION" , "\x31\x20" };
+static const cgmCommand _cgmX_MF_DESC = { "MF_DESC" , "\x31\x21" };
+static const cgmCommand _cgmX_VDC_TYPE = { "VDC_TYPE" , "\x31\x22" };
+static const cgmCommand _cgmX_INTEGER_PREC = { "INTEGER_PREC" , "\x31\x23" };
+static const cgmCommand _cgmX_REAL_PREC = { "REAL_PREC" , "\x31\x24" };
+static const cgmCommand _cgmX_INDEX_PREC = { "INDEX_PREC" , "\x31\x25" };
+static const cgmCommand _cgmX_COLR_PREC = { "COLR_PREC" , "\x31\x26" };
+static const cgmCommand _cgmX_COLR_INDEX_PREC = { "COLR_INDEX_PREC" , "\x31\x27" };
+static const cgmCommand _cgmX_MAX_COLR_INDEX = { "MAX_COLR_INDEX" , "\x31\x28" };
+static const cgmCommand _cgmX_COLR_VALUE_EXT = { "COLR_VALUE_EXT" , "\x31\x29" };
+static const cgmCommand _cgmX_MF_ELEM_LIST = { "MF_ELEM_LIST" , "\x31\x2a" };
+static const cgmCommand _cgmX_BEG_MF_DEFAULTS = { "BEG_MF_DEFAULTS" , "\x31\x2b" };
+static const cgmCommand _cgmX_END_MF_DEFAULTS = { "END_MF_DEFAULTS" , "\x31\x2c" };
+static const cgmCommand _cgmX_FONT_LIST = { "FONT_LIST" , "\x31\x2d" };
+static const cgmCommand _cgmX_CHAR_SET_LIST = { "CHAR_SET_LIST" , "\x31\x2e" };
+static const cgmCommand _cgmX_CHAR_CODING = { "CHAR_CODING" , "\x31\x2f" };
+
+/* picture descriptor elements */
+
+static const cgmCommand _cgmX_SCALE_MODE = { "SCALE_MODE" , "\x30\x20" };
+static const cgmCommand _cgmX_COLR_MODE = { "COLR_MODE" , "\x30\x21" };
+static const cgmCommand _cgmX_LINE_WIDTH_MODE = { "LINE_WIDTH_MODE" , "\x30\x22" };
+static const cgmCommand _cgmX_MARKER_SIZE_MODE = { "MARKER_SIZE_MODE" , "\x30\x23" };
+static const cgmCommand _cgmX_EDGE_WIDTH_MODE = { "EDGE_WIDTH_MODE" , "\x30\x24" };
+static const cgmCommand _cgmX_VDC_EXTENT = { "VDC_EXT" , "\x30\x25" };
+static const cgmCommand _cgmX_BACK_COLR = { "BACK_COLR" , "\x30\x26" };
+
+/* control elements */
+
+static const cgmCommand _cgmX_VDC_INTEGER_PREC = { "VDC_INTEGER_PREC" , "\x30\x20" };
+static const cgmCommand _cgmX_VDC_REAL_PREC = { "VDC_REAL_PREC" , "\x30\x21" };
+static const cgmCommand _cgmX_AUX_COLR = { "AUX_COLR" , "\x30\x22" };
+static const cgmCommand _cgmX_TRANSPARENCY = { "TRANSPARENCY" , "\x30\x23" };
+static const cgmCommand _cgmX_CLIP_RECT = { "CLIP_RECT" , "\x30\x24" };
+static const cgmCommand _cgmX_CLIP = { "CLIP" , "\x30\x25" };
+
+/* primitive elements */
+
+static const cgmCommand _cgmX_LINE = { "LINE" , "\x20" };
+static const cgmCommand _cgmX_DISJT_LINE = { "DISJT_LINE" , "\x21" };
+static const cgmCommand _cgmX_MARKER = { "MARKER" , "\x22" };
+static const cgmCommand _cgmX_TEXT = { "TEXT" , "\x23" };
+static const cgmCommand _cgmX_RESTR_TEXT = { "RESTR_TEXT" , "\x24" };
+static const cgmCommand _cgmX_APND_TEXT = { "APND_TEXT" , "\x25" };
+static const cgmCommand _cgmX_POLYGON = { "POLYGON" , "\x26" };
+static const cgmCommand _cgmX_POLYGON_SET = { "POLYGON_SET" , "\x27" };
+static const cgmCommand _cgmX_CELL_ARRAY = { "CELL_ARRAY" , "\x28" };
+static const cgmCommand _cgmX_GDP = { "GDP" , "\x29" };
+static const cgmCommand _cgmX_RECT = { "RECT" , "\x2a" };
+static const cgmCommand _cgmX_CIRCLE = { "CIRCLE" , "\x34\x20" };
+static const cgmCommand _cgmX_ARC_3_PT = { "ARC_3_PT" , "\x34\x21" };
+static const cgmCommand _cgmX_ARC_3_PT_CLOSE = { "ARC_3_PT_CLOSE" , "\x34\x22" };
+static const cgmCommand _cgmX_ARC_CTR = { "ARC_CTR" , "\x34\x23" };
+static const cgmCommand _cgmX_ARC_CTR_CLOSE = { "ARC_CTR_CLOSE" , "\x34\x24" };
+static const cgmCommand _cgmX_ELLIPSE = { "ELLIPSE" , "\x34\x25" };
+static const cgmCommand _cgmX_ELLIP_ARC = { "ELLIP_ARC" , "\x34\x26" };
+static const cgmCommand _cgmX_ELLIP_ARC_CLOSE = { "ELLIP_ARC_CLOSE" , "\x34\x27" };
+
+/* attribute elements */
+
+static const cgmCommand _cgmX_LINE_INDEX = { "LINE_INDEX" , "\x35\x20" };
+static const cgmCommand _cgmX_LINE_TYPE = { "LINE_TYPE" , "\x35\x21" };
+static const cgmCommand _cgmX_LINE_WIDTH = { "LINE_WIDTH" , "\x35\x22" };
+static const cgmCommand _cgmX_LINE_COLR = { "LINE_COLR" , "\x35\x23" };
+static const cgmCommand _cgmX_MARKER_INDEX = { "MARKER_INDEX" , "\x35\x24" };
+static const cgmCommand _cgmX_MARKER_TYPE = { "MARKER_TYPE" , "\x35\x25" };
+static const cgmCommand _cgmX_MARKER_WIDTH = { "MARKER_SIZE" , "\x35\x26" };
+static const cgmCommand _cgmX_MARKER_COLR = { "MARKER_COLR" , "\x35\x27" };
+static const cgmCommand _cgmX_TEXT_INDEX = { "TEXT_INDEX" , "\x35\x30" };
+static const cgmCommand _cgmX_TEXT_FONT_INDEX = { "TEXT_FONT_INDEX" , "\x35\x31" };
+static const cgmCommand _cgmX_TEXT_PREC = { "TEXT_PREC" , "\x35\x32" };
+static const cgmCommand _cgmX_CHAR_EXPAN = { "CHAR_EXPAN" , "\x35\x33" };
+static const cgmCommand _cgmX_CHAR_SPACE = { "CHAR_SPACE" , "\x35\x34" };
+static const cgmCommand _cgmX_TEXT_COLR = { "TEXT_COLR" , "\x35\x35" };
+static const cgmCommand _cgmX_CHAR_HEIGHT = { "CHAR_HEIGHT" , "\x35\x36" };
+static const cgmCommand _cgmX_CHAR_ORI = { "CHAR_ORI" , "\x35\x37" };
+static const cgmCommand _cgmX_TEXT_PATH = { "TEXT_PATH" , "\x35\x38" };
+static const cgmCommand _cgmX_TEXT_ALIGN = { "TEXT_ALIGN" , "\x35\x39" };
+static const cgmCommand _cgmX_CHAR_SET_INDEX = { "CHAR_SET_INDEX" , "\x35\x3a" };
+static const cgmCommand _cgmX_ALT_CHAR_SET = { "ALT_CHAR_SET_INDEX" , "\x35\x3b" };
+static const cgmCommand _cgmX_FILL_INDEX = { "FILL_INDEX" , "\x36\x20" };
+static const cgmCommand _cgmX_INT_STYLE = { "INT_STYLE" , "\x36\x21" };
+static const cgmCommand _cgmX_FILL_COLR = { "FILL_COLR" , "\x36\x22" };
+static const cgmCommand _cgmX_HATCH_INDEX = { "HATCH_INDEX" , "\x36\x23" };
+static const cgmCommand _cgmX_PAT_INDEX = { "PAT_INDEX" , "\x36\x24" };
+static const cgmCommand _cgmX_EDGE_INDEX = { "EDGE_INDEX" , "\x36\x25" };
+static const cgmCommand _cgmX_EDGE_TYPE = { "EDGE_TYPE" , "\x36\x26" };
+static const cgmCommand _cgmX_EDGE_WIDTH = { "EDGE_WIDTH" , "\x36\x27" };
+static const cgmCommand _cgmX_EDGE_COLR = { "EDGE_COLR" , "\x36\x28" };
+static const cgmCommand _cgmX_EDGE_VIS = { "EDGE_VIS" , "\x36\x29" };
+static const cgmCommand _cgmX_FILL_REF_PT = { "FILL_REF_PT" , "\x36\x2a" };
+static const cgmCommand _cgmX_PAT_TABLE = { "PAT_TABLE" , "\x36\x2b" };
+static const cgmCommand _cgmX_PAT_SIZE = { "PAT_SIZE" , "\x36\x2c" };
+static const cgmCommand _cgmX_COLR_TABLE = { "COLR_TABLE" , "\x36\x30" };
+static const cgmCommand _cgmX_ASF = { "ASF" , "\x36\x31" };
+
+/* escape elements */
+
+static const cgmCommand _cgmX_ESCAPE = { "ESCAPE" , "\x37\x20" };
+static const cgmCommand _cgmX_DOMAIN_RING = { "DOMAIN_RING" , "\x37\x30" };
+
+/* external elements */
+
+static const cgmCommand _cgmX_MESSAGE = { "MESSAGE" , "\x37\x21" };
+static const cgmCommand _cgmX_APPL_DATA = { "APPL_DATA" , "\x37\x22" };
+
+/* drawing sets */
+static const cgmCommand _cgmX_DRAWING_SET = { "drawing_set" , "\x40" };
+static const cgmCommand _cgmX_DRAWING_PLUS = { "drawing_plus" , "\x41" };
+
+static const cgmCommand *_elements_list_sets[] = {
+ & _cgmX_DRAWING_SET,
+ & _cgmX_DRAWING_PLUS,
+ NULL };
+
+
+static const cgmCommand *delimiter[] = {
+ & _cgmX_NULL,
+ & _cgmX_BEGMF,
+ & _cgmX_ENDMF,
+ & _cgmX_BEG_PIC,
+ & _cgmX_BEG_PIC_BODY,
+ & _cgmX_END_PIC,
+ NULL };
+
+static const cgmCommand *metafile[] = {
+ & _cgmX_END_MF_DEFAULTS,
+ & _cgmX_MF_VERSION,
+ & _cgmX_MF_DESC,
+ & _cgmX_VDC_TYPE,
+ & _cgmX_INTEGER_PREC,
+ & _cgmX_REAL_PREC,
+ & _cgmX_INDEX_PREC,
+ & _cgmX_COLR_PREC,
+ & _cgmX_COLR_INDEX_PREC,
+ & _cgmX_MAX_COLR_INDEX,
+ & _cgmX_COLR_VALUE_EXT,
+ & _cgmX_MF_ELEM_LIST,
+ & _cgmX_BEG_MF_DEFAULTS,
+ & _cgmX_FONT_LIST,
+ & _cgmX_CHAR_SET_LIST,
+ & _cgmX_CHAR_CODING,
+ NULL };
+
+static const cgmCommand *picture[] = {
+ & _cgmX_NULL,
+ & _cgmX_SCALE_MODE,
+ & _cgmX_COLR_MODE,
+ & _cgmX_LINE_WIDTH_MODE,
+ & _cgmX_MARKER_SIZE_MODE,
+ & _cgmX_EDGE_WIDTH_MODE,
+ & _cgmX_VDC_EXTENT,
+ & _cgmX_BACK_COLR,
+ NULL };
+
+static const cgmCommand *control[] = {
+ & _cgmX_NULL,
+ & _cgmX_VDC_INTEGER_PREC,
+ & _cgmX_VDC_REAL_PREC,
+ & _cgmX_AUX_COLR,
+ & _cgmX_TRANSPARENCY,
+ & _cgmX_CLIP_RECT,
+ & _cgmX_CLIP,
+ NULL };
+
+static const cgmCommand *primitive[] = {
+ & _cgmX_NULL,
+ & _cgmX_LINE,
+ & _cgmX_DISJT_LINE,
+ & _cgmX_MARKER,
+ & _cgmX_TEXT,
+ & _cgmX_RESTR_TEXT,
+ & _cgmX_APND_TEXT,
+ & _cgmX_POLYGON,
+ & _cgmX_POLYGON_SET,
+ & _cgmX_CELL_ARRAY,
+ & _cgmX_GDP,
+ & _cgmX_RECT,
+ & _cgmX_CIRCLE,
+ & _cgmX_ARC_3_PT,
+ & _cgmX_ARC_3_PT_CLOSE,
+ & _cgmX_ARC_CTR,
+ & _cgmX_ARC_CTR_CLOSE,
+ & _cgmX_ELLIPSE,
+ & _cgmX_ELLIP_ARC,
+ & _cgmX_ELLIP_ARC_CLOSE,
+ NULL };
+
+static const cgmCommand *attributes[] = {
+ & _cgmX_NULL,
+ & _cgmX_LINE_INDEX,
+ & _cgmX_LINE_TYPE,
+ & _cgmX_LINE_WIDTH,
+ & _cgmX_LINE_COLR,
+ & _cgmX_MARKER_INDEX,
+ & _cgmX_MARKER_TYPE,
+ & _cgmX_MARKER_WIDTH,
+ & _cgmX_MARKER_COLR,
+ & _cgmX_TEXT_INDEX,
+ & _cgmX_TEXT_FONT_INDEX,
+ & _cgmX_TEXT_PREC,
+ & _cgmX_CHAR_EXPAN,
+ & _cgmX_CHAR_SPACE,
+ & _cgmX_TEXT_COLR,
+ & _cgmX_CHAR_HEIGHT,
+ & _cgmX_CHAR_ORI,
+ & _cgmX_TEXT_PATH,
+ & _cgmX_TEXT_ALIGN,
+ & _cgmX_CHAR_SET_INDEX,
+ & _cgmX_ALT_CHAR_SET,
+ & _cgmX_FILL_INDEX,
+ & _cgmX_INT_STYLE,
+ & _cgmX_FILL_COLR,
+ & _cgmX_HATCH_INDEX,
+ & _cgmX_PAT_INDEX,
+ & _cgmX_EDGE_INDEX,
+ & _cgmX_EDGE_TYPE,
+ & _cgmX_EDGE_WIDTH,
+ & _cgmX_EDGE_COLR,
+ & _cgmX_EDGE_VIS,
+ & _cgmX_FILL_REF_PT,
+ & _cgmX_PAT_TABLE,
+ & _cgmX_PAT_SIZE,
+ & _cgmX_COLR_TABLE,
+ & _cgmX_ASF,
+ NULL };
+
+static const cgmCommand *escape[] = {
+ & _cgmX_NULL,
+ & _cgmX_ESCAPE,
+ & _cgmX_DOMAIN_RING,
+ NULL };
+
+static const cgmCommand *external[] = {
+ & _cgmX_NULL,
+ & _cgmX_MESSAGE,
+ & _cgmX_APPL_DATA,
+ NULL };
+
+static const cgmCommand **comandos[] = {
+ _elements_list_sets,
+ delimiter,
+ metafile,
+ picture,
+ control,
+ primitive,
+ attributes,
+ escape,
+ external,
+ NULL };
+
+#define unit (cgm->file)
+
+/************************************************
+* *
+* listas de funcoes necessarias *
+* *
+************************************************/
+
+
+static void cgmb_wch ( CGM *, int, int, int ); /* write command header */
+static void cgmb_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */
+static void cgmb_cd ( CGM *, double ); /* put color direct at colour direct precision */
+static void cgmb_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */
+static void cgmb_ix ( CGM *, long ); /* put index at index precision */
+static void cgmb_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */
+static void cgmb_i ( CGM *, long ); /* put int ( integer precision ) */
+static void cgmb_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */
+static void cgmb_r ( CGM *, double ); /* put real ( real precision ) */
+static void cgmb_s ( CGM *, const char * ); /* put string */
+static void cgmb_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */
+static void cgmb_p ( CGM *, double, double ); /* put point at VDC mode and precision */
+static void cgmb_co ( CGM *, const void * ); /* put colour at colour mode and precision */
+static void cgmb_sep ( CGM *, const char * ); /* put separator */
+static int cgmb_get_col ( CGM * ); /* get column position */
+static void cgmb_align ( CGM *, int ); /* align at column number */
+static void cgmb_nl ( CGM * ); /* new line */
+static int cgmb_term ( CGM * ); /* terminate element */
+
+static const CGMFUNC cgmf_binary = {
+ cgmb_wch ,
+ cgmb_ci ,
+ cgmb_cd ,
+ cgmb_rgb ,
+ cgmb_ix ,
+ cgmb_e ,
+ cgmb_i ,
+ cgmb_u ,
+ cgmb_r ,
+ cgmb_s ,
+ cgmb_vdc ,
+ cgmb_p ,
+ cgmb_co ,
+ cgmb_sep ,
+ cgmb_get_col,
+ cgmb_align ,
+ cgmb_nl ,
+ cgmb_term
+ };
+
+static void cgmt_wch ( CGM *, int, int, int ); /* write command header */
+static void cgmt_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */
+static void cgmt_cd ( CGM *, double ); /* put color direct at colour direct precision */
+static void cgmt_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */
+static void cgmt_ix ( CGM *, long ); /* put index at index precision */
+static void cgmt_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */
+static void cgmt_i ( CGM *, long ); /* put int ( integer precision ) */
+static void cgmt_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */
+static void cgmt_r ( CGM *, double ); /* put real ( real precision ) */
+static void cgmt_s ( CGM *, const char * ); /* put string */
+static void cgmt_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */
+static void cgmt_p ( CGM *, double, double ); /* put point at VDC mode and precision */
+static void cgmt_co ( CGM *, const void * ); /* put colour at colour mode and precision */
+static void cgmt_sep ( CGM *, const char * ); /* put separator */
+static int cgmt_get_col ( CGM * ); /* get column position */
+static void cgmt_align ( CGM *, int ); /* align at column number */
+static void cgmt_nl ( CGM * ); /* new line */
+static int cgmt_term ( CGM * ); /* terminate element */
+
+static const CGMFUNC cgmf_clear_text = {
+ cgmt_wch ,
+ cgmt_ci ,
+ cgmt_cd ,
+ cgmt_rgb ,
+ cgmt_ix ,
+ cgmt_e ,
+ cgmt_i ,
+ cgmt_u ,
+ cgmt_r ,
+ cgmt_s ,
+ cgmt_vdc ,
+ cgmt_p ,
+ cgmt_co ,
+ cgmt_sep ,
+ cgmt_get_col,
+ cgmt_align ,
+ cgmt_nl ,
+ cgmt_term
+ };
+
+static void cgmc_wch ( CGM *, int, int, int ); /* write command header */
+static void cgmc_ci ( CGM *, unsigned long ); /* put colour index at colour index precision */
+static void cgmc_cd ( CGM *, double ); /* put color direct at colour direct precision */
+static void cgmc_rgb ( CGM *, double, double, double ); /* put color direct (rgb) at colour direct precision */
+static void cgmc_ix ( CGM *, long ); /* put index at index precision */
+static void cgmc_e ( CGM *, int, const char *l[] ); /* put enum ( int*2 ) */
+static void cgmc_i ( CGM *, long ); /* put int ( integer precision ) */
+static void cgmc_u ( CGM *, unsigned long ); /* put unsigned int ( integer precision ) */
+static void cgmc_r ( CGM *, double ); /* put real ( real precision ) */
+static void cgmc_s ( CGM *, const char * ); /* put string */
+static void cgmc_vdc ( CGM *, double ); /* put VDC at VDC mode and precision */
+static void cgmc_p ( CGM *, double, double ); /* put point at VDC mode and precision */
+static void cgmc_co ( CGM *, const void * ); /* put colour at colour mode and precision */
+static void cgmc_sep ( CGM *, const char * ); /* put separator */
+static int cgmc_get_col ( CGM * ); /* get column position */
+static void cgmc_align ( CGM *, int ); /* align at column number */
+static void cgmc_nl ( CGM * ); /* new line */
+static int cgmc_term ( CGM * ); /* terminate element */
+
+static const CGMFUNC cgmf_character = {
+ cgmc_wch ,
+ cgmc_ci ,
+ cgmc_cd ,
+ cgmc_rgb ,
+ cgmc_ix ,
+ cgmc_e ,
+ cgmc_i ,
+ cgmc_u ,
+ cgmc_r ,
+ cgmc_s ,
+ cgmc_vdc ,
+ cgmc_p ,
+ cgmc_co ,
+ cgmc_sep ,
+ cgmc_get_col,
+ cgmc_align ,
+ cgmc_nl ,
+ cgmc_term
+ };
+
+static const CGMFUNC *cgmf[] = { &cgmf_character, &cgmf_binary, &cgmf_clear_text };
+
+/************************************************
+* *
+* Funcoes para binario *
+* *
+************************************************/
+
+#define cgmb_putw cgmb_putu16
+#define cgmb_putb(a,b) cgmb_putc((a),(int)(b))
+
+static void cgmb_putw ( CGM *, unsigned );
+
+static void cgmb_putc ( CGM *cgm, int b )
+{
+ if ( cgm->op != -1 )
+ {
+ register int i;
+ for ( i=cgm->op; i>=0; i-- )
+ {
+ if ( cgm->bc[i] == 32766 - 2*i )
+ {
+ long po = ftell(unit);
+ int op = cgm->op;
+
+ cgm->op = -1;
+ fseek(unit, cgm->po[i] , SEEK_SET);
+ cgmb_putw ( cgm, (1 << 15) | (cgm->bc[i]) );
+
+ cgm->op = i - 1;
+ fseek(unit, po, SEEK_SET);
+ cgmb_putw ( cgm, 0 );
+
+ cgm->op = op;
+ cgm->bc[i] = 0;
+ cgm->po[i] = po;
+ }
+ cgm->bc[i] ++;
+ }
+ }
+
+ fputc ( b, unit );
+}
+
+
+static void cgmb_puti8 ( CGM *cgm, int b )
+{
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_puti16 ( CGM *cgm, int b )
+{
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_puti24 ( CGM *cgm, long b )
+{
+ cgmb_putb ( cgm, b >> 16 );
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_puti32 ( CGM *cgm, long b )
+{
+ cgmb_putb ( cgm, b >> 24 );
+ cgmb_putb ( cgm, b >> 16 );
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_putu8 ( CGM *cgm, unsigned int b )
+{
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_putu16 ( CGM *cgm, unsigned int b )
+{
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_putu24 ( CGM *cgm, unsigned long b )
+{
+ cgmb_putb ( cgm, b >> 16 );
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_putu32 ( CGM *cgm, unsigned long b )
+{
+ cgmb_putb ( cgm, b >> 24 );
+ cgmb_putb ( cgm, b >> 16 );
+ cgmb_putb ( cgm, b >> 8 );
+ cgmb_putb ( cgm, b );
+}
+
+static void cgmb_putfl32 ( CGM *cgm, float b )
+{
+ union {
+ float func;
+ long l;
+ } r;
+ r.func = b;
+ cgmb_putb ( cgm, r.l >> 24 );
+ cgmb_putb ( cgm, r.l >> 16 );
+ cgmb_putb ( cgm, r.l >> 8 );
+ cgmb_putb ( cgm, r.l );
+}
+
+static void cgmb_putfl64 ( CGM *cgm, double b )
+{
+ union {
+ double d;
+ long l[2];
+ } r;
+ r.d = b;
+ cgmb_putb ( cgm, r.l[1] >> 24 );
+ cgmb_putb ( cgm, r.l[1] >> 16 );
+ cgmb_putb ( cgm, r.l[1] >> 8 );
+ cgmb_putb ( cgm, r.l[1] );
+ cgmb_putb ( cgm, r.l[0] >> 24 );
+ cgmb_putb ( cgm, r.l[0] >> 16 );
+ cgmb_putb ( cgm, r.l[0] >> 8 );
+ cgmb_putb ( cgm, r.l[0] );
+}
+
+static void cgmb_putfx32 ( CGM *cgm, float b )
+{
+ int si = ( int ) floor ( b );
+ unsigned int ui = ( unsigned int ) ( (b - si) * 65536.0 );
+
+ cgmb_puti16 ( cgm, si );
+ cgmb_puti16 ( cgm, ui );
+}
+
+static void cgmb_putfx64 ( CGM *cgm, double b )
+{
+ long si = ( long ) floor ( b );
+ unsigned long ui = ( unsigned long ) ( (b - si) * 65536.0 * 65536.0 );
+
+ cgmb_puti32 ( cgm, si );
+ cgmb_puti32 ( cgm, ui );
+}
+
+static void cgmb_wch ( CGM* cgm, int c, int id, int len )
+{
+
+ /* if ( len & 1 ) len ++; */ /* word aligned */
+
+ if ( len > 30 )
+ cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | 31 );
+ else
+ cgmb_putw ( cgm, (c << 12) | ( id << 5 ) | (int)(len) );
+
+
+ cgm->op++;
+
+ if ( len > 30 )
+ {
+ cgm->po[cgm->op] = ftell(unit);
+ cgmb_putw ( cgm, 0 );
+ }
+ else
+ cgm->po[cgm->op] = 0L;
+
+ cgm->bc[cgm->op] = 0;
+
+}
+
+static void cgmb_ci ( CGM *cgm, unsigned long ci )
+{
+ switch ( cgm->cix_prec )
+ {
+ case 0: cgmb_putu8 ( cgm, (unsigned)ci ); break;
+ case 1: cgmb_putu16 ( cgm, (unsigned)ci ); break;
+ case 2: cgmb_putu24 ( cgm, ci ); break;
+ case 3: cgmb_putu32 ( cgm, ci ); break;
+ }
+}
+
+static void cgmb_cd ( CGM *cgm, double cd )
+{
+ unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1));
+ switch ( cgm->cd_prec )
+ {
+ case 0: cgmb_putu8 ( cgm, (unsigned)cv ); break;
+ case 1: cgmb_putu16 ( cgm, (unsigned)cv ); break;
+ case 2: cgmb_putu24 ( cgm, cv ); break;
+ case 3: cgmb_putu32 ( cgm, cv ); break;
+ }
+}
+
+static void cgmb_rgb ( CGM *cgm, double r, double g, double b )
+{
+ cgmb_cd ( cgm, r );
+ cgmb_cd ( cgm, g );
+ cgmb_cd ( cgm, b );
+}
+
+static void cgmb_ix ( CGM *cgm, long ix )
+{
+ switch ( cgm->ix_prec )
+ {
+ case 0: cgmb_puti8 ( cgm, (int)ix ); break;
+ case 1: cgmb_puti16 ( cgm, (int)ix ); break;
+ case 2: cgmb_puti24 ( cgm, ix ); break;
+ case 3: cgmb_puti32 ( cgm, ix ); break;
+ }
+}
+
+static void cgmb_e ( CGM *cgm, int e, const char *el[] )
+{
+ cgmb_puti16 ( cgm, e );
+}
+
+static void cgmb_i ( CGM *cgm, long i )
+{
+ switch ( cgm->int_prec )
+ {
+ case 0: cgmb_puti8 ( cgm, (int)i ); break;
+ case 1: cgmb_puti16 ( cgm, (int)i ); break;
+ case 2: cgmb_puti24 ( cgm, i ); break;
+ case 3: cgmb_puti32 ( cgm, i ); break;
+ }
+}
+
+static void cgmb_u ( CGM *cgm, unsigned long i )
+{
+ switch ( cgm->int_prec )
+ {
+ case 0: cgmb_putu8 ( cgm, (unsigned)i ); break;
+ case 1: cgmb_putu16 ( cgm, (unsigned)i ); break;
+ case 2: cgmb_putu24 ( cgm, i ); break;
+ case 3: cgmb_putu32 ( cgm, i ); break;
+ }
+}
+
+static void cgmb_r ( CGM *cgm, double func )
+{
+ switch ( cgm->real_prec )
+ {
+ case 0: cgmb_putfl32 ( cgm, (float )func ); break;
+ case 1: cgmb_putfl64 ( cgm, (double)func ); break;
+ case 2: cgmb_putfx32 ( cgm, (float )func ); break;
+ case 3: cgmb_putfx64 ( cgm, (double)func ); break;
+ }
+}
+
+static void cgmb_s ( CGM *cgm, const char *s )
+{
+ register unsigned i;
+ unsigned l = strlen(s);
+ int bc = 0;
+
+ if ( l > 254 )
+ {
+ cgmb_putu8(cgm,255);
+ if ( l > 32763 )
+ cgmb_putu16 ( cgm, (1<<16) | 32763 );
+ else
+ cgmb_putu16 ( cgm, l );
+ bc = 1;
+ }
+ else
+ cgmb_putu8(cgm,l);
+
+ for ( i=0; s[i]; s++ )
+ {
+ if ( (i + bc) == 32766 )
+ {
+ l -= i;
+ s += i;
+ i = 0;
+ bc = 0;
+ if ( l > 32764 )
+ cgmb_putu16 ( cgm, (1<<16) | 32764 );
+ else
+ cgmb_putu16 ( cgm, l );
+ }
+ cgmb_putc ( cgm, s[i] );
+ }
+}
+
+static void cgmb_vdc ( CGM *cgm, double vdc)
+{
+ if ( cgm->vdc_type == 0 )
+ switch ( cgm->vdc_int )
+ {
+ case 0: cgmb_puti8 ( cgm, (int )vdc ); break;
+ case 1:
+ /* Evita overflow em ambientes de 32 bits */
+ if (vdc < -32768) vdc = -32768;
+ else if (vdc > 32767) vdc = +32767;
+ cgmb_puti16 ( cgm, (int) vdc );
+ break;
+ case 2: cgmb_puti24 ( cgm, (long)vdc ); break;
+ case 3:
+ /* Evita overflow em ambientes de 32 bits */
+ if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0;
+ else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0;
+ cgmb_puti32 ( cgm, (long)vdc );
+ break;
+
+ }
+ else
+ switch ( cgm->vdc_real )
+ {
+ case 0: cgmb_putfl32 ( cgm, (float )vdc ); break;
+ case 1: cgmb_putfl64 ( cgm, (double)vdc ); break;
+ case 2: cgmb_putfx32 ( cgm, (float )vdc ); break;
+ case 3: cgmb_putfx64 ( cgm, (double)vdc ); break;
+ }
+
+}
+
+static void cgmb_p ( CGM *cgm, double x, double y)
+{
+ cgmb_vdc ( cgm, x );
+ cgmb_vdc ( cgm, y );
+}
+
+static void cgmb_co ( CGM *cgm, const void * co)
+{
+ if ( cgm->clrsm == 0 ) /* indexed */
+ {
+ unsigned long ci = *(unsigned long *)co;
+ cgmb_ci ( cgm, ci );
+ }
+ else
+ {
+ double *cb = (double *) co;
+ cgmb_rgb ( cgm, cb[0], cb[1], cb[2] );
+ }
+}
+
+static void cgmb_sep ( CGM *cgm, const char * sep )
+{}
+
+static int cgmb_get_col ( CGM *cgm )
+{
+ return 0;
+}
+
+static void cgmb_align ( CGM *cgm, int n )
+{}
+
+static void cgmb_nl ( CGM *cgm )
+{}
+
+static int cgmb_term ( CGM *cgm )
+{
+ if ( cgm->op != -1 )
+ {
+ if ( cgm->bc[cgm->op] & 1 )
+ {
+ cgmb_putb( cgm, 0 );
+ cgm->bc[cgm->op] --;
+ }
+
+ if ( cgm->po[cgm->op] != 0L )
+ {
+ long po = ftell(unit);
+ int op = cgm->op;
+
+ cgm->op = -1;
+ fseek ( unit, cgm->po[op], SEEK_SET);
+ cgmb_putw ( cgm, cgm->bc[op] );
+
+ fseek ( unit, po, SEEK_SET );
+ cgm->op = op;
+ }
+ cgm->op --;
+ }
+
+ return 0;
+}
+
+/************************************************
+* *
+* Funcoes para clear text *
+* *
+************************************************/
+
+static void cgmt_wch ( CGM* cgm, int c, int id, int len )
+{
+ cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct );
+}
+
+static void cgmt_ci ( CGM *cgm, unsigned long ci )
+{
+ cgm->func->u ( cgm, ci );
+}
+
+static void cgmt_cd ( CGM *cgm, double cd )
+{
+ unsigned long cv = (unsigned long) (cd * (pow(2.0, (cgm->cd_prec + 1) * 8.0) - 1));
+
+ cgm->func->u ( cgm, cv );
+}
+
+static void cgmt_rgb ( CGM *cgm, double r, double g, double b )
+{
+ cgm->func->cd ( cgm, r );
+ cgm->func->cd ( cgm, g );
+ cgm->func->cd ( cgm, b );
+}
+
+static void cgmt_ix ( CGM *cgm, long ix )
+{
+ cgm->func->i ( cgm, ix );
+}
+
+static void cgmt_e ( CGM *cgm, int e, const char *el[] )
+{
+ cgm->cl += fprintf ( unit, " %s", el[e] );
+}
+
+static void cgmt_i ( CGM *cgm, long i )
+{
+ cgm->cl += fprintf ( unit, " %ld", i );
+}
+
+static void cgmt_u ( CGM *cgm, unsigned long i )
+{
+ cgm->cl += fprintf ( unit, " %lu", i );
+}
+
+static void cgmt_r ( CGM *cgm, double func )
+{
+ cgm->cl += fprintf ( unit, " %g", func );
+}
+
+static void cgmt_s ( CGM *cgm, const char *s )
+{
+ register unsigned i;
+ fputc ( 34, unit );
+
+ for ( i=0; s[i]; i++ )
+ {
+ if ( s[i] == 34 )
+ {
+ fputc ( 34, unit );
+ cgm->cl ++;
+ }
+ fputc ( s[i], unit );
+ }
+
+ fputc ( 34, unit );
+ cgm->cl += strlen (s) + 2;
+}
+
+static void cgmt_vdc ( CGM *cgm, double vdc)
+{
+ if ( cgm->vdc_type == 0 )
+ {
+ /* Evita overflow em ambientes de 32 bits */
+ if (vdc < (double)-2147483648.0) vdc = (double)-2147483648.0;
+ else if (vdc > (double)2147483647.0) vdc = (double)2147483647.0;
+
+ cgm->func->i ( cgm, (long) vdc );
+ }
+ else
+ cgm->func->r ( cgm, vdc );
+}
+
+static void cgmt_p ( CGM *cgm, double x, double y)
+{
+ cgm->func->sep ( cgm, "(" );
+ cgm->func->vdc ( cgm, x );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, y );
+ cgm->func->sep ( cgm, ")" );
+}
+
+static void cgmt_co ( CGM *cgm, const void * co)
+{
+ if ( cgm->clrsm == 0 ) /* indexed */
+ {
+ unsigned long ci = *(unsigned *)co;
+ cgm->func->ci ( cgm, ci );
+ }
+ else
+ {
+ double *cb = (double *) co;
+ cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] );
+ }
+}
+
+static void cgmt_sep ( CGM *cgm, const char * sep )
+{
+ cgm->cl += fprintf ( unit, " %s", sep );
+}
+
+static int cgmt_get_col ( CGM *cgm )
+{
+ return cgm->cl;
+}
+
+static void cgmt_align ( CGM *cgm, int n )
+{
+ for ( ; cgm->cl < n ; cgm->cl ++ )
+ fputc ( ' ', unit );
+}
+
+static void cgmt_nl ( CGM *cgm )
+{
+ fputc ( '\n', unit );
+ cgm->cl = 1;
+}
+
+static int cgmt_term ( CGM *cgm )
+{
+ fputc ( ';', unit );
+ cgm->func->nl(cgm);
+ return 0;
+}
+
+/************************************************
+* *
+* Funcoes para character *
+* *
+************************************************/
+
+static void cgmc_wch ( CGM* cgm, int c, int id, int len )
+{
+ cgm->cl += fprintf ( unit, "%s", comandos[c+1][id]->ct );
+}
+
+static void cgmc_ci ( CGM *cgm, unsigned long ci )
+{
+ cgm->func->u ( cgm, ci );
+}
+
+static void cgmc_cd ( CGM *cgm, double cd )
+{
+ cgm->func->r ( cgm, cd );
+}
+
+static void cgmc_rgb ( CGM *cgm, double r, double g, double b )
+{
+ cgm->func->cd ( cgm, r );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->cd ( cgm, g );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->cd ( cgm, b );
+}
+
+static void cgmc_ix ( CGM *cgm, long ix )
+{
+ cgm->func->i ( cgm, ix );
+}
+
+static void cgmc_e ( CGM *cgm, int e, const char *el[] )
+{
+ cgm->cl += fprintf ( unit, " %s", el[e] );
+}
+
+static void cgmc_i ( CGM *cgm, long i )
+{
+ cgm->cl += fprintf ( unit, " %ld", i );
+}
+
+static void cgmc_u ( CGM *cgm, unsigned long i )
+{
+ cgm->cl += fprintf ( unit, " %lu", i );
+}
+
+static void cgmc_r ( CGM *cgm, double func )
+{
+ cgm->cl += fprintf ( unit, " %g", func );
+}
+
+static void cgmc_s ( CGM *cgm, const char *s )
+{
+ register unsigned i;
+ fputc ( 34, unit );
+
+ for ( i=0; s[i]; i++ )
+ {
+ if ( s[i] == 34 )
+ {
+ fputc ( 34, unit );
+ cgm->cl ++;
+ }
+ fputc ( s[i], unit );
+ }
+
+ fputc ( 34, unit );
+ cgm->cl += strlen (s) + 2;
+}
+
+static void cgmc_vdc ( CGM *cgm, double vdc)
+{
+ if ( cgm->vdc_type == 0 )
+ cgm->func->i ( cgm, (long) vdc );
+ else
+ cgm->func->r ( cgm, vdc );
+}
+
+static void cgmc_p ( CGM *cgm, double x, double y)
+{
+ cgm->func->sep ( cgm, "(" );
+ cgm->func->vdc ( cgm, x );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, y );
+ cgm->func->sep ( cgm, ")" );
+}
+
+static void cgmc_co ( CGM *cgm, const void * co)
+{
+ if ( cgm->clrsm == 0 ) /* indexed */
+ {
+ unsigned long ci = *(unsigned long *)co;
+ cgm->func->ci ( cgm, ci );
+ }
+ else
+ {
+ double *cb = (double *) co;
+ cgm->func->rgb ( cgm, cb[0], cb[1], cb[2] );
+ }
+}
+
+static void cgmc_sep ( CGM *cgm, const char * sep )
+{
+ cgm->cl += fprintf ( unit, " %s", sep );
+}
+
+static int cgmc_get_col ( CGM *cgm )
+{
+ return cgm->cl;
+}
+
+static void cgmc_align ( CGM *cgm, int n )
+{
+ for ( ; cgm->cl < n ; cgm->cl ++ )
+ fputc ( ' ', unit );
+}
+
+static void cgmc_nl ( CGM *cgm )
+{
+ fputc ( '\n', unit );
+ cgm->cl = 1;
+}
+
+static int cgmc_term ( CGM *cgm )
+{
+ fputc ( ';', unit );
+ cgm->func->nl(cgm);
+ return 0;
+}
+
+/************************************************
+* *
+* independente de codificacao *
+* *
+************************************************/
+
+
+/* Definicoes de precisao */
+
+static const long _cgm_int_precs[][2] = {
+ { -128, 127 }, /* 8 */
+ { -32768L, 32767 }, /* 16 */
+ { LONG_MIN >> 8, LONG_MAX >> 8 }, /* 24 */
+ { LONG_MIN , LONG_MAX } }; /* 32 */
+
+static int _cgm_ireal_precs[][4] = {
+ { 0, 9, 23, 0 }, /* float*32 */
+ { 0, 12, 52, 0 }, /* float*64 */
+ { 1, 16, 16, 5 }, /* fixed*32 */
+ { 1, 32, 32, 9 } }; /* fixed*64 */
+
+static double _cgm_rreal_precs[][2] = {
+ /* float*32 */ { 0, 0 }, /* Em Turbo C, FLT_MAX e DLB_MAX sao */
+ /* float*64 */ { 0, 0 }, /* DEFINES para variaveis externas */
+ /* fixed*32 */ { - (32769.0 - 1.0 / 65536.0),
+ 32768.0 - 1.0 / 65536.0 },
+ /* fixed*64 */ { (double)(LONG_MIN) - ( 1 - 1 / ( 65536.0 * 65536.0 ) ),
+ (double)(LONG_MAX) + ( 1 - 1 / ( 65536.0 * 65536.0 ) ) } };
+
+/* Enumeraveis genericos */
+
+static const char *offon[] = { "OFF", "ON" };
+
+/*********************
+* Delimiter elements *
+*********************/
+
+CGM *cgm_begin_metafile ( char *file, int mode, char *header )
+{
+ CGM *cgm;
+
+ if ( (cgm = (CGM *)malloc ( sizeof (CGM) ) ) == NULL )
+ return NULL;
+
+#ifdef __VAXC__
+
+ if ( mode == 2 )
+ cgm->file = fopen ( file , "w" , "rfm=var", "rat=cr" );
+ else
+ cgm->file = fopen ( file , "w+b", "rfm=var", "ctx=stm" );
+
+#else
+
+ if ( mode == 2 )
+ cgm->file = fopen ( file , "w" );
+ else
+ cgm->file = fopen ( file , "w+b" );
+
+#endif
+
+ if ( cgm->file == NULL )
+ {
+ free ( cgm );
+ return NULL;
+ }
+
+ cgm->mode = mode;
+ cgm->func = cgmf[mode];
+
+ cgm->vdc_type = 0;
+ cgm->int_prec = 1;
+ cgm->real_prec = 2;
+ cgm->ix_prec = 1;
+ cgm->cd_prec = 0;
+ cgm->cix_prec = 0;
+ cgm->max_cix = 63;
+
+ cgm->clrsm = 0;
+ cgm->lnwsm = 1;
+ cgm->mkssm = 1;
+ cgm->edwsm = 1;
+ cgm->vdc_int = 1;
+ cgm->vdc_real = 2;
+
+ cgm->vdc_size = 2;
+ cgm->int_size = 2;
+ cgm->real_size = 4;
+ cgm->ix_size = 3;
+ cgm->cd_size = 3;
+ cgm->cix_size = 1;
+ cgm->clr_size = 1;
+ cgm->lnw_size = 4;
+ cgm->mks_size = 4;
+ cgm->edw_size = 4;
+
+ cgm->cl = 1;
+
+ cgm->op = -1;
+
+ cgm->func->wch ( cgm, 0, 1, strlen ( header ) + 1 );
+
+ cgm->func->s ( cgm, header );
+
+ cgm->func->term ( cgm );
+
+ _cgm_ireal_precs[0][3] = FLT_DIG;
+ _cgm_ireal_precs[1][3] = DBL_DIG;
+
+ _cgm_rreal_precs[0][0] = - FLT_MAX;
+ _cgm_rreal_precs[0][1] = FLT_MAX;
+ _cgm_rreal_precs[1][0] = - DBL_MAX;
+ _cgm_rreal_precs[1][1] = DBL_MAX;
+
+ return cgm;
+}
+
+int cgm_end_metafile ( CGM *cgm )
+{
+ cgm->func->wch ( cgm, 0, 2, 0 );
+ cgm->func->term ( cgm );
+
+ fclose ( cgm->file );
+ cgm->file = NULL;
+ free ( cgm );
+
+ return 0;
+}
+
+int cgm_begin_picture (CGM *cgm, const char *s )
+{
+ cgm->func->wch ( cgm, 0, 3, strlen(s)+1 );
+ cgm->func->s ( cgm, s );
+ return cgm->func->term(cgm);
+}
+
+int cgm_begin_picture_body ( CGM *cgm )
+{
+ cgm->func->wch ( cgm, 0, 4, 0 );
+ return cgm->func->term(cgm);
+}
+
+int cgm_end_picture ( CGM *cgm )
+{
+ cgm->func->wch ( cgm, 0, 5, 0 );
+ return cgm->func->term(cgm);
+}
+
+/*******************************
+* Metafile Descriptor Elements *
+*******************************/
+
+int cgm_metafile_version ( CGM *cgm, long version )
+{
+ cgm->func->wch ( cgm, 1, 1, cgm->int_size );
+
+ cgm->func->i ( cgm, version );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_metafile_description ( CGM *cgm, const char *s )
+{
+ cgm->func->wch ( cgm, 1, 2, 1+strlen(s) );
+ cgm->func->s ( cgm, s );
+ return cgm->func->term(cgm);
+}
+
+int cgm_vdc_type ( CGM *cgm, int mode )
+{
+ static const char *vdct[] = { "integer", "real" };
+ cgm->func->wch ( cgm, 1, 3, 2 );
+ cgm->func->e ( cgm, mode, vdct );
+
+ cgm->vdc_type = mode;
+ if ( cgm->vdc_type == 0 ) /* integer */
+ cgm->vdc_size = cgm->vdc_int + 1;
+ else
+ cgm->vdc_size = ( _cgm_ireal_precs[cgm->vdc_real][1] +
+ _cgm_ireal_precs[cgm->vdc_real][2]) / 8;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_integer_precision ( CGM *cgm, int prec )
+{
+ cgm->func->wch ( cgm, 1, 4, cgm->int_size );
+
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] );
+ break;
+ }
+
+ cgm->int_prec = prec/8-1;
+ cgm->int_size = prec/8;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_real_precision ( CGM *cgm, int mode )
+{
+ cgm->func->wch ( cgm, 1, 5, 2 + 2*cgm->int_size );
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) );
+ break;
+ }
+
+ cgm->real_prec = mode;
+ cgm->real_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8;
+
+ /* absolute scaling modes */
+ if ( cgm->lnwsm == 1 ) cgm->lnw_size = cgm->real_size;
+ if ( cgm->mkssm == 1 ) cgm->mks_size = cgm->real_size;
+ if ( cgm->edwsm == 1 ) cgm->edw_size = cgm->real_size;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_index_precision ( CGM *cgm, int prec )
+{
+ cgm->func->wch ( cgm, 1, 6, cgm->int_size );
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] );
+ break;
+ }
+
+ cgm->ix_prec = prec/8-1;
+ cgm->ix_size = prec/8;
+ return cgm->func->term(cgm);
+}
+
+int cgm_colour_precision ( CGM *cgm, int prec )
+{
+ cgm->func->wch ( cgm, 1, 7, cgm->int_size );
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] );
+ break;
+ }
+
+ cgm->cd_prec = prec/8-1;
+ cgm->cd_size = 3*(prec/8);
+
+ if ( cgm->clrsm == 1 ) /* direct */
+ cgm->clr_size = cgm->cd_size;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_colour_index_precision ( CGM *cgm, int prec )
+{
+ cgm->func->wch ( cgm, 1, 8, cgm->int_size );
+
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, 1ul+ 2ul * (unsigned long)_cgm_int_precs[prec/8 - 1][1] );
+ break;
+ }
+
+ cgm->cix_prec = prec/8-1;
+ cgm->cix_size = prec/8;
+
+ if ( cgm->clrsm == 0 ) /* indexed */
+ cgm->clr_size = cgm->cix_size;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_maximum_colour_index ( CGM *cgm, unsigned long ci )
+{
+ cgm->func->wch ( cgm, 1, 9, cgm->cix_size );
+ cgm->func->ci ( cgm, ci );
+ return cgm->func->term(cgm);
+}
+
+int cgm_colour_value_extent ( CGM *cgm, const double *black,
+ const double *white)
+{
+ cgm->func->wch ( cgm, 1, 10, 2 * cgm->cd_size );
+ cgm->func->rgb ( cgm, black[0], black[1], black[2] );
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 15 );
+ cgm->func->rgb ( cgm, white[0], white[1], white[2] );
+ return cgm->func->term(cgm);
+}
+
+int cgm_metafile_element_list ( CGM *cgm, int n, const int *group, const int *element )
+{
+ register int i;
+ cgm->func->wch ( cgm, 1, 11, 31 );
+ cgm->func->sep ( cgm, "\x22" ); /* aspas */
+ if ( cgm->mode == 1 ) cgm->func->i ( cgm, n );
+ for ( i=0; i<n; i++ )
+ {
+ if ( cgm->mode == 1 ) /* binario */
+ {
+ cgm->func->ix ( cgm, group[i] );
+ cgm->func->ix ( cgm, element[i] );
+ cgm->func->term( cgm );
+ }
+ else
+ {
+ cgm->func->wch ( cgm, group[i], element[i], 0 );
+ cgm->func->sep ( cgm, "" );
+ }
+ }
+ cgm->func->sep ( cgm, "\x22" ); /* aspas */
+ return cgm->func->term(cgm);
+}
+
+int cgm_begin_metafile_defaults ( CGM *cgm )
+{
+ cgm->func->wch ( cgm, 1, 12, 31 );
+
+ /* modo binario - deixa aberto */
+ if ( cgm->mode == 1 ) /* binario */
+ return 0;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_end_metafile_defaults ( CGM *cgm )
+{
+ /* modo binario - ja estava aberto */
+ if ( cgm->mode != 1 ) /* binario */
+ cgm->func->wch ( cgm, 1, 0, 0 );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_font_list ( CGM *cgm, const char *fl[] )
+{
+ register int i;
+
+ cgm->func->wch ( cgm, 1, 13, 31 );
+
+ for ( i=0; fl[i] != NULL; i++ )
+ {
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 10 );
+ cgm->func->s ( cgm, fl[i] );
+ }
+
+ return cgm->func->term(cgm);
+}
+
+/******************************
+* Picture Descriptor Elements *
+******************************/
+
+int cgm_scaling_mode ( CGM *cgm, int mode, float metric )
+{
+ static const char *sm[] = { "abstract", "metric" };
+ cgm->func->wch ( cgm, 2, 1, 2 + 4 );
+ cgm->func->e ( cgm, mode, sm );
+ if ( cgm->mode == 1 )
+ cgmb_putfl32 ( cgm, metric );
+ else
+ cgm->func->r ( cgm, metric );
+ return cgm->func->term(cgm);
+}
+
+int cgm_colour_selection_mode ( CGM *cgm, int mode)
+{
+ static const char *csm[] = { "indexed", "direct" };
+ cgm->func->wch ( cgm, 2, 2, 2 );
+ cgm->func->e ( cgm, mode, csm );
+
+ cgm->clrsm = mode;
+ if ( mode == 0 ) /* indexed */
+ cgm->clr_size = cgm->cix_size;
+ else
+ cgm->clr_size = cgm->cd_size;
+
+ return cgm->func->term(cgm);
+}
+
+static int _cgm_width_specify_mode ( CGM *cgm, int t, int mode)
+{
+ static const char *sm[] = { "abstract", "scaled" };
+ cgm->func->wch ( cgm, 2, t, 2 );
+ cgm->func->e ( cgm, mode, sm );
+ return cgm->func->term(cgm);
+}
+
+int cgm_line_width_specify_mode ( CGM *cgm, int mode)
+{
+ cgm->lnwsm = mode;
+ if ( mode == 0 )
+ cgm->lnw_size = cgm->vdc_size;
+ else
+ cgm->lnw_size = cgm->real_size;
+ return _cgm_width_specify_mode ( cgm, 3, mode );
+}
+
+int cgm_marker_size_specify_mode ( CGM *cgm, int mode)
+{
+ cgm->mkssm = mode;
+ if ( mode == 0 )
+ cgm->mks_size = cgm->vdc_size;
+ else
+ cgm->mks_size = cgm->real_size;
+ return _cgm_width_specify_mode ( cgm, 4, mode );
+}
+
+int cgm_edge_width_specify_mode ( CGM *cgm, int mode)
+{
+ cgm->edwsm = mode;
+ if ( mode == 0 )
+ cgm->edw_size = cgm->vdc_size;
+ else
+ cgm->edw_size = cgm->real_size;
+ return _cgm_width_specify_mode ( cgm, 5, mode );
+}
+
+int cgm_vdc_extent ( CGM *cgm, double xmin, double ymin,
+ double xmax, double ymax )
+{
+ cgm->func->wch ( cgm, 2, 6, 2*2*cgm->vdc_size );
+ cgm->func->vdc ( cgm, xmin );
+ cgm->func->vdc ( cgm, ymin );
+ cgm->func->vdc ( cgm, xmax );
+ cgm->func->vdc ( cgm, ymax );
+ return cgm->func->term(cgm);
+}
+
+int cgm_backgound_colour ( CGM *cgm, const double *cr )
+{
+ cgm->func->wch ( cgm, 2, 7, cgm->cd_size );
+ cgm->func->rgb ( cgm , cr[0], cr[1], cr[2] );
+ return cgm->func->term(cgm);
+}
+
+/*******************
+* Control Elements *
+*******************/
+
+int cgm_vdc_integer_precision ( CGM *cgm, int prec )
+{
+ cgm->func->wch ( cgm, 3, 1, cgm->int_size );
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][0] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->i ( cgm, _cgm_int_precs[prec/8 - 1][1] );
+ break;
+ }
+
+ if ( cgm->vdc_type == 0 )
+ cgm->vdc_size = prec/8;
+
+ cgm->vdc_int = prec/8 - 1;
+
+ if ( cgm->lnwsm == 0 && cgm->vdc_type == 0 ) cgm->lnw_size = cgm->vdc_size;
+ if ( cgm->mkssm == 0 && cgm->vdc_type == 0 ) cgm->mks_size = cgm->vdc_size;
+ if ( cgm->edwsm == 0 && cgm->vdc_type == 0 ) cgm->edw_size = cgm->vdc_size;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_vdc_real_precision ( CGM *cgm, int mode )
+{
+ cgm->func->wch ( cgm, 3, 2, 2 + 2*cgm->int_size );
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->e ( cgm, _cgm_ireal_precs[mode][0] , NULL );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][1]) );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][2]) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->r ( cgm, _cgm_rreal_precs[mode][0] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->r ( cgm, _cgm_rreal_precs[mode][1] );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->i ( cgm, (long)(_cgm_ireal_precs[mode][3]) );
+ break;
+ }
+
+ if ( cgm->vdc_type == 1 )
+ cgm->vdc_size = ( _cgm_ireal_precs[mode][1] + _cgm_ireal_precs[mode][2]) / 8;
+
+ cgm->vdc_real = mode;
+
+ if ( cgm->lnwsm == 0 && cgm->vdc_type == 1 ) cgm->lnw_size = cgm->vdc_size;
+ if ( cgm->mkssm == 0 && cgm->vdc_type == 1 ) cgm->mks_size = cgm->vdc_size;
+ if ( cgm->edwsm == 0 && cgm->vdc_type == 1 ) cgm->edw_size = cgm->vdc_size;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_auxiliary_colour ( CGM *cgm, const void *c )
+{
+ cgm->func->wch ( cgm, 3, 3, cgm->clr_size );
+
+ cgm->func->co ( cgm, c ) ;
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_transparency ( CGM *cgm, int mode )
+{
+ cgm->func->wch ( cgm, 3, 4, 2 );
+
+ cgm->func->e ( cgm, mode, offon );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_clip_rectangle ( CGM *cgm, double xmin, double ymin,
+ double xmax, double ymax )
+{
+ cgm->func->wch ( cgm, 3, 5, 4 * cgm->vdc_size );
+
+ cgm->func->vdc ( cgm, xmin );
+ cgm->func->vdc ( cgm, ymin );
+ cgm->func->vdc ( cgm, xmax );
+ cgm->func->vdc ( cgm, ymax );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_clip_indicator ( CGM *cgm, int mode )
+{
+ cgm->func->wch ( cgm, 3, 6, 2 );
+
+ cgm->func->e ( cgm, mode, offon );
+
+ return cgm->func->term(cgm);
+}
+
+/*******************************
+* Graphical Primitive Elements *
+*******************************/
+
+static int _cgm_point ( CGM *cgm, double x, double y )
+{
+ cgm->func->p ( cgm, x, y );
+ return 0;
+}
+
+static int _cgm_point_list ( CGM *cgm, int element, int n, const double *p)
+{
+ register int i;
+ cgm->func->wch ( cgm, 4, element, 2*n*cgm->vdc_size );
+
+ for ( i=0; i < 2*n; i+=2 )
+ {
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 8 );
+ _cgm_point ( cgm, p[i], p[i+1] );
+ }
+ return cgm->func->term(cgm);
+}
+
+int cgm_polyline ( CGM *cgm, int n, const double *p )
+{
+ return _cgm_point_list ( cgm, 1, n, p );
+}
+
+int cgm_polymarker ( CGM *cgm, int n, const double *p )
+{
+ return _cgm_point_list ( cgm, 3, n, p );
+}
+
+static int _cgm_text_piece ( CGM *cgm, int t, const char *s)
+{
+ static const char *tt[] = { "NOT_FINAL", " FINAL" };
+ cgm->func->e ( cgm, t, tt );
+ cgm->func->s ( cgm, s );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text ( CGM *cgm, int tt, double x, double y, const char *s )
+{
+ cgm->func->wch ( cgm, 4, 4, 2 * cgm->vdc_size + strlen(s) + 3 );
+ cgm->func->p ( cgm, x, y );
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 10 );
+
+ if ( cgm->mode == 2 ) /* clear text */
+ {
+ while ( strlen (s) > 50 )
+ {
+ char s1[51];
+
+ strncpy ( s1, s, 50 );
+ s1[50] = 0;
+
+ _cgm_text_piece ( cgm, 0, s1 );
+
+ s += 50;
+ cgm->func->wch ( cgm, 4, 6, 2 * cgm->vdc_size + strlen(s) + 1 );
+ }
+
+ }
+
+ return _cgm_text_piece ( cgm, tt, s );
+}
+
+int cgm_polygon ( CGM *cgm, int n, const double *p )
+{
+ return _cgm_point_list ( cgm, 7, n, p );
+}
+
+static int _cgm_cell_rows ( CGM *cgm, long sx, long sy, int prec, const void *c )
+{
+ register long i,j, brk;
+
+ cgm->func->nl ( cgm );
+ cgm->func->sep ( cgm, "(" );
+
+ if ( cgm->clrsm )
+ brk = 5;
+ else
+ brk = 12;
+
+ for ( i=0; i < sy; i++ )
+ {
+ if ( i )
+ {
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 3 );
+ }
+
+ for ( j=0; j < sx; j++)
+ {
+ if ( j && ( j % brk == 0 ) )
+ {
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 3 );
+ }
+
+ cgm->func->co ( cgm, c );
+ c = (void*)((char*)c+ (cgm->clrsm ? (3*sizeof(double)) : sizeof(int)));
+
+ if ( i<sy-1 || j<sx-1 ) cgm->func->sep ( cgm, "," );
+ }
+ }
+
+ cgm->func->sep ( cgm, ")" );
+
+ return 0;
+}
+
+int cgm_cell_array ( CGM *cgm, const double *p, long sx, long sy, int prec, const void *c )
+{
+ register int i;
+ static const char *repmode[] = { "run lenght", "packed" };
+
+ cgm->func->wch ( cgm, 4, 9, 31 );
+
+ for ( i=0; i<3*2; i+=2 )
+ _cgm_point ( cgm, p[i], p[i+1] );
+
+ cgm->func->nl (cgm );
+
+ cgm->func->i ( cgm, sx );
+ cgm->func->i ( cgm, sy );
+
+ if ( prec == 0 )
+ cgm->func->i ( cgm, (long)(prec) );
+ else
+ {
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) );
+ break;
+ }
+ }
+
+ if ( cgm->mode==1 ) cgm->func->e ( cgm, 1, repmode );
+
+ _cgm_cell_rows( cgm, sx, sy, prec, c );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_rectangle ( CGM *cgm, const double *p )
+{
+ return _cgm_point_list ( cgm, 11, 2, p );
+}
+
+static int _cgm_ellipse_CDP ( CGM *cgm, const double *c, const double *p1,
+ const double *p2 )
+{
+ _cgm_point ( cgm, c[0], c[1] );
+ _cgm_point ( cgm, p1[0], p1[1] );
+ _cgm_point ( cgm, p2[0], p2[1] );
+
+ return 0;
+}
+
+static int _cgm_ellipse_vectors ( CGM *cgm, double dxs, double dys, double dxe,
+ double dye )
+{
+ cgm->func->vdc ( cgm, dxs );
+ cgm->func->vdc ( cgm, dys );
+ cgm->func->vdc ( cgm, dxe );
+ cgm->func->vdc ( cgm, dye );
+
+ return 0;
+}
+
+int cgm_elliptical_arc ( CGM *cgm, const double *c, const double *p1,
+ const double *p2, double dxs, double dys, double dxe,
+ double dye )
+{
+ cgm->func->wch ( cgm, 4, 18, 10*cgm->vdc_size );
+
+ _cgm_ellipse_CDP ( cgm, c, p1, p2 );
+
+ _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_elliptical_arc_close ( CGM *cgm, const double *c, const double *p1,
+ const double *p2, double dxs, double dys,
+ double dxe, double dye, int type )
+{
+ static const char *ct[] = { "pie", "chord" };
+
+ cgm->func->wch ( cgm, 4, 19, 10*cgm->vdc_size + 2 );
+
+ _cgm_ellipse_CDP ( cgm, c, p1, p2 );
+
+ _cgm_ellipse_vectors ( cgm, dxs, dys, dxe, dye );
+
+ cgm->func->e ( cgm, type, ct );
+
+ return cgm->func->term(cgm);
+}
+
+/*********************
+* Attribute Elements *
+*********************/
+
+int cgm_line_bundle_index( CGM *cgm, long li)
+{
+ cgm->func->wch ( cgm, 5, 1, cgm->ix_size );
+ cgm->func->ix ( cgm, li );
+ return cgm->func->term(cgm);
+}
+
+int cgm_line_type( CGM *cgm, long lt)
+{
+ cgm->func->wch ( cgm, 5, 2, cgm->ix_size );
+ cgm->func->ix ( cgm, lt );
+ return cgm->func->term(cgm);
+}
+
+int cgm_line_width( CGM *cgm, double lw)
+{
+ cgm->func->wch ( cgm, 5, 3, cgm->lnw_size );
+
+ if ( cgm->lnwsm == 0 ) /* absolute */
+ cgm->func->vdc ( cgm, lw );
+ else
+ cgm->func->r ( cgm, lw );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_line_colour( CGM *cgm, const void *lc)
+{
+ cgm->func->wch ( cgm, 5, 4, cgm->clr_size );
+ cgm->func->co ( cgm, lc );
+ return cgm->func->term(cgm);
+}
+
+int cgm_marker_bundle_index( CGM *cgm, long mi)
+{
+ cgm->func->wch ( cgm, 5, 5, cgm->ix_size );
+ cgm->func->ix ( cgm, mi );
+ return cgm->func->term(cgm);
+}
+
+int cgm_marker_type( CGM *cgm, long mt)
+{
+ cgm->func->wch ( cgm, 5, 6, cgm->ix_size );
+ cgm->func->ix ( cgm, mt );
+ return cgm->func->term(cgm);
+}
+
+int cgm_marker_size( CGM *cgm, double ms)
+{
+ cgm->func->wch ( cgm, 5, 7, cgm->mks_size );
+
+ if ( cgm->mkssm == 0 ) /* absolute */
+ cgm->func->vdc ( cgm, ms );
+ else
+ cgm->func->r ( cgm, ms );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_marker_colour( CGM *cgm, const void *mc)
+{
+ cgm->func->wch ( cgm, 5, 8, cgm->clr_size );
+ cgm->func->co ( cgm, mc );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_bundle_index( CGM *cgm, long ti)
+{
+ cgm->func->wch ( cgm, 5, 9, cgm->ix_size );
+ cgm->func->ix ( cgm, ti );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_font_index( CGM *cgm, long fi)
+{
+ cgm->func->wch ( cgm, 5, 10, cgm->ix_size );
+ cgm->func->ix ( cgm, fi );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_precision( CGM *cgm, int tp)
+{
+ static const char *txprec[] = { "STRING", "CHAR", "STROKE" };
+ cgm->func->wch ( cgm, 5, 11, 2 );
+ cgm->func->e ( cgm, tp, txprec );
+ return cgm->func->term(cgm);
+}
+
+int cgm_char_expansion_factor ( CGM *cgm, double expan )
+{
+ cgm->func->wch ( cgm, 5, 12, cgm->real_size );
+ cgm->func->r ( cgm, expan );
+ return cgm->func->term(cgm);
+}
+
+int cgm_char_spacing ( CGM *cgm, double spacing )
+{
+ cgm->func->wch ( cgm, 5, 13, cgm->real_size );
+ cgm->func->r ( cgm, spacing );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_colour( CGM *cgm, const void *tc)
+{
+ cgm->func->wch ( cgm, 5, 14, cgm->clr_size );
+ cgm->func->co ( cgm, tc );
+ return cgm->func->term(cgm);
+}
+
+int cgm_char_height ( CGM *cgm, double height )
+{
+ cgm->func->wch ( cgm, 5, 15, cgm->vdc_size );
+ cgm->func->vdc ( cgm, height );
+ return cgm->func->term(cgm);
+}
+
+int cgm_char_orientation ( CGM *cgm, double chupx, double chupy,
+ double chbsx, double chbsy )
+{
+ cgm->func->wch ( cgm, 5, 16, 4*cgm->vdc_size );
+ cgm->func->sep ( cgm, "% char up %" );
+ cgm->func->vdc ( cgm, chupx );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, chupy );
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 8 );
+ cgm->func->sep ( cgm, "% char base %" );
+ cgm->func->vdc ( cgm, chbsx );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, chbsy );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_path ( CGM *cgm, int tp)
+{
+ static const char *txpath[] = { "RIGHT", "LEFT", "UP", "DOWN" };
+ cgm->func->wch ( cgm, 5, 17, 2 );
+ cgm->func->e ( cgm, tp, txpath );
+ return cgm->func->term(cgm);
+}
+
+int cgm_text_alignment ( CGM *cgm, int hor, int ver , double ch, double cv)
+{
+ static const char *txhor[] = { "NORMHORIZ", "LEFT", "CTR", "RIGHT", "CONTHORIZ" };
+ static const char *txver[] = { "NORMVERT", "TOP", "CAP", "HALF", "BASE",
+ "BOTTOM", "CONTHORIZ" };
+
+ cgm->func->wch ( cgm, 5, 18, 2*2 + 2*cgm->real_size );
+ cgm->func->e ( cgm, hor, txhor );
+ cgm->func->e ( cgm, ver, txver );
+ cgm->func->r ( cgm, ch );
+ cgm->func->r ( cgm, cv );
+ return cgm->func->term(cgm);
+}
+
+int cgm_fill_bundle_index( CGM *cgm, long fi)
+{
+ cgm->func->wch ( cgm, 5, 21, cgm->ix_size );
+ cgm->func->ix ( cgm, fi );
+ return cgm->func->term(cgm);
+}
+
+int cgm_interior_style( CGM *cgm, int is)
+{
+ static const char *style[]= { "HOLLOW", "SOLID", "PAT", "HATCH", "EMPTY" };
+ cgm->func->wch ( cgm, 5, 22, 2 );
+ cgm->func->e ( cgm, is, style );
+ return cgm->func->term(cgm);
+}
+
+int cgm_fill_colour( CGM *cgm, const void *fc)
+{
+ cgm->func->wch ( cgm, 5, 23, cgm->clr_size );
+ cgm->func->co ( cgm, fc );
+ return cgm->func->term(cgm);
+}
+
+int cgm_hatch_index( CGM *cgm, long hi)
+{
+ cgm->func->wch ( cgm, 5, 24, cgm->ix_size );
+ cgm->func->ix ( cgm, hi );
+ return cgm->func->term(cgm);
+}
+
+int cgm_pattern_index( CGM *cgm, long pi)
+{
+ cgm->func->wch ( cgm, 5, 25, cgm->ix_size );
+ cgm->func->ix ( cgm, pi );
+ return cgm->func->term(cgm);
+}
+
+int cgm_edge_width( CGM *cgm, double ew)
+{
+ cgm->func->wch ( cgm, 5, 28, cgm->edw_size );
+
+ if ( cgm->lnwsm == 0 ) /* absolute */
+ cgm->func->vdc ( cgm, ew );
+ else
+ cgm->func->r ( cgm, ew );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_edge_colour( CGM *cgm, const void *ec)
+{
+ cgm->func->wch ( cgm, 5, 29, cgm->clr_size );
+ cgm->func->co ( cgm, ec );
+ return cgm->func->term(cgm);
+}
+
+int cgm_edge_visibility ( CGM *cgm, int mode )
+{
+ cgm->func->wch ( cgm, 5, 30, 2 );
+ cgm->func->e ( cgm, mode, offon );
+ return cgm->func->term(cgm);
+}
+
+int cgm_fill_reference_point ( CGM *cgm, double rpx, double rpy )
+{
+ cgm->func->wch ( cgm, 5, 31, 2*cgm->vdc_size );
+ _cgm_point ( cgm, rpx, rpy );
+ return cgm->func->term(cgm);
+}
+
+int cgm_pattern_table ( CGM *cgm, long pi, long sx, long sy, int prec, const void *c)
+{
+ cgm->func->wch ( cgm, 5, 32, 31 );
+ cgm->func->ix ( cgm, pi );
+
+ cgm->func->i ( cgm, sx );
+ cgm->func->i ( cgm, sy );
+
+ if ( prec == 0 )
+ cgm->func->i ( cgm, (long)(prec) );
+ else
+ {
+ switch ( cgm->mode )
+ {
+ case 0: /* character */
+ break;
+
+ case 1: /* binary */
+ cgm->func->i ( cgm, (long)(prec) );
+ break;
+
+ case 2: /* clear text */
+ cgm->func->i ( cgm, 2 * ( _cgm_int_precs[prec/8 - 1][1] + 1) );
+ break;
+ }
+ }
+
+ _cgm_cell_rows( cgm, sx, sy, prec, c );
+
+ return cgm->func->term(cgm);
+}
+
+int cgm_pattern_size ( CGM *cgm, double hx, double hy, double wx, double wy )
+{
+ cgm->func->wch ( cgm, 5, 33, 4*cgm->vdc_size );
+ cgm->func->sep ( cgm, "% height %" );
+ cgm->func->vdc ( cgm, hx );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, hy );
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 8 );
+ cgm->func->sep ( cgm, "% width %" );
+ cgm->func->vdc ( cgm, wx );
+ cgm->func->sep ( cgm, "," );
+ cgm->func->vdc ( cgm, wy );
+ return cgm->func->term(cgm);
+}
+
+int cgm_colour_table ( CGM *cgm, long ci, long n, const double *cb )
+{
+ register long i=n;
+
+ if ( n > 31 ) n = 31;
+
+ cgm->func->wch ( cgm, 5, 34, cgm->int_size+n*cgm->cd_size );
+ cgm->func->i ( cgm, ci );
+
+ n = i;
+
+ for ( i=0; i<n; i++ )
+ {
+ if ( i )
+ {
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 18 );
+ }
+ cgm->func->rgb ( cgm, cb[(int)i], cb[(int)i+1], cb[(int)i+2] );
+ }
+
+ return cgm->func->term(cgm);
+}
+
+static void _cgm_asf_pair ( CGM *cgm, int asft, int asfv )
+{
+ static const char *asfvl[] = { "INDIV", "BUNDLED" };
+ static const char *asftl[] = {
+ "LINE_TYPE", "LINE_WIDTH", "LINE_COLR",
+ "MARKER_TYPE", "MARKER_SIZE", "MARKER_COLR",
+ "TEXT_FONT_INDEX", "TEXT_PREC", "CHAR_EXP", "CHAR_SPACE", "TEXT_COLR",
+ "INT_STYLE", "FILL_COLR", "HATCH_INDEX", "PAT_INDEX",
+ "EDGE_TYPE", "EDGE_WIDTH", "EDGE_COLR",
+ "ALL", "ALL_LINE", "ALL_MARKER", "ALL_TEXT", "ALL_FILL", "ALL_EDGE"
+ };
+
+ cgm->func->nl ( cgm );
+ cgm->func->align ( cgm, 4 );
+ cgm->func->e ( cgm, asft, asftl );
+ cgm->func->e ( cgm, asfv, asfvl );
+}
+
+int cgm_asfs ( CGM *cgm, int n, const int *asfts, const int* asfvs )
+{
+ register int i;
+ cgm->func->wch ( cgm, 5, 35, 2*n* 2 );
+
+ for ( i=0; i<n; i++ )
+ _cgm_asf_pair ( cgm, asfts[i], asfvs[i] );
+
+ return cgm->func->term(cgm);
+}
+
+/*****************
+* Escape Element *
+*****************/
+
+/********************
+* External elements *
+********************/
+
+int cgm_message ( CGM *cgm, int action, const char *s)
+{
+ static const char *ac[] = { "NOACTION", "ACTION" };
+ cgm->func->wch ( cgm, 7, 2, 2 + strlen(s)+1 );
+ cgm->func->e ( cgm, action, ac );
+ cgm->func->s ( cgm, s );
+ return cgm->func->term(cgm);
+}
diff --git a/src/drv/cgm.h b/src/drv/cgm.h
new file mode 100644
index 0000000..0404604
--- /dev/null
+++ b/src/drv/cgm.h
@@ -0,0 +1,156 @@
+/** \file
+ * \brief CGM library
+ * Extracted from GKS/PUC
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CGM_H
+#define __CGM_H
+
+typedef struct _cgmFunc CGMFUNC;
+
+typedef struct {
+ FILE *file; /* file pointer */
+
+ const CGMFUNC *func; /* functions */
+
+ int mode; /* character, binary, clear text */
+
+ int vdc_type, /* integer, real */
+ int_prec, /* 8, 16, 24, 32 */
+ real_prec, /* float*32, float*64, fixed*32, fixed*64 */
+ ix_prec, /* 8, 16, 24, 32 */
+ cd_prec, /* 8, 16, 24, 32 */
+ cix_prec, /* 8, 16, 24, 32 */
+ max_cix; /* maximum colour index */
+
+ int clrsm, /* indexed, direct */
+ lnwsm, /* absolute, scaled */
+ mkssm, /* absolute, scaled */
+ edwsm; /* absolute, scaled */
+ int vdc_int, /* X, 16, 24, 32 */
+ vdc_real; /* float*32, float*64, fixed*32, fixed*64 */
+
+ int vdc_size, /* 2, 3, 4, 8 */
+ int_size, /* 1, 2, 3, 4 */
+ real_size, /* 4, 8 */
+ ix_size, /* 1, 2, 3, 4 */
+ cd_size, /* 1, 2, 3, 4 */
+ cix_size, /* 1, 2, 3, 4 */
+ clr_size, /* 3 * cd_size , cix_size */
+ lnw_size, /* 2, 3, 4, 8 */
+ mks_size, /* 2, 3, 4, 8 */
+ edw_size; /* 2, 3, 4, 8 */
+
+ int cl; /* coluna para alinhamento */
+
+ int op; /* commands opened */
+ int bc[5]; /* bytes count for command */
+ long po[5]; /* position offset do arquivo */
+} CGM;
+
+CGM *cgm_begin_metafile ( char *, int, char * );
+int cgm_end_metafile ( CGM * );
+int cgm_begin_picture ( CGM *, const char * );
+int cgm_begin_picture_body ( CGM * );
+int cgm_end_picture ( CGM * );
+int cgm_metafile_version ( CGM *, long );
+int cgm_metafile_description ( CGM *, const char * );
+int cgm_vdc_type ( CGM *, int );
+int cgm_integer_precision ( CGM *, int );
+int cgm_real_precision ( CGM *, int );
+int cgm_index_precision ( CGM *, int );
+int cgm_colour_precision ( CGM *, int );
+int cgm_colour_index_precision ( CGM *, int );
+int cgm_maximum_colour_index ( CGM *, unsigned long );
+int cgm_colour_value_extent ( CGM *, const double *, const double * );
+int cgm_metafile_element_list ( CGM *, int, const int *, const int * );
+int cgm_begin_metafile_defaults ( CGM * );
+int cgm_end_metafile_defaults ( CGM * );
+int cgm_font_list ( CGM *, const char *l[] );
+int cgm_scaling_mode ( CGM *, int, float );
+int cgm_colour_selection_mode ( CGM *, int );
+int cgm_line_width_specify_mode ( CGM *, int );
+int cgm_marker_size_specify_mode( CGM *, int );
+int cgm_edge_width_specify_mode ( CGM *, int );
+int cgm_vdc_extent ( CGM *, double, double, double, double );
+int cgm_backgound_colour ( CGM *, const double * );
+int cgm_vdc_integer_precision ( CGM *, int );
+int cgm_vdc_real_precision ( CGM *, int );
+int cgm_auxiliary_colour ( CGM *, const void * );
+int cgm_transparency ( CGM *, int );
+int cgm_clip_rectangle ( CGM *, double, double, double, double );
+int cgm_clip_indicator ( CGM *, int );
+int cgm_polyline ( CGM *, int, const double * );
+int cgm_polymarker ( CGM *, int, const double * );
+int cgm_text ( CGM *, int, double, double, const char * );
+int cgm_polygon ( CGM *, int, const double * );
+int cgm_cell_array ( CGM *, const double *, long, long, int, const void * );
+int cgm_rectangle ( CGM *, const double * );
+int cgm_elliptical_arc ( CGM *, const double *, const double *, const double *, double, double, double, double );
+int cgm_elliptical_arc_close ( CGM *, const double *, const double *, const double *, double, double, double, double, int );
+int cgm_line_bundle_index ( CGM *, long );
+int cgm_line_type ( CGM *, long );
+int cgm_line_width ( CGM *, double );
+int cgm_line_colour ( CGM *, const void * );
+int cgm_marker_bundle_index ( CGM *, long );
+int cgm_marker_type ( CGM *, long );
+int cgm_marker_size ( CGM *, double );
+int cgm_marker_colour ( CGM *, const void * );
+int cgm_text_bundle_index ( CGM *, long );
+int cgm_text_font_index ( CGM *, long );
+int cgm_text_precision ( CGM *, int );
+int cgm_char_expansion_factor ( CGM *, double );
+int cgm_char_spacing ( CGM *, double );
+int cgm_text_colour ( CGM *, const void * );
+int cgm_char_height ( CGM *, double );
+int cgm_char_orientation ( CGM *, double, double, double, double );
+int cgm_text_path ( CGM *, int );
+int cgm_text_alignment ( CGM *, int, int, double, double );
+int cgm_fill_bundle_index ( CGM *, long );
+int cgm_interior_style ( CGM *, int );
+int cgm_fill_colour ( CGM *, const void * );
+int cgm_hatch_index ( CGM *, long );
+int cgm_pattern_index ( CGM *, long );
+int cgm_edge_width ( CGM *, double );
+int cgm_edge_colour ( CGM *, const void * );
+int cgm_edge_visibility ( CGM *, int );
+int cgm_fill_reference_point ( CGM *, double, double );
+int cgm_pattern_table ( CGM *, long, long, long, int, const void * );
+int cgm_pattern_size ( CGM *, double, double, double, double );
+int cgm_colour_table ( CGM *, long, long, const double * );
+int cgm_asfs ( CGM *, int, const int *, const int * );
+int cgm_message ( CGM *, int, const char * );
+
+enum {
+ LINE_SOLID=1,
+ LINE_DASH=2,
+ LINE_DOT=3,
+ LINE_DASH_DOT=4,
+ LINE_DASH_DOT_DOT=5
+ };
+
+enum {
+ MARKER_DOT=1,
+ MARKER_PLUS=2,
+ MARKER_ASTERISK=3,
+ MARKER_CIRCLE=4,
+ MARKER_CROSS=5
+ };
+
+enum {
+ HOLLOW,
+ SOLID,
+ PAT,
+ HATCH,
+ EMPTY
+ };
+
+enum { /* encoding */
+ CD_CHARACTER,
+ CD_BIN,
+ CD_CLEAR_TEXT
+ };
+
+#endif