From 79f65d040d72f778f66f8eefdaffb6acd9799a38 Mon Sep 17 00:00:00 2001 From: lecoanet Date: Tue, 10 May 2005 07:59:48 +0000 Subject: Merge of the newly developped postscript code (still not fully functional). --- generic/Arc.c | 93 ++- generic/Curve.c | 97 ++- generic/Field.c | 235 +++++- generic/Field.h | 1 + generic/Group.c | 66 +- generic/Icon.c | 129 ++- generic/Image.c | 12 + generic/Image.h | 31 +- generic/Item.h | 2 +- generic/Map.c | 8 +- generic/PostScript.c | 2223 +++++++++++++++++++++++++++++++++++--------------- generic/PostScript.h | 26 +- generic/Rectangle.c | 83 +- generic/Reticle.c | 8 +- generic/Tabular.c | 8 +- generic/Text.c | 72 +- generic/Track.c | 8 +- generic/Triangles.c | 58 +- generic/WidgetInfo.h | 3 +- generic/Window.c | 169 +++- generic/tkZinc.c | 5 +- 21 files changed, 2591 insertions(+), 746 deletions(-) diff --git a/generic/Arc.c b/generic/Arc.c index 2b5f7fa..b6b0252 100644 --- a/generic/Arc.c +++ b/generic/Arc.c @@ -1184,10 +1184,97 @@ GetAnchor(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ArcItem arc = (ArcItem) item; + ZnWInfo *wi = item->wi; + ZnPoint *p; + int i, num_points; + char path[500]; + + if (ISCLEAR(arc->flags, FILLED_BIT) && !arc->line_width) { + return TCL_OK; + } + + /* + * Create the arc path. + */ + if (ISSET(arc->flags, USING_POLY_BIT)) { + p = ZnListArray(arc->render_shape); + num_points = ZnListSize(arc->render_shape); + sprintf(path, "%.15g %.15g moveto ", p[0].x, p[0].y); + Tcl_AppendResult(wi->interp, path, NULL); + for (i = 0; i < num_points; i++) { + sprintf(path, "%.15g %.15g lineto ", p[i].x, p[i].y); + Tcl_AppendResult(wi->interp, path, NULL); + } + Tcl_AppendResult(wi->interp, "closepath\n", NULL); + } + else { + sprintf(path, + "matrix currentmatrix\n%.15g %.15g translate %.15g %.15g scale 1 0 moveto 0 0 1 0 360 arc\nsetmatrix\n", + (arc->corner.x + arc->orig.x) / 2.0, (arc->corner.y + arc->orig.y) / 2.0, + (arc->corner.x - arc->orig.x) / 2.0, (arc->corner.y - arc->orig.y) / 2.0); + Tcl_AppendResult(wi->interp, path, NULL); + } + + /* + * Emit code to draw the filled area. + */ + if (ISSET(arc->flags, FILLED_BIT)) { + if (arc->line_width) { + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + } + if (!ZnGradientFlat(arc->fill_color)) { + if (ZnPostscriptGradient(wi->interp, wi->ps_info, arc->fill_color, + arc->grad_geo, NULL) != TCL_OK) { + return TCL_ERROR; + } + } + else if (arc->tile != ZnUnspecifiedImage) { + if (!ZnImageIsBitmap(arc->tile)) { /* Fill tiled */ + /* TODO No support yet */ + } + else { /* Fill stippled */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(arc->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "clip ", NULL); + if (Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, + ZnImagePixmap(arc->tile, wi->win)) != TCL_OK) { + return TCL_ERROR; + } + } + } + else { /* Fill solid */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(arc->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "fill\n", NULL); + } + if (arc->line_width) { + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + + /* + * Then emit code code to stroke the outline. + */ + if (arc->line_width) { + Tcl_AppendResult(wi->interp, "0 setlinejoin 2 setlinecap\n", NULL); + if (ZnPostscriptOutline(wi->interp, wi->ps_info, wi->win, + arc->line_width, arc->line_style, + arc->line_color, arc->line_pattern) != TCL_OK) { + return TCL_ERROR; + } + } + + return TCL_OK; } diff --git a/generic/Curve.c b/generic/Curve.c index 7054e81..c73d467 100644 --- a/generic/Curve.c +++ b/generic/Curve.c @@ -1578,10 +1578,101 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ZnWInfo *wi = item->wi; + CurveItem cv = (CurveItem) item; + char path[500]; + ZnContour *contours; + ZnPoint *points; + int num_contours, num_points; + int i, j; + + num_contours = cv->outlines.num_contours; + contours = cv->outlines.contours; + + /* + * Put all contours in an array on the stack + */ + if (ISSET(cv->flags, FILLED_BIT) || cv->line_width) { + Tcl_AppendResult(wi->interp, "newpath ", NULL); + for (i = 0; i < num_contours; i++, contours++) { + num_points = contours->num_points; + points = contours->points; + sprintf(path, "%.15g %.15g moveto\n", points[0].x, points[0].y); + Tcl_AppendResult(wi->interp, path, NULL); + for (j = 1; j < num_points; j++) { + sprintf(path, "%.15g %.15g lineto ", points[j].x, points[j].y); + Tcl_AppendResult(wi->interp, path, NULL); + if (((j+1) % 5) == 0) { + Tcl_AppendResult(wi->interp, "\n", NULL); + } + } + } + } + + /* + * Emit code to draw the filled area. + */ + if (ISSET(cv->flags, FILLED_BIT)) { + if (cv->line_width) { + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + } + if (!ZnGradientFlat(cv->fill_color)) { + if (ZnPostscriptGradient(wi->interp, wi->ps_info, cv->fill_color, + cv->grad_geo, NULL) != TCL_OK) { + return TCL_ERROR; + } + } + else if (cv->tile != ZnUnspecifiedImage) { + if (!ZnImageIsBitmap(cv->tile)) { /* Fill tiled */ + /* TODO No support yet */ + } + else { /* Fill stippled */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(cv->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "clip ", NULL); + if (Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, + ZnImagePixmap(cv->tile, wi->win)) != TCL_OK) { + return TCL_ERROR; + } + } + } + else { /* Fill solid */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(cv->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "fill\n", NULL); + } + if (cv->line_width) { + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + + /* + * Then emit code code to stroke the outline. + */ + if (cv->line_width) { + if (cv->relief != ZN_RELIEF_FLAT) { + /* TODO No support yet */ + } + else { + Tcl_AppendResult(wi->interp, "0 setlinejoin 2 setlinecap\n", NULL); + if (ZnPostscriptOutline(wi->interp, wi->ps_info, wi->win, + cv->line_width, cv->line_style, + cv->line_color, cv->line_pattern) != TCL_OK) { + return TCL_ERROR; + } + } + } + + return TCL_OK; } diff --git a/generic/Field.c b/generic/Field.c index ace5407..9f36e88 100644 --- a/generic/Field.c +++ b/generic/Field.c @@ -2132,14 +2132,246 @@ RenderField(ZnWInfo *wi, } #endif +#ifdef GL static void RenderFields(ZnFieldSet field_set) { -#ifdef GL /* glDisable(GL_LINE_SMOOTH);*/ FieldsEngine(field_set, RenderField); /* glEnable(GL_LINE_SMOOTH);*/ +} +#else +static void +RenderFields(ZnFieldSet field_set) +{ +} #endif + + +/* + ********************************************************************************** + * + * PostScriptFields -- + * + ********************************************************************************** + */ +static int +PsField(ZnWInfo *wi, + ZnBool prepass, + Field fptr, + ZnBBox *bbox, + ZnBBox *pm_bbox, + ZnPoint *text_pos, + ZnBBox *text_bbox) +{ + int j; + char path[250]; + + /* + * Must set the clip rect for the whole field, not only for stipple fill. + */ + if (ISSET(fptr->flags, FILLED_BIT)) { + if (fptr->tile != ZnUnspecifiedImage) { + if (!ZnImageIsBitmap(fptr->tile)) { /* Fill tiled */ + /* TODO No support yet */ + } + else { /* Fill stippled */ + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(fptr->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, + ZnImagePixmap(fptr->tile, wi->win)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + else { /* Fill solid */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(fptr->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "fill\n", NULL); + } + } + + /* + * Draw the image and the text, which is in back depends on + * the value of text_on_top. + */ + for (j = 0; j < 2; j++) { + if ((j == 0 && ISSET(fptr->flags, TEXT_ON_TOP_BIT)) || + (j == 1 && ISCLEAR(fptr->flags, TEXT_ON_TOP_BIT))) { + /* + * Draw the image. + */ + if (fptr->image != ZnUnspecifiedImage) { + int w, h; + + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + sprintf(path, "%.15g %.15g translate 1 -1 scale\n", + pm_bbox->orig.x, pm_bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + w = ZnNearestInt(pm_bbox->corner.x - pm_bbox->orig.x); + h = ZnNearestInt(pm_bbox->corner.y - pm_bbox->orig.y); + if (Tk_PostscriptImage(ZnImageTkImage(fptr->image), wi->interp, wi->win, + wi->ps_info, 0, 0, w, h, prepass) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + else if (fptr->text) { + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + if (Tk_PostscriptFont(wi->interp, wi->ps_info, fptr->font) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(fptr->color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + /* + * TODO pourquoi la text_bbox ne donne pas un texte centré verticalement ? + * Apparement la fonte PostScript n'est pas centrée comme la fonte X. + * Il faut donc opérer le calcul dans le code PostScript de DrawText. + */ + sprintf(path, "%.15g %.15g translate 1 -1 scale 0 0 [\n", + text_bbox->orig.x, text_bbox->orig.y); + Tcl_AppendResult(wi->interp, path, NULL); + /* + * strlen should do the work of counting _bytes_ in the utf8 string. + */ + ZnPostscriptString(wi->interp, fptr->text, strlen(fptr->text)); + Tcl_AppendResult(wi->interp, "] 0 0.0 0.0 0.0 false DrawText\n", NULL); + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + + /* + * Draw the border relief. + */ + if ((fptr->relief != ZN_RELIEF_FLAT) && (fptr->relief_thickness > 1)) { + } + + /* + * Draw the border line. + */ + if (fptr->border_edges != ZN_NO_BORDER) { + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(fptr->border_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "1 setlinewidth 0 setlinejoin 2 setlinecap\n", NULL); + if (fptr->border_edges & ZN_LEFT_BORDER) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->orig.x, bbox->orig.y, bbox->orig.x, bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + if (fptr->border_edges & ZN_RIGHT_BORDER) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->corner.x, bbox->orig.y, bbox->corner.x, bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + if (fptr->border_edges & ZN_TOP_BORDER) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->orig.x, bbox->orig.y, bbox->corner.x, bbox->orig.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + if (fptr->border_edges & ZN_BOTTOM_BORDER) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->orig.x, bbox->corner.y, bbox->corner.x, bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + if (fptr->border_edges & ZN_OBLIQUE) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->orig.x, bbox->orig.y, bbox->corner.x, bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + if (fptr->border_edges & ZN_COUNTER_OBLIQUE) { + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto stroke\n", + bbox->corner.x, bbox->orig.y, bbox->orig.x, bbox->corner.y); + Tcl_AppendResult(wi->interp, path, NULL); + } + } + + return TCL_OK; +} + +static int +PostScriptFields(ZnFieldSet field_set, + ZnBool prepass, + ZnBBox *area) +{ + ZnWInfo *wi = field_set->item->wi; + ZnBBox lclip_bbox, fclip_bbox; + ZnBBox bbox, text_bbox, pm_bbox; + ZnPoint text_pos; + int i, num_fields; + ZnDim lwidth, lheight; + Field fptr; + char path[250]; + + if (!field_set->num_fields) { + return TCL_OK; + } + + + if (field_set->label_format && ZnLFNumFields(field_set->label_format)) { + /* + * Fields are drawn with respect to a point already converted + * to device space, so we need to reinstate the initial transform. + */ + Tcl_AppendResult(wi->interp, "/InitialTransform load setmatrix\n", NULL); + + lclip_bbox.orig.x = ZnNearestInt(field_set->label_pos.x); + lclip_bbox.orig.y = ZnNearestInt(field_set->label_pos.y); + GetLabelBBox(field_set, &lwidth, &lheight); + lclip_bbox.corner.x = lclip_bbox.orig.x + lwidth; + lclip_bbox.corner.y = lclip_bbox.orig.y + lheight; + + num_fields = ZnLFNumFields(field_set->label_format); + for (i = 0; i < num_fields; i++) { + fptr = &field_set->fields[i]; + + if (ISCLEAR(fptr->flags, FIELD_VISIBLE_BIT)) { + continue; + } + + GetFieldBBox(field_set, i, &bbox); + ZnIntersectBBox(&lclip_bbox, &bbox, &fclip_bbox); + if (ZnIsEmptyBBox(&fclip_bbox)) { + /* The field is outside the label bbox */ + continue; + } + + /* + * Setup a clip area around the field + */ + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto %.15g %.15g lineto %.15g %.15g", + fclip_bbox.orig.x, fclip_bbox.orig.y, fclip_bbox.corner.x+1, fclip_bbox.orig.y, + fclip_bbox.corner.x+1, fclip_bbox.corner.y+1, fclip_bbox.orig.x, + fclip_bbox.corner.y+1); + Tcl_AppendResult(wi->interp, path, " lineto closepath clip\n", NULL); + + if (fptr->text) { + ComputeFieldTextLocation(fptr, &bbox, &text_pos, &text_bbox); + } + if (fptr->image != ZnUnspecifiedImage) { + ComputeFieldImageLocation(fptr, &bbox, &pm_bbox); + } + + if (PsField(wi, prepass, fptr, &bbox, &pm_bbox, &text_pos, &text_bbox) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + + return TCL_OK; } @@ -2325,6 +2557,7 @@ struct _ZnFIELD ZnFIELD = { QueryField, DrawFields, RenderFields, + PostScriptFields, FieldsToArea, IsFieldSensitive, FieldsPick, diff --git a/generic/Field.h b/generic/Field.h index 88cb224..ad13663 100644 --- a/generic/Field.h +++ b/generic/Field.h @@ -60,6 +60,7 @@ extern struct _ZnFIELD { int (*QueryField)(ZnFieldSet fs, int field, int argc, Tcl_Obj *CONST argv[]); void (*DrawFields)(ZnFieldSet fs); void (*RenderFields)(ZnFieldSet fs); + int (*PostScriptFields)(ZnFieldSet fs, ZnBool prepass, ZnBBox *area); int (*FieldsToArea)(ZnFieldSet fs, ZnBBox *area); ZnBool (*IsFieldSensitive)(ZnFieldSet fs, int part); double (*FieldsPick)(ZnFieldSet fs, ZnPoint *p, int *part); diff --git a/generic/Group.c b/generic/Group.c index d569182..1f6a183 100644 --- a/generic/Group.c +++ b/generic/Group.c @@ -1355,10 +1355,70 @@ Coords(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + GroupItem group = (GroupItem) item; + ZnWInfo *wi = item->wi; + ZnItem current_item; + ZnBBox bbox; + int result = TCL_OK; + char msg[500]; + + PushTransform(item); + PushClip(group, True); + + for (current_item = group->tail; current_item != ZN_NO_ITEM; + current_item = current_item->previous) { + if (ISCLEAR(current_item->flags, ZN_VISIBLE_BIT)) { + continue; + } + //printf("area %g %g %g %g\n", area->orig.x, area->orig.y, + // area->corner.x, area->corner.y); + ZnIntersectBBox(area, ¤t_item->item_bounding_box, &bbox); + if (ZnIsEmptyBBox(&bbox)) { + continue; + } + if (current_item->class->PostScript == NULL) { + continue; + } + + if (current_item->class != ZnGroup) { + PushTransform(current_item); + if (!prepass) { + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + } + ZnPostscriptTrace(current_item, 1); + } + result = current_item->class->PostScript(current_item, prepass, area); + if (current_item->class != ZnGroup) { + ZnPostscriptTrace(current_item, 0); + if (!prepass && (result == TCL_OK)) { + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + PopTransform(current_item); + } + if (result == TCL_ERROR) { + if (!prepass) { + /* + * Add some trace to ease the error lookup. + */ + sprintf(msg, "\n (generating Postscript for item %d)", current_item->id); + Tcl_AddErrorInfo(wi->interp, msg); + break; + } + } + } + + PopClip(group, True); + PopTransform(item); + + if (!prepass && (result == TCL_OK)) { + ZnFlushPsChan(wi->interp, wi->ps_info); + } + return result; } diff --git a/generic/Icon.c b/generic/Icon.c index 38c4ac9..5b9eae8 100644 --- a/generic/Icon.c +++ b/generic/Icon.c @@ -228,6 +228,57 @@ Query(ZnItem item, /* + * Compute the transformation to be used and the origin + * of the icon (upper left point in item coordinates). + */ +static ZnTransfo * +ComputeTransfoAndOrigin(ZnItem item, + ZnPoint *origin) +{ + IconItem icon = (IconItem) item; + int w, h; + ZnTransfo *t; + + ZnSizeOfImage(icon->image, &w, &h); + + /* + * The connected item support anchors, this is checked by configure. + */ + if (item->connected_item != ZN_NO_ITEM) { + ZnTransfo inv; + + item->connected_item->class->GetAnchor(item->connected_item, + icon->connection_anchor, + origin); + + /* GetAnchor return a position in device coordinates not in + * the item coordinate space. To compute the icon origin + * (upper left corner), we must apply the inverse transform + * to the ref point before calling anchor2origin. + */ + ZnTransfoInvert(item->transfo, &inv); + ZnTransformPoint(&inv, origin, origin); + /* + * The relevant transform in case of an attachment is the item + * transform alone. This is case of local coordinate space where + * only the translation is a function of the whole transform + * stack, scale and rotation are reset. + */ + t = item->transfo; + } + else { + origin->x = origin->y = 0; + t = item->wi->current_transfo; + } + + ZnAnchor2Origin(origin, (ZnReal) w, (ZnReal) h, icon->anchor, origin); + //origin->x = ZnNearestInt(origin->x); + //origin->y = ZnNearestInt(origin->y); + + return t; +} + +/* ********************************************************************************** * * ComputeCoordinates -- @@ -238,10 +289,11 @@ static void ComputeCoordinates(ZnItem item, ZnBool force) { - ZnWInfo *wi = item->wi; - IconItem icon = (IconItem) item; - int width, height, i; - ZnPoint pos, quad[4]; + //ZnWInfo *wi = item->wi; + IconItem icon = (IconItem) item; + int width, height, i; + ZnPoint quad[4]; + ZnTransfo *t; ZnResetBBox(&item->item_bounding_box); @@ -252,34 +304,16 @@ ComputeCoordinates(ZnItem item, return; } - if (icon->image != ZnUnspecifiedImage) { - ZnSizeOfImage(icon->image, &width, &height); - } - + ZnSizeOfImage(icon->image, &width, &height); + t = ComputeTransfoAndOrigin(item, quad); - /* - * The connected item support anchors, this is checked by - * configure. - */ - if (item->connected_item != ZN_NO_ITEM) { - ZnTransfo t; - - item->connected_item->class->GetAnchor(item->connected_item, - icon->connection_anchor, quad); - ZnTransfoInvert(wi->current_transfo, &t); - ZnTransformPoint(&t, quad, &pos); - } - else { - pos.x = pos.y = 0; - } - ZnAnchor2Origin(&pos, (ZnReal) width, (ZnReal) height, icon->anchor, quad); quad[1].x = quad[0].x; quad[1].y = quad[0].y + height; quad[2].x = quad[0].x + width; quad[2].y = quad[1].y; quad[3].x = quad[2].x; quad[3].y = quad[0].y; - ZnTransformPoints(wi->current_transfo, quad, icon->dev, 4); + ZnTransformPoints(t, quad, icon->dev, 4); for (i = 0; i < 4; i++) { icon->dev[i].x = ZnNearestInt(icon->dev[i].x); @@ -726,10 +760,49 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ZnWInfo *wi = item->wi; + IconItem icon = (IconItem) item; + int w, h, result; + ZnPoint origin; + char path[500]; + + if (prepass || (icon->image == ZnUnspecifiedImage)) { + return TCL_OK; + } + + ZnSizeOfImage(icon->image, &w, &h); + + ComputeTransfoAndOrigin(item, &origin); + + sprintf(path, "/InitialTransform load setmatrix\n" + "[%.15g %.15g %.15g %.15g %.15g %.15g] concat\n" + "1 -1 scale\n" + "%.15g %.15g translate\n", + wi->current_transfo->_[0][0], wi->current_transfo->_[0][1], + wi->current_transfo->_[1][0], wi->current_transfo->_[1][1], + wi->current_transfo->_[2][0], wi->current_transfo->_[2][1], + origin.x, origin.y - h); + Tcl_AppendResult(wi->interp, path, NULL); + + if (ZnImageIsBitmap(icon->image)) { + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(icon->color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + result = ZnPostscriptBitmap(wi->interp, wi->win, wi->ps_info, + icon->image, 0, 0, w, h); + } + else { + result = Tk_PostscriptImage(ZnImageTkImage(icon->image), wi->interp, wi->win, + wi->ps_info, 0, 0, w, h, prepass); + } + + return result; } diff --git a/generic/Image.c b/generic/Image.c index 10a507e..d6636e9 100644 --- a/generic/Image.c +++ b/generic/Image.c @@ -765,6 +765,18 @@ ZnImageRegion(ZnImage image) } +Tk_Image +ZnImageTkImage(ZnImage image) +{ + return ((Image) image)->bits->tkimage; +} + +Tk_PhotoHandle +ZnImageTkPhoto(ZnImage image) +{ + return ((Image) image)->bits->tkphoto; +} + /* ********************************************************************************** * diff --git a/generic/Image.h b/generic/Image.h index 6e72907..426c0df 100644 --- a/generic/Image.h +++ b/generic/Image.h @@ -29,28 +29,21 @@ typedef void *ZnImage; #define ZnGetBitmapPixel(bits, stride, x, y)\ (((bits)[(y)*(stride)+((x)>>3)]<<((x)&7))&0x80) -ZnImage -ZnGetImage(struct _ZnWInfo *wi, Tk_Uid image_name, - void (*inv_proc)(void *cd), void *cd); -ZnImage -ZnGetImageByValue(ZnImage image, void (*inv_proc)(void *cd), void *cd); -void -ZnFreeImage(ZnImage image, void (*inv_proc)(void *cd), void *cd); -char * -ZnNameOfImage(ZnImage image); -void -ZnSizeOfImage(ZnImage image, int *width, int *height); -Pixmap -ZnImagePixmap(ZnImage image, Tk_Window win); -ZnBool -ZnImageIsBitmap(ZnImage image); -TkRegion -ZnImageRegion(ZnImage image); +ZnImage ZnGetImage(struct _ZnWInfo *wi, Tk_Uid image_name, + void (*inv_proc)(void *cd), void *cd); +ZnImage ZnGetImageByValue(ZnImage image, void (*inv_proc)(void *cd), void *cd); +void ZnFreeImage(ZnImage image, void (*inv_proc)(void *cd), void *cd); +char * ZnNameOfImage(ZnImage image); +void ZnSizeOfImage(ZnImage image, int *width, int *height); +Pixmap ZnImagePixmap(ZnImage image, Tk_Window win); +ZnBool ZnImageIsBitmap(ZnImage image); +TkRegion ZnImageRegion(ZnImage image); +Tk_Image ZnImageTkImage(ZnImage image); +Tk_PhotoHandle ZnImageTkPhoto(ZnImage image); ZnBool ZnPointInImage(ZnImage image, int x, int y); #ifdef GL -GLuint -ZnImageTex(ZnImage image, ZnReal *t, ZnReal *s); +GLuint ZnImageTex(ZnImage image, ZnReal *t, ZnReal *s); typedef struct _ZnTexGlyphVertexInfo { GLfloat t0x; diff --git a/generic/Item.h b/generic/Item.h index 83f95e9..3871bf8 100644 --- a/generic/Item.h +++ b/generic/Item.h @@ -241,7 +241,7 @@ typedef int (*ZnItemIndexMethod)(ZnItem item, int field, Tcl_Obj *index_spec, typedef int (*ZnItemPartMethod)(ZnItem item, Tcl_Obj **part_spec, int *part); typedef int (*ZnItemSelectionMethod)(ZnItem item, int field, int offset, char *chars, int max_chars); -typedef void (*ZnItemPostScriptMethod)(ZnItem item, ZnBool prepass); +typedef int (*ZnItemPostScriptMethod)(ZnItem item, ZnBool prepass, ZnBBox *area); typedef void *ZnItemClassId; diff --git a/generic/Map.c b/generic/Map.c index c331c67..cba3d14 100644 --- a/generic/Map.c +++ b/generic/Map.c @@ -1557,10 +1557,12 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + return TCL_OK; } diff --git a/generic/PostScript.c b/generic/PostScript.c index 56737e9..eeee5f0 100644 --- a/generic/PostScript.c +++ b/generic/PostScript.c @@ -30,8 +30,6 @@ ********************************************************************************** */ -#if 0 - #ifndef _WIN32 #include #include @@ -39,7 +37,9 @@ #include #include #include +#include +#include "Types.h" #include "Item.h" #include "Group.h" #include "PostScript.h" @@ -59,152 +59,140 @@ static const char rcsid[] = "$Id$"; static const char compile_id[]="$Compile: " __FILE__ " " __DATE__ " " __TIME__ " $"; -#define PROLOG_VERSION 1.0 -#define PROLOG_REVISION 0 - -static char ps_prolog[] = ""; - - -typedef struct _ZnPostScriptInfo { - ZnBBox area; /* Area to print, in device coordinates. */ - ZnReal page_x; /* PostScript coordinates of anchor on page */ - ZnReal page_y; - ZnReal page_width; /* Printed width and height of output area. */ - ZnReal page_height; - Tk_Anchor page_anchor; /* Area anchor on Postscript page. */ - ZnBool landscape; /* True means output is rotated ccw by 90 degrees - * (landscape mode). */ - char *font_var; /* If non-NULL, gives name of global variable - * containing font mapping information. Malloc'ed. */ - char *color_var; /* If non-NULL, give name of global variable - * containing color mapping information. Malloc'ed. */ - int colormode; /* Tell how color show be handled: 0 for mono, - * 1 for gray, 2 for color. */ - char *filename; /* Name of file in which to write PostScript; NULL - * means return Postscript info as result. Malloc'ed. */ - char *channel_name; /* If -channel is specified, the name of the channel - * to use. Malloc'ed */ - Tcl_Channel chan; /* Open channel corresponding to fileName. */ - Tcl_HashTable font_table; /* Hash table containing names of all font families - * used in output. The table values are not used. */ - ZnBool prepass; /* True means that we're currently in - * the pre-pass that collects font information, - * so the PostScript generated isn't relevant. */ - ZnBool prolog; /* True means output should contain the file - * prolog.ps in the header. */ -} ZnPostScriptInfo; - - -static int ZnPsDimParse _ANSI_ARGS_((ClientData client_data, Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *ovalue, - char *widget_rec, int offset)); -static Tcl_Obj *ZnPsDimPrint _ANSI_ARGS_((ClientData client_data, Tk_Window tkwin, - char *widget_rec, int offset, - Tcl_FreeProc **free_proc)); -static int ZnPsColorModeParse _ANSI_ARGS_((ClientData client_data, Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *ovalue, - char *widget_rec, int offset)); -static Tcl_Obj *ZnPsColorModePrint _ANSI_ARGS_((ClientData client_data, Tk_Window tkwin, - char *widget_rec, int offset, - Tcl_FreeProc **free_proc)); -static int ZnBBoxParse _ANSI_ARGS_((ClientData client_data, Tcl_Interp *interp, - Tk_Window tkwin, Tcl_Obj *ovalue, - char *widget_rec, int offset)); -static Tcl_Obj *ZnBBoxPrint _ANSI_ARGS_((ClientData client_data, Tk_Window tkwin, - char *widget_rec, int offset, - Tcl_FreeProc **free_proc)); - -static Tk_CustomOption psDimOption = { - (Tk_OptionParseProc *) ZnPsDimParse, - (Tk_OptionPrintProc *) ZnPsDimPrint, - NULL -}; - -static Tk_CustomOption psColorModeOption = { - (Tk_OptionParseProc *) ZnPsColorModeParse, - (Tk_OptionPrintProc *) ZnPsColorModePrint, - NULL -}; - -static Tk_CustomOption bboxOption = { - (Tk_OptionParseProc *) ZnBBoxParse, - (Tk_OptionPrintProc *) ZnBBoxPrint, - NULL -}; +/* + * One of the following structures is created to keep track of Postscript + * output being generated. It consists mostly of information provided on + * the widget command line. + * WATCH! This structure must be kept in sync with the structure in + * tkCanvPs.c, we share most of the code for emitting postscript and + * this rely on sharing the structure. + */ +typedef struct TkPostscriptInfo { + int x, y, width, height; /* Area to print, in canvas pixel + * coordinates. */ + int x2, y2; /* x+width and y+height. */ + char *pageXString; /* String value of "-pagex" option or NULL. */ + char *pageYString; /* String value of "-pagey" option or NULL. */ + double pageX, pageY; /* Postscript coordinates (in points) + * corresponding to pageXString and + * pageYString. Don't forget that y-values + * grow upwards for Postscript! */ + char *pageWidthString; /* Printed width of output. */ + char *pageHeightString; /* Printed height of output. */ + double scale; /* Scale factor for conversion: each pixel + * maps into this many points. */ + Tk_Anchor pageAnchor; /* How to anchor bbox on Postscript page. */ + int rotate; /* Non-zero means output should be rotated + * on page (landscape mode). */ + char *fontVar; /* If non-NULL, gives name of global variable + * containing font mapping information. + * Malloc'ed. */ + char *colorVar; /* If non-NULL, give name of global variable + * containing color mapping information. + * Malloc'ed. */ + char *colorMode; /* Mode for handling colors: "monochrome", + * "gray", or "color". Malloc'ed. */ + int colorLevel; /* Numeric value corresponding to colorMode: + * 0 for mono, 1 for gray, 2 for color. */ + char *fileName; /* Name of file in which to write Postscript; + * NULL means return Postscript info as + * result. Malloc'ed. */ + char *channelName; /* If -channel is specified, the name of + * the channel to use. */ + Tcl_Channel chan; /* Open channel corresponding to fileName. */ + Tcl_HashTable fontTable; /* Hash table containing names of all font + * families used in output. The hash table + * values are not used. */ + int prepass; /* Non-zero means that we're currently in + * the pre-pass that collects font information, + * so the Postscript generated isn't + * relevant. */ + int prolog; /* Non-zero means output should contain + * the file prolog.ps in the header. */ + /* + * Below are extensions for Tkzinc. + */ + ZnBBox bbox; +} TkPostscriptInfo; /* - * Information used for argv parsing. + * The table below provides a template that's used to process arguments + * to the "postscript" command and fill in TkPostscriptInfo structures. */ static Tk_ConfigSpec config_specs[] = { - {TK_CONFIG_CUSTOM, "-area", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, area), 0, &bboxOption}, - {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, color_var), 0, NULL}, - {TK_CONFIG_CUSTOM, "-colormode", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, colormode), 0, &psColorModeOption}, - {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, filename), 0, NULL}, - {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, channel_name), 0, NULL}, - {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, font_var), 0, NULL}, - {TK_CONFIG_BOOLEAN, "-landscape", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, landscape), 0, NULL}, - {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, page_anchor), 0, NULL}, - {TK_CONFIG_CUSTOM, "-pageheight", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, page_height), 0, &psDimOption}, - {TK_CONFIG_CUSTOM, "-pagewidth", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, page_width), 0, &psDimOption}, - {TK_CONFIG_CUSTOM, "-pagex", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, page_x), 0, &psDimOption}, - {TK_CONFIG_CUSTOM, "-pagey", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, page_y), 0, &psDimOption}, - {TK_CONFIG_BOOLEAN, "-prolog", (char *) NULL, (char *) NULL, - "", Tk_Offset(ZnPostScriptInfo, prolog), 0, NULL}, - {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, - (char *) NULL, 0, 0, NULL} + {TK_CONFIG_STRING, "-colormap", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, colorVar), 0, NULL}, + {TK_CONFIG_STRING, "-colormode", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, colorMode), 0, NULL}, + {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, fileName), 0, NULL}, + {TK_CONFIG_STRING, "-channel", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, channelName), 0, NULL}, + {TK_CONFIG_STRING, "-fontmap", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, fontVar), 0, NULL}, + {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, height), 0, NULL}, + {TK_CONFIG_ANCHOR, "-pageanchor", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, pageAnchor), 0, NULL}, + {TK_CONFIG_STRING, "-pageheight", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, pageHeightString), 0, NULL}, + {TK_CONFIG_STRING, "-pagewidth", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, pageWidthString), 0, NULL}, + {TK_CONFIG_STRING, "-pagex", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, pageXString), 0, NULL}, + {TK_CONFIG_STRING, "-pagey", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, pageYString), 0, NULL}, + {TK_CONFIG_BOOLEAN, "-prolog", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, prolog), 0, NULL}, + {TK_CONFIG_BOOLEAN, "-rotate", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, rotate), 0, NULL}, + {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, width), 0, NULL}, + {TK_CONFIG_PIXELS, "-x", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, x), 0, NULL}, + {TK_CONFIG_PIXELS, "-y", (char *) NULL, (char *) NULL, + "", Tk_Offset(TkPostscriptInfo, y), 0, NULL}, + {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL, + (char *) NULL, 0, 0, NULL} }; - /* - *---------------------------------------------------------------------- + *-------------------------------------------------------------- + * + * GetPostscriptPoints -- + * + * Given a string, returns the number of Postscript points + * corresponding to that string. * - * ZnPsDimParse - * ZnPsDimPrint -- - * Converter for the PostScript dimension options - * (-pagex, -pagey, -pagewidth, -pageheight). + * Results: + * The return value is a standard Tcl return result. If + * TCL_OK is returned, then everything went well and the + * screen distance is stored at *doublePtr; otherwise + * TCL_ERROR is returned and an error message is left in + * the interp's result. * - *---------------------------------------------------------------------- + * Side effects: + * None. + * + *-------------------------------------------------------------- */ static int -ZnPsDimParse(ClientData client_data, - Tcl_Interp *interp, - Tk_Window tkwin, - Tcl_Obj *ovalue, - char *widget_rec, - int offset) +GetPostscriptPoints(Tcl_Interp *interp, + char *string, + double *double_ptr) { - ZnReal *dim = (ZnReal *) (widget_rec + offset); -#ifdef PTK - char *value = Tcl_GetString(ovalue); -#else - char *value = (char *) ovalue; -#endif - char *end; + char *end; double d; - d = strtod(value, &end); - if (end == value) { - dim_error: - Tcl_AppendResult(interp, "bad distance \"", value, "\"", NULL); + d = strtod(string, &end); + if (end == string) { + error: + Tcl_AppendResult(interp, "bad distance \"", string, "\"", (char *) NULL); return TCL_ERROR; } - while ((*end != '\0') && isspace(UCHAR(*end))) { end++; } - switch (*end) { case 'c': d *= 72.0/2.54; @@ -224,413 +212,144 @@ ZnPsDimParse(ClientData client_data, end++; break; default: - goto dim_error; + goto error; } - while ((*end != '\0') && isspace(UCHAR(*end))) { end++; } if (*end != 0) { - goto dim_error; - } - *dim = d; - - return TCL_OK; -} - -static Tcl_Obj * -ZnPsDimPrint(ClientData client_data, - Tk_Window tkwin, - char *widget_rec, - int offset, -#ifdef PTK - Tcl_FreeProc **free_proc -#else - Tcl_FreeProc **free_proc -#endif -) -{ - ZnReal *dim = (ZnReal *) (widget_rec + offset); - Tcl_Obj *obj = Tcl_NewDoubleObj(*dim); -#ifdef PTK - return obj; -#else - { - char *s1, *s2; - - *free_proc = TCL_DYNAMIC; - s1 = Tcl_GetString(obj); - s2 = ZnMalloc(strlen(s1) + 1); - strcpy(s2, s1); - Tcl_DecrRefCount(obj); - return (Tcl_Obj *) s2; - } -#endif -} - -/* - *---------------------------------------------------------------------- - * - * ZnPsColorModeParse - * ZnPsColorModePrint -- - * Converter for the PostScript -colormode option. - * - *---------------------------------------------------------------------- - */ -static int -ZnPsColorModeParse(ClientData client_data, - Tcl_Interp *interp, - Tk_Window tkwin, - Tcl_Obj *ovalue, - char *widget_rec, - int offset) -{ - int *mode = (int *) (widget_rec + offset); -#ifdef PTK - char *value = Tcl_GetString(ovalue); -#else - char *value = (char *) ovalue; -#endif - int result = TCL_OK; - - if (value != NULL) { - if (strcmp(value, "monochrome") == 0) { - *mode = 0; - } - else if (strcmp(value, "gray") == 0) { - *mode = 1; - } - else if (strcmp(value, "color") == 0) { - *mode = 2; - } - else { - Tcl_AppendResult(interp, " incorrect PostScript color mode \"", - value, "\" should be \"monochrome\", \"gray\"", - " or \"color\"", NULL); - result = TCL_ERROR; - } - } - - return result; -} - -static Tcl_Obj * -ZnPsColorModePrint(ClientData client_data, - Tk_Window tkwin, - char *widget_rec, - int offset, - Tcl_FreeProc **free_proc) -{ - int *mode = (int *) (widget_rec + offset); - char *s; - - switch (*mode) { - case 0: s = "monochrome"; - break; - case 1: s = "gray"; - break; - case 2: s = "color"; - break; - default: s = "PsColorModeInvalid"; - break; - } -#ifdef PTK - return Tcl_NewStringObj(s, -1); -#else - return (Tcl_Obj *) s; -#endif -} - -/* - *---------------------------------------------------------------------- - * - * ZnBBoxParse - * ZnBBoxPrint -- - * Converter for the -area option. - * - *---------------------------------------------------------------------- - */ -static int -ZnBBoxParse(ClientData client_data, - Tcl_Interp *interp, - Tk_Window tkwin, - Tcl_Obj *ovalue, - char *widget_rec, - int offset) -{ - ZnBBox *bbox = (ZnBBox *) (widget_rec + offset); - int i, result, num_elems; - Tcl_Obj **elems; - double d[4]; - - result = Tcl_ListObjGetElements(interp, ovalue, &num_elems, &elems); - if ((result == TCL_ERROR) || - (num_elems != 0) || - (num_elems != 4)) { - bbox_error: - Tcl_AppendResult(interp, " malformed area", NULL); - return TCL_ERROR; - } - - bbox->orig.x = bbox->orig.y = bbox->corner.x = bbox->corner.y = 0; - - if (num_elems != 0) { - for (i = 0; i < 4; i++) { - result = Tcl_GetDoubleFromObj(interp, elems[0], &d[0]); - if (result == TCL_ERROR) { - goto bbox_error; - } - } - bbox->orig.x = d[0]; - bbox->orig.y = d[1]; - bbox->corner.x = d[2]; - bbox->corner.y = d[3]; + goto error; } - + *double_ptr = d; return TCL_OK; } -static Tcl_Obj * -ZnBBoxPrint(ClientData client_data, - Tk_Window tkwin, - char *widget_rec, - int offset, -#ifdef PTK - Tcl_FreeProc **free_proc -#else - Tcl_FreeProc **free_proc -#endif - ) -{ - ZnBBox *bbox = (ZnBBox *) (widget_rec + offset); - Tcl_Obj *obj = NULL; - - obj = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bbox->orig.x)); - Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bbox->orig.y)); - Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bbox->corner.x)); - Tcl_ListObjAppendElement(NULL, obj, Tcl_NewDoubleObj(bbox->corner.y)); - -#ifdef PTK - return obj; -#else - { - char *s1, *s2; - - s1 = Tcl_GetString(obj); - s2 = ZnMalloc(strlen(s1) + 1); - strcpy(s2, s1); - Tcl_DecrRefCount(obj); - *free_proc = TCL_DYNAMIC; - return (Tcl_Obj *) s2; - } -#endif -} - - -#if 0 -/* - ********************************************************************************** - * - * EmitPostScript -- - * - ********************************************************************************** - */ - /* - * Emit Encapsulated PostScript Header. - */ - fprintf(ps_info->file, "%%!PS-Adobe-3.0 EPSF-3.0\n"); - fprintf(ps_info->file, "%%%%Creator: Zn Widget\n"); - pwd_info = getpwuid(getuid()); - fprintf(ps_info->file, "%%%%For: %s\n", pwd_info ? pwd_info->pw_gecos : "Unknown"); - fprintf(ps_info->file, "%%%%Title: (%s)\n", ps_info->title); - time(&now); - fprintf(ps_info->file, "%%%%CreationDate: %s\n", ctime(&now)); - if (ps_info->landscape) { - fprintf(ps_info->file, "%%%%BoundingBox: %d %d %d %d\n", 1, 1, 1, 1); - } - else { - fprintf(ps_info->file, "%%%%BoundingBox: %d %d %d %d\n", 1, 1, 1, 1); - } - fprintf(ps_info->file, "%%%%Pages: 1\n"); - fprintf(ps_info->file, "%%%%DocumentData: Clean7Bit\n"); - fprintf(ps_info->file, "%%%%Orientation: %s\n", - ps_info->landscape ? "Landscape" : "Portrait"); - fprintf(ps_info->file, "%%%%LanguageLevel: 1\n"); - fprintf(ps_info->file, "%%%%DocumentNeededResources: (atend)\n"); - fprintf(ps_info->file, - "%%%%DocumentSuppliedResources: procset Zinc-Widget-Prolog %f %d\n", - PROLOG_VERSION, PROLOG_REVISION); - fprintf(ps_info->file, "%%%%EndComments\n\n\n"); - - /* - * Emit the prolog. - */ - fprintf(ps_info->file, "%%%%BeginProlog\n"); - fprintf(ps_info->file, "%%%%BeginResource: procset Zinc-Widget-Prolog %f %d\n", - PROLOG_VERSION, PROLOG_REVISION); - fwrite(ps_prolog, 1, sizeof(ps_prolog), ps_info->file); - fprintf(ps_info->file, "%%%%EndResource\n"); - fprintf(ps_info->file, "%%%%EndProlog\n"); - - /* - * Emit the document setup. - */ - fprintf(ps_info->file, "%%%%BeginSetup\n"); - fprintf(ps_info->file, "%%%%EndSetup\n"); - - /* - * Emit the page setup. - */ - fprintf(ps_info->file, "%%%%Page: 0 1\n"); - fprintf(ps_info->file, "%%%%BeginPageSetup\n"); - fprintf(ps_info->file, "%%%%EndPageSetup\n"); - - /* - * Iterate through all items emitting PostScript for each. - */ - - /* - * Emit the page trailer. - */ - fprintf(ps_info->file, "%%%%PageTrailer\n"); - - /* - * Emit the document trailer. - */ - fprintf(ps_info->file, "%%%%Trailer\n"); - s = "%%DocumentNeededResources: font "; - for (fs = (XFontStruct *) ZnListArray(ps_info->fonts), - i = ZnListSize(ps_info->fonts); i > 0; i--, fs++) { - fprintf(ps_info->file, "%s", s); - s = "%%+ font"; - } - fprintf(ps_info->file, "%%%%EOF\n"); -#endif - /* *-------------------------------------------------------------- * - * ZnPostScriptY -- - * - * Given a y-coordinate in local coordinates, this procedure - * returns a y-coordinate to use for PostScript output. + * ZnPostScriptCmd -- * - *-------------------------------------------------------------- - */ -ZnReal -ZnPostScriptY(ZnReal y, - void *ps_info) -{ - return ((ZnPostScriptInfo *) ps_info)->area.corner.y - y; -} - -/* - *---------------------------------------------------------------------------- + * This procedure is invoked to process the "postscript" options + * of the widget command for zinc widgets. See the user + * documentation for details on what it does. * - * ZnPostScriptCmd -- + * Results: + * A standard Tcl result. * - * This procedure process the "postscript" command for - * zinc widgets. + * Side effects: + * See the user documentation. * - *---------------------------------------------------------------------------- + *-------------------------------------------------------------- */ int -ZnPostScriptCmd(ZnWInfo *wi, - int argc, - Tcl_Obj *CONST args[]) +ZnPostScriptCmd(ZnWInfo *wi, + int argc, + Tcl_Obj *CONST argv[]) { - ZnPostScriptInfo ps_info; - void *old_info; - int result; - int delta_x = 0, delta_y = 0; - ZnReal width, height; - CONST char *p; - Tcl_DString buffer; + TkPostscriptInfo ps_info; + Tk_PostscriptInfo old_info; + int result; #define STRING_LENGTH 400 - char string[STRING_LENGTH+1]; - ZnBBox *area; - time_t now; - Tcl_HashSearch search; - Tcl_HashEntry *entry; - - old_info = wi->ps_info; - wi->ps_info = (void *) &ps_info; - + char string[STRING_LENGTH+1]; + CONST char *p; + time_t now; + size_t length; + Tk_Window tkwin = wi->win; /* - * A null area means print the currently visible area. + * Offset of lower-left corner of area to be marked up, measured + * in canvas units from the positioning point on the page (reflects + * anchor position). Initial values needed only to stop compiler + * warnings. */ - area = &ps_info.area; - area->orig.x = 0; - area->orig.y = 0; - area->corner.x = 0; - area->corner.y = 0; + int delta_x = 0, delta_y = 0; + Tcl_HashSearch search; + Tcl_HashEntry *entry; + Tcl_DString buffer; + char psenccmd[] = "::tk::ensure_psenc_is_loaded"; + /* - * Center the result on a letter format page - * The size will be deduced automatically from - * the area (default to a 1:1 scale along X axis). + *---------------------------------------------------------------- + * Initialize the data structure describing Postscript generation, + * then process all the arguments to fill the data structure in. + *---------------------------------------------------------------- */ - ps_info.page_x = 72*4.25; - ps_info.page_y = 72*5.5; - ps_info.page_width = -1; - ps_info.page_height = -1; - ps_info.page_anchor = TK_ANCHOR_CENTER; - - ps_info.landscape = False; - ps_info.font_var = NULL; - ps_info.color_var = NULL; - ps_info.colormode = 2; - ps_info.filename = NULL; - ps_info.channel_name = NULL; + result = Tcl_EvalEx(wi->interp, psenccmd, -1, TCL_EVAL_GLOBAL); + if (result != TCL_OK) { + return result; + } + old_info = wi->ps_info; + wi->ps_info = (Tk_PostscriptInfo) &ps_info; + ps_info.x = (int) wi->origin.x; + ps_info.y = (int) wi->origin.y; + ps_info.width = -1; + ps_info.height = -1; + ps_info.pageXString = NULL; + ps_info.pageYString = NULL; + ps_info.pageX = 72*4.25; + ps_info.pageY = 72*5.5; + ps_info.pageWidthString = NULL; + ps_info.pageHeightString = NULL; + ps_info.scale = 1.0; + ps_info.pageAnchor = TK_ANCHOR_CENTER; + ps_info.rotate = 0; + ps_info.fontVar = NULL; + ps_info.colorVar = NULL; + ps_info.colorMode = NULL; + ps_info.colorLevel = 0; + ps_info.fileName = NULL; + ps_info.channelName = NULL; ps_info.chan = NULL; - ps_info.prepass = False; - ps_info.prolog = True; - Tcl_InitHashTable(&ps_info.font_table, TCL_STRING_KEYS); - result = Tk_ConfigureWidget(wi->interp, wi->win, config_specs, argc-2, -#ifdef PTK - (Tcl_Obj **) args+2, (char *) &ps_info, - TK_CONFIG_ARGV_ONLY -#else - (CONST char **) args+2, (char *) &ps_info, - TK_CONFIG_ARGV_ONLY|TK_CONFIG_OBJS -#endif -); + ps_info.prepass = 0; + ps_info.prolog = 1; + Tcl_InitHashTable(&ps_info.fontTable, TCL_STRING_KEYS); + result = Tk_ConfigureWidget(wi->interp, wi->win, config_specs, + argc-2, (CONST char **) argv+2, + (char *) &ps_info, + TK_CONFIG_ARGV_ONLY|TK_CONFIG_OBJS); if (result != TCL_OK) { goto cleanup; } - if ((area->corner.x - area->orig.x) == 0) { - area->orig.x = 0; - area->corner.x = Tk_Width(wi->win); + if (ps_info.width == -1) { + ps_info.width = Tk_Width(tkwin); } - width = area->corner.x - area->orig.x; - if ((area->corner.y - area->orig.y) == 0) { - area->orig.y = 0; - area->corner.y = Tk_Height(wi->win); + if (ps_info.height == -1) { + ps_info.height = Tk_Height(tkwin); } - height = area->corner.y - area->orig.y; - - if ((ps_info.page_width < 0) || (ps_info.page_height < 0)) { - ZnReal scale; - if (ps_info.page_width >= 0) { - scale = ps_info.page_width / width; - } - else if (ps_info.page_height >= 0) { - scale = ps_info.page_height / height; + ps_info.x2 = ps_info.x + ps_info.width; + ps_info.y2 = ps_info.y + ps_info.height; + ps_info.bbox.orig.x = ps_info.x; + ps_info.bbox.orig.y = ps_info.y; + ps_info.bbox.corner.x = ps_info.x2; + ps_info.bbox.corner.y = ps_info.y2; + + if (ps_info.pageXString != NULL) { + if (GetPostscriptPoints(wi->interp, ps_info.pageXString, &ps_info.pageX) != TCL_OK) { + goto cleanup; } - else { - scale = (72.0 / 25.4) * WidthMMOfScreen(Tk_Screen(wi->win)); - scale /= WidthOfScreen(Tk_Screen(wi->win)); + } + if (ps_info.pageYString != NULL) { + if (GetPostscriptPoints(wi->interp, ps_info.pageYString, &ps_info.pageY) != TCL_OK) { + goto cleanup; } - if (ps_info.page_width < 0) { - ps_info.page_width = width * scale; + } + if (ps_info.pageWidthString != NULL) { + if (GetPostscriptPoints(wi->interp, ps_info.pageWidthString, &ps_info.scale) != TCL_OK) { + goto cleanup; } - if (ps_info.page_height < 0) { - ps_info.page_height = height * scale; + ps_info.scale /= ps_info.width; + } + else if (ps_info.pageHeightString != NULL) { + if (GetPostscriptPoints(wi->interp, ps_info.pageHeightString, &ps_info.scale) != TCL_OK) { + goto cleanup; } + ps_info.scale /= ps_info.height; } - - switch (ps_info.page_anchor) { + else { + ps_info.scale = (72.0/25.4)*WidthMMOfScreen(Tk_Screen(tkwin)); + ps_info.scale /= WidthOfScreen(Tk_Screen(tkwin)); + } + switch (ps_info.pageAnchor) { case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW: @@ -639,24 +358,24 @@ ZnPostScriptCmd(ZnWInfo *wi, case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S: - delta_x = -width/2; + delta_x = -ps_info.width/2; break; case TK_ANCHOR_NE: case TK_ANCHOR_E: case TK_ANCHOR_SE: - delta_x = -width; + delta_x = -ps_info.width; break; } - switch (ps_info.page_anchor) { + switch (ps_info.pageAnchor) { case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE: - delta_y = -height; + delta_y = - ps_info.height; break; case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E: - delta_y = -height/2; + delta_y = -ps_info.height/2; break; case TK_ANCHOR_SW: case TK_ANCHOR_S: @@ -665,28 +384,50 @@ ZnPostScriptCmd(ZnWInfo *wi, break; } - if (ps_info.filename != NULL) { + if (ps_info.colorMode == NULL) { + ps_info.colorLevel = 2; + } + else { + length = strlen(ps_info.colorMode); + if (strncmp(ps_info.colorMode, "monochrome", length) == 0) { + ps_info.colorLevel = 0; + } + else if (strncmp(ps_info.colorMode, "gray", length) == 0) { + ps_info.colorLevel = 1; + } + else if (strncmp(ps_info.colorMode, "color", length) == 0) { + ps_info.colorLevel = 2; + } + else { + Tcl_AppendResult(wi->interp, "bad color mode \"", ps_info.colorMode, + "\": must be monochrome, ", "gray, or color", + (char *) NULL); + goto cleanup; + } + } + if (ps_info.fileName != NULL) { /* * Check that -file and -channel are not both specified. */ - if (ps_info.channel_name != NULL) { - Tcl_AppendResult(wi->interp, "can't specify both -file and -channel", NULL); + if (ps_info.channelName != NULL) { + Tcl_AppendResult(wi->interp, "can't specify both -file", " and -channel", + (char *) NULL); result = TCL_ERROR; goto cleanup; } - /* * Check that we are not in a safe interpreter. If we are, disallow * the -file specification. */ if (Tcl_IsSafe(wi->interp)) { - Tcl_AppendResult(wi->interp, "can't specify -file in a safe interpreter", NULL); + Tcl_AppendResult(wi->interp, "can't specify -file in a", " safe interpreter", + (char *) NULL); result = TCL_ERROR; goto cleanup; } - - p = Tcl_TranslateFileName(wi->interp, ps_info.filename, &buffer); + + p = Tcl_TranslateFileName(wi->interp, ps_info.fileName, &buffer); if (p == NULL) { goto cleanup; } @@ -697,21 +438,21 @@ ZnPostScriptCmd(ZnWInfo *wi, } } - if (ps_info.channel_name != NULL) { + if (ps_info.channelName != NULL) { int mode; /* * Check that the channel is found in this interpreter and that it * is open for writing. */ - ps_info.chan = Tcl_GetChannel(wi->interp, ps_info.channel_name, &mode); + ps_info.chan = Tcl_GetChannel(wi->interp, ps_info.channelName, &mode); if (ps_info.chan == (Tcl_Channel) NULL) { result = TCL_ERROR; goto cleanup; } if ((mode & TCL_WRITABLE) == 0) { - Tcl_AppendResult(wi->interp, "channel \"", ps_info.channel_name, - "\" wasn't opened for writing", NULL); + Tcl_AppendResult(wi->interp, "channel \"", ps_info.channelName, + "\" wasn't opened for writing", (char *) NULL); result = TCL_ERROR; goto cleanup; } @@ -727,10 +468,15 @@ ZnPostScriptCmd(ZnWInfo *wi, *-------------------------------------------------------- */ ps_info.prepass = 1; - - wi->top_group->class->PostScript(wi->top_group, True); + result = wi->top_group->class->PostScript(wi->top_group, True, &ps_info.bbox); Tcl_ResetResult(wi->interp); - + /* + * If an error occurred, just proceed with the main pass. + * There's no need to report the error now; it can be + * reported later (errors can happen later that don't + * happen now, so we still have to check for errors later + * anyway). + */ ps_info.prepass = 0; /* @@ -739,77 +485,57 @@ ZnPostScriptCmd(ZnWInfo *wi, *-------------------------------------------------------- */ if (ps_info.prolog) { - ZnReal scale_x, scale_y; - - scale_x = ps_info.page_width / width; - scale_y = ps_info.page_height/ height; - - Tcl_AppendResult(wi->interp, - "%!PS-Adobe-3.0 EPSF-3.0\n", - "%%Creator: TkZinc Widget\n", - NULL); + Tcl_AppendResult(wi->interp, "%!PS-Adobe-3.0 EPSF-3.0\n", + "%%Creator: Tk Zinc Widget\n", (char *) NULL); #ifdef HAVE_PW_GECOS if (!Tcl_IsSafe(wi->interp)) { - struct passwd *pw = getpwuid(getuid()); - Tcl_AppendResult(wi->interp, - "%%For: ", (pw != NULL) ? pw->pw_gecos : "Unknown", "\n", - NULL); + struct passwd *pwPtr = getpwuid(getuid()); /* INTL: Native. */ + Tcl_AppendResult(wi->interp, "%%For: ", + (pwPtr != NULL) ? pwPtr->pw_gecos : "Unknown", "\n", + (char *) NULL); endpwent(); } #endif /* HAVE_PW_GECOS */ - Tcl_AppendResult(wi->interp, - "%%Title: Window ", Tk_PathName(wi->win), "\n", - NULL); + Tcl_AppendResult(wi->interp, "%%Title: Window ", Tk_PathName(tkwin), "\n", + (char *) NULL); time(&now); - Tcl_AppendResult(wi->interp, - "%%CreationDate: ", ctime(&now), - NULL); - - if (!ps_info.landscape) { - sprintf(string, "%d %d %d %d", - (int) (ps_info.page_x + scale_x*delta_x), - (int) (ps_info.page_y + scale_y*delta_y), - (int) (ps_info.page_x + scale_x*(delta_x + width) + 1.0), - (int) (ps_info.page_y + scale_y*(delta_y + height) + 1.0)); - } else { + /* INTL: Native. */ + Tcl_AppendResult(wi->interp, "%%CreationDate: ", ctime(&now), (char *) NULL); + if (!ps_info.rotate) { + sprintf(string, "%d %d %d %d", (int) (ps_info.pageX + ps_info.scale*delta_x), + (int) (ps_info.pageY + ps_info.scale*delta_y), + (int) (ps_info.pageX + ps_info.scale*(delta_x + ps_info.width) + 1.0), + (int) (ps_info.pageY + ps_info.scale*(delta_y + ps_info.height) + 1.0)); + } + else { sprintf(string, "%d %d %d %d", - (int) (ps_info.page_x - scale_x*(delta_y + height)), - (int) (ps_info.page_y + scale_y*delta_x), - (int) (ps_info.page_x - scale_x*delta_y + 1.0), - (int) (ps_info.page_y + scale_y*(delta_x + width) + 1.0)); - } - Tcl_AppendResult(wi->interp, - "%%BoundingBox: ", string, "\n", - NULL); - Tcl_AppendResult(wi->interp, - "%%Pages: 1\n", - "%%DocumentData: Clean7Bit\n", - NULL); - Tcl_AppendResult(wi->interp, - "%%Orientation: ", - ps_info.landscape ? "Landscape\n" : "Portrait\n", - NULL); + (int) (ps_info.pageX - ps_info.scale*(delta_y + ps_info.height)), + (int) (ps_info.pageY + ps_info.scale*delta_x), + (int) (ps_info.pageX - ps_info.scale*delta_y + 1.0), + (int) (ps_info.pageY + ps_info.scale*(delta_x + ps_info.width) + 1.0)); + } + Tcl_AppendResult(wi->interp, "%%BoundingBox: ", string, "\n", (char *) NULL); + Tcl_AppendResult(wi->interp, "%%Pages: 1\n", "%%DocumentData: Clean7Bit\n", + (char *) NULL); + Tcl_AppendResult(wi->interp, "%%Orientation: ", + ps_info.rotate ? "Landscape\n" : "Portrait\n", (char *) NULL); p = "%%DocumentNeededResources: font "; - for (entry = Tcl_FirstHashEntry(&ps_info.font_table, &search); - entry != NULL; entry = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(wi->interp, - p, Tcl_GetHashKey(&ps_info.font_table, entry), "\n", - NULL); + for (entry = Tcl_FirstHashEntry(&ps_info.fontTable, &search); entry != NULL; + entry = Tcl_NextHashEntry(&search)) { + Tcl_AppendResult(wi->interp, p, Tcl_GetHashKey(&ps_info.fontTable, entry), + "\n", (char *) NULL); p = "%%+ font "; } - Tcl_AppendResult(wi->interp, - "%%EndComments\n\n", - NULL); - + Tcl_AppendResult(wi->interp, "%%EndComments\n\n", (char *) NULL); + /* * Insert the prolog */ - Tcl_AppendResult(wi->interp, - Tcl_GetVar(wi->interp,"::tk::ps_preamable", TCL_GLOBAL_ONLY), - NULL); - + Tcl_AppendResult(wi->interp, Tcl_GetVar(wi->interp,"::tk::ps_preamable", + TCL_GLOBAL_ONLY), (char *) NULL); + if (ps_info.chan != NULL) { - /* Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1);*/ + Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1); Tcl_ResetResult(wi->interp); } @@ -818,21 +544,15 @@ ZnPostScriptCmd(ZnWInfo *wi, * Document setup: set the color level and include fonts. *----------------------------------------------------------- */ - sprintf(string, "/CL %d def\n", ps_info.colormode); - Tcl_AppendResult(wi->interp, - "%%BeginSetup\n", string, - NULL); - for (entry = Tcl_FirstHashEntry(&ps_info.font_table, &search); - entry != NULL; entry = Tcl_NextHashEntry(&search)) { - Tcl_AppendResult(wi->interp, - "%%IncludeResource: font ", - Tcl_GetHashKey(&ps_info.font_table, entry), "\n", - NULL); - } - Tcl_AppendResult(wi->interp, - "%%EndSetup\n\n", - NULL); - + sprintf(string, "/CL %d def\n", ps_info.colorLevel); + Tcl_AppendResult(wi->interp, "%%BeginSetup\n", string, (char *) NULL); + for (entry = Tcl_FirstHashEntry(&ps_info.fontTable, &search); entry != NULL; + entry = Tcl_NextHashEntry(&search)) { + Tcl_AppendResult(wi->interp, "%%IncludeResource: font ", + Tcl_GetHashKey(&ps_info.fontTable, entry), "\n", (char *) NULL); + } + Tcl_AppendResult(wi->interp, "%%EndSetup\n\n", (char *) NULL); + /* *----------------------------------------------------------- * Page setup: move to page positioning point, rotate if @@ -840,44 +560,43 @@ ZnPostScriptCmd(ZnWInfo *wi, * and set clip region. *----------------------------------------------------------- */ - Tcl_AppendResult(wi->interp, - "%%Page: 1 1\n", - "save\n", - NULL); - sprintf(string, "%.1f %.1f translate\n", ps_info.page_x, ps_info.page_y); - Tcl_AppendResult(wi->interp, string, NULL); - if (ps_info.landscape) { - Tcl_AppendResult(wi->interp, - "90 rotate\n", - NULL); - } - sprintf(string, "%.4g %.4g scale\n", scale_x, scale_y); - Tcl_AppendResult(wi->interp, string, NULL); - sprintf(string, "%d %d translate\n", - (int) (delta_x - area->orig.x), (int) delta_y); - Tcl_AppendResult(wi->interp, string, NULL); + Tcl_AppendResult(wi->interp, "%%Page: 1 1\n", "save\n", (char *) NULL); + sprintf(string, "%.1f %.1f translate\n", ps_info.pageX, ps_info.pageY); + Tcl_AppendResult(wi->interp, string, (char *) NULL); + if (ps_info.rotate) { + Tcl_AppendResult(wi->interp, "90 rotate\n", (char *) NULL); + } + sprintf(string, "%.4g %.4g scale\n", ps_info.scale, -ps_info.scale); + Tcl_AppendResult(wi->interp, string, (char *) NULL); + sprintf(string, "%d %d translate\n", delta_x - ps_info.x, delta_y); + Tcl_AppendResult(wi->interp, string, (char *) NULL); + /* + * Save the base matrix for further reference. + */ + Tcl_AppendResult(wi->interp, "/InitialTransform matrix currentmatrix def\n", NULL); + sprintf(string, "%d %.15g moveto %d %.15g lineto %d %.15g lineto %d %.15g", - (int) area->orig.x, ZnPostScriptY(area->orig.y, &ps_info), - (int) area->corner.x, ZnPostScriptY(area->orig.y, &ps_info), - (int) area->corner.x, ZnPostScriptY(area->corner.y, &ps_info), - (int) area->orig.x, ZnPostScriptY(area->corner.y, &ps_info)); - Tcl_AppendResult(wi->interp, - string, " lineto closepath clip newpath\n", - NULL); + ps_info.x, Tk_PostscriptY((double) ps_info.y, (Tk_PostscriptInfo) &ps_info), + ps_info.x2, Tk_PostscriptY((double) ps_info.y, (Tk_PostscriptInfo) &ps_info), + ps_info.x2, Tk_PostscriptY((double) ps_info.y2, (Tk_PostscriptInfo) &ps_info), + ps_info.x, Tk_PostscriptY((double) ps_info.y2, (Tk_PostscriptInfo) &ps_info)); + Tcl_AppendResult(wi->interp, string, " lineto closepath clip newpath\n", (char *) NULL); } - if (ps_info.chan != NULL) { - /* Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1);*/ + Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1); Tcl_ResetResult(wi->interp); } - + /* *--------------------------------------------------------------------- - * Second pass through all the items. This time PostScript is actually - * emitted. + * Iterate through all the items, having each relevant one draw itself. + * Quit if any of the items returns an error. *--------------------------------------------------------------------- */ - wi->top_group->class->PostScript(wi->top_group, False); + result = wi->top_group->class->PostScript(wi->top_group, False, &ps_info.bbox); + if (result == TCL_ERROR) { + goto cleanup; + } /* *--------------------------------------------------------------------- @@ -886,37 +605,1263 @@ ZnPostScriptCmd(ZnWInfo *wi, *--------------------------------------------------------------------- */ if (ps_info.prolog) { - Tcl_AppendResult(wi->interp, - "restore showpage\n\n", - "%%Trailer\nend\n%%EOF\n", - NULL); + Tcl_AppendResult(wi->interp, "restore showpage\n\n", "%%Trailer\nend\n%%EOF\n", + (char *) NULL); } if (ps_info.chan != NULL) { - /* Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1);*/ + Tcl_Write(ps_info.chan, Tcl_GetStringResult(wi->interp), -1); Tcl_ResetResult(wi->interp); } - cleanup: - if (ps_info.font_var != NULL) { - ZnFree(ps_info.font_var); + /* + * Clean up ps_info to release malloc'ed stuff. + */ + cleanup: + if (ps_info.pageXString != NULL) { + ckfree(ps_info.pageXString); } - if (ps_info.color_var != NULL) { - ZnFree(ps_info.color_var); + if (ps_info.pageYString != NULL) { + ckfree(ps_info.pageYString); } - if (ps_info.filename != NULL) { - ZnFree(ps_info.filename); + if (ps_info.pageWidthString != NULL) { + ckfree(ps_info.pageWidthString); } - if ((ps_info.chan != NULL) && (ps_info.channel_name == NULL)) { - Tcl_Close(wi->interp, ps_info.chan); + if (ps_info.pageHeightString != NULL) { + ckfree(ps_info.pageHeightString); } - if (ps_info.channel_name != NULL) { - ZnFree(ps_info.channel_name); + if (ps_info.fontVar != NULL) { + ckfree(ps_info.fontVar); } - Tcl_DeleteHashTable(&ps_info.font_table); - wi->ps_info = old_info; - + if (ps_info.colorVar != NULL) { + ckfree(ps_info.colorVar); + } + if (ps_info.colorMode != NULL) { + ckfree(ps_info.colorMode); + } + if (ps_info.fileName != NULL) { + ckfree(ps_info.fileName); + } + if ((ps_info.chan != NULL) && (ps_info.channelName == NULL)) { + Tcl_Close(wi->interp, ps_info.chan); + } + if (ps_info.channelName != NULL) { + ckfree(ps_info.channelName); + } + Tcl_DeleteHashTable(&ps_info.fontTable); + wi->ps_info = (Tk_PostscriptInfo) old_info; return result; } +void +ZnFlushPsChan(Tcl_Interp *interp, + Tk_PostscriptInfo ps_info) { + TkPostscriptInfo *psi = (TkPostscriptInfo *) ps_info; + if (psi->chan != NULL) { + Tcl_Write(psi->chan, Tcl_GetStringResult(interp), -1); + Tcl_ResetResult(interp); + } +} +int +ZnPostscriptOutline(Tcl_Interp *interp, + Tk_PostscriptInfo ps_info, + Tk_Window tkwin, + ZnDim line_width, + ZnLineStyle line_style, + ZnGradient *line_color, + ZnImage line_pattern) +{ + char string[41]; + char dashed[] = { 8 }; + char dotted[] = { 2, 5 }; + char mixed[] = { 8, 5, 2, 5 }; + char *pattern = NULL; + int patlen = 0; + + sprintf(string, "%.15g setlinewidth\n", (double) line_width); + Tcl_AppendResult(interp, string, NULL); + /* + * Setup the line style. It is dependent on the line + * width. + */ + switch (line_style) { + case ZN_LINE_DOTTED: + pattern = dotted; + patlen = sizeof(dotted)/sizeof(char); + break; + case ZN_LINE_DASHED: + pattern = dashed; + patlen = sizeof(dashed)/sizeof(char); + break; + case ZN_LINE_MIXED: + pattern = mixed; + patlen = sizeof(mixed)/sizeof(char); + break; + } + if (pattern) { + sprintf(string, "[%d", ((*pattern++) * (int) line_width) & 0xff); + while (--patlen) { + sprintf(string+strlen(string), " %d", ((*pattern++) * (int) line_width) & 0xff); + } + Tcl_AppendResult(interp, string, NULL); + sprintf(string, "] %d setdash\n", 0 /* dash offset */); + Tcl_AppendResult(interp, string, NULL); + } + if (Tk_PostscriptColor(interp, ps_info, + ZnGetGradientColor(line_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + if (line_pattern != ZnUnspecifiedImage) { + Tcl_AppendResult(interp, "StrokeClip ", NULL); + if (Tk_PostscriptStipple(interp, tkwin, ps_info, + ZnImagePixmap(line_pattern, tkwin)) != TCL_OK) { + return TCL_ERROR; + } + } + else { + Tcl_AppendResult(interp, "stroke\n", NULL); + } + + return TCL_OK; +} + +/* + * Emit PostScript to describe a bitmap as a string possibly + * spliting it in parts due to the limited length of PostScript + * strings. + * This function emit the common code for ZnPostscriptBitmap and + * ZnPostscriptStipple. + */ +static int +EmitPSBitmap() +{ +} + +int +ZnPostscriptStipple(Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo ps_info, + ZnImage bitmap) +{ + return TCL_OK; +} + +int +ZnPostscriptBitmap(Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo ps_info, + ZnImage bitmap, + ZnReal x, + ZnReal y, + int width, + int height) +{ + char buffer[100 + TCL_DOUBLE_SPACE * 2 + TCL_INTEGER_SPACE * 4]; + int rows_at_once, rows_this_time, cur_row; + + if (width > 60000) { + Tcl_ResetResult(interp); + Tcl_AppendResult(interp, "can't generate Postscript", + " for bitmaps more than 60000 pixels wide", NULL); + return TCL_ERROR; + } + rows_at_once = 60000/width; + if (rows_at_once < 1) { + rows_at_once = 1; + } + sprintf(buffer, "%.15g %.15g translate\n", x, y + height); + Tcl_AppendResult(interp, buffer, NULL); + for (cur_row = 0; cur_row < height; cur_row += rows_at_once) { + rows_this_time = rows_at_once; + if (rows_this_time > (height - cur_row)) { + rows_this_time = height - cur_row; + } + sprintf(buffer, "0 -%.15g translate\n%d %d true matrix {\n", + (double) rows_this_time, width, rows_this_time); + Tcl_AppendResult(interp, buffer, NULL); + if (Tk_PostscriptBitmap(interp, tkwin, ps_info, ZnImagePixmap(bitmap, tkwin), + 0, cur_row, width, rows_this_time) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(interp, "\n} imagemask\n", (char *) NULL); + } + + return TCL_OK; +} + +void +ZnPostscriptString(Tcl_Interp *interp, + char *str, + int num_bytes) +{ + int used, len, clen; + int c, bytecount = 0; + CONST char *p, *last_p, *glyphname; + Tcl_UniChar ch; + char charbuf[5]; +#define MAXUSE 500 + char buf[MAXUSE+30]; + + used = 0; + buf[used++] = '['; + buf[used++] = '('; + len = num_bytes; + p = str; + while (len) { + clen = Tcl_UtfToUniChar(p, &ch); + last_p = p; + p += clen; + len -= clen; + /* + * INTL: For now we just treat the characters as binary + * data and display the lower byte. Eventually this should + * be revised to handle international postscript fonts. + */ + Tcl_UtfToExternal(interp, NULL, last_p, clen, 0, NULL, + charbuf, 4, NULL, &bytecount, NULL); + if (bytecount == 1) { + c = UCHAR(charbuf[0]); + if ((c == '(') || (c == ')') || (c == '\\') || + (c < 0x20) || (c >= UCHAR(0x7f))) { + /* + * Tricky point: the "03" is necessary in the sprintf + * below, so that a full three digits of octal are + * always generated. Without the "03", a number + * following this sequence could be interpreted by + * Postscript as part of this sequence. + */ + sprintf(buf + used, "\\%03o", c); + used += 4; + } + else { + buf[used++] = c; + } + } + else { + /* This character doesn't belong to system character set. + * So, we must use full glyph name */ + sprintf(charbuf, "%04X", ch); /* endianness? */ + if ((glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", charbuf, 0))) { + if ((used > 0) && (buf[used-1] == '(')) { + --used; + } + else { + buf[used++] = ')'; + } + if ((used + strlen(glyphname)) >= MAXUSE) { + buf[used] = '\0'; + Tcl_AppendResult(interp, buf, NULL); + used = 0; + } + buf[used++] = '/'; + while(*glyphname) { + buf[used++] = *glyphname++ ; + } + buf[used++] = '('; + } + } + if (used >= MAXUSE) { + buf[used] = '\0'; + Tcl_AppendResult(interp, buf, NULL); + used = 0; + } + } + buf[used++] = ')'; + buf[used++] = ']'; + buf[used++] = '\n'; + buf[used] = '\0'; + Tcl_AppendResult(interp, buf, NULL); +} + +int +ZnPostscriptTile(Tcl_Interp *interp, + Tk_Window win, + Tk_PostscriptInfo ps_info, + ZnImage image) +{ + char path[150]; + int w, h; + + ZnSizeOfImage(image, &w, &h); + Tcl_AppendResult(interp, "<< /PatternType 1 /PaintType 1 /TilingType 1\n", NULL); + sprintf(path, " /BBox [%.15g %.15g %.15g %.15g] /XStep %.15g /YStep %.15g\n", + 0.0, (double) h, (double) w, 0.0, (double) w, (double) h); + Tcl_AppendResult(interp, path, " /PaintProc { begin\n", NULL); + + /* + * On ne peut pas reprendre le code de Tk_PostscriptImage, + * il génère une image inline impropre à l'inclusion dans + * une procedure de tuilage. C'est d'ailleurs un problème : + * Une string postscript ne doit pas dépasser 65K. + */ + if (Tk_PostscriptImage(ZnImageTkImage(image), interp, win, ps_info, 0, 0, w, h, 0) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_AppendResult(interp, "end } bind >> matrix makepattern setpattern fill\n", NULL); + + return TCL_OK; +} + +void +ZnPostscriptTrace(ZnItem item, + ZnBool enter) +{ + ZnWInfo *wi = item->wi; + char buf[100]; + + if (wi->debug) { + sprintf(buf, "%%%%%%%% %s for %s %d %%%%%%%%\n", + enter ? "Code" : "End of code", item->class->name, item->id); + Tcl_AppendResult(wi->interp, buf, NULL); + } +} + +int +ZnPostscriptGradient(Tcl_Interp *interp, + Tk_PostscriptInfo ps_info, + ZnGradient *gradient, + ZnPoint *quad, + ZnPoly *poly) +{ + unsigned int i; + char path[150]; + ZnPoint p, center, extent; + ZnGradientColor *gc1, *gc2; + + if (gradient->type == ZN_CONICAL_GRADIENT || gradient->type == ZN_PATH_GRADIENT) { + return TCL_OK; + } + + Tcl_AppendResult(interp, "<< /PatternType 2 /Shading\n", NULL); + + switch (gradient->type) { + case ZN_AXIAL_GRADIENT: + /* + * Fill the rectangle defined by quad with + * the axial gradient. + */ + switch (gradient->angle) { + case 0: + center = quad[0]; + extent = quad[1]; + case 90: + center = quad[0]; + extent = quad[3]; + break; + case 180: + center = quad[1]; + extent = quad[0]; + break; + case 270: + center = quad[3]; + extent = quad[0]; + break; + } + Tcl_AppendResult(interp, + " << /ShadingType 2 /ColorSpace /DeviceRGB /Extend [true true] ", + NULL); + sprintf(path, "/Coords [%.15g %.15g %.15g %.15g]\n", + quad[0].x, quad[0].y, quad[1].x, quad[1].y); + Tcl_AppendResult(interp, path, NULL); + break; + case ZN_RADIAL_GRADIENT: + /* + * On ne peut pas représenter un dégradé radial ou conique + * anamorphique si on n'inclu pas la transformation dans le + * PostScript résultant. PostScript ne peut décrire que des + * dégradés circulaires. La seule solution rapide est d'utiliser + * comme dans l'item Triangles une trame de triangles (Shading + * type 4). + */ + p.x = p.y = 0; + ZnTransformPoint((ZnTransfo *) quad, &p, ¢er); + p.x = 1.0; + ZnTransformPoint((ZnTransfo *) quad, &p, &extent); + Tcl_AppendResult(interp, + " << /ShadingType 3 /ColorSpace /DeviceRGB /Extend [true true] ", + NULL); + sprintf(path, "/Coords [%.15g %.15g %.15g %.15g %.15g %.15g]\n", + center.x, center.y, 0.0, center.x, center.y, ABS(center.x-extent.x)); + printf("center %g %g, radius %g\n", center.x, center.y, ABS(center.x-extent.x)); + Tcl_AppendResult(interp, path, NULL); + break; + case ZN_CONICAL_GRADIENT: + break; + case ZN_PATH_GRADIENT: + break; + } + + Tcl_AppendResult(interp, " /Function << ", NULL); + Tcl_AppendResult(interp, "/FunctionType 3\n", NULL); + Tcl_AppendResult(interp, " /Domain [0 1] /Bounds [", NULL); + for (i = 1; i < gradient->num_actual_colors-1; i++) { + sprintf(path, "%.4g ", gradient->actual_colors[i].position/100.0); + Tcl_AppendResult(interp, path, NULL); + } + Tcl_AppendResult(interp, "] /Encode [", NULL); + for (i = 0; i < gradient->num_actual_colors-1; i++) { + Tcl_AppendResult(interp, "0 1 ", NULL); + } + Tcl_AppendResult(interp, "]\n /Functions [\n", NULL); + for (i = 0, gc1 = gradient->actual_colors; i < gradient->num_actual_colors-1; i++) { + gc2 = gc1 + 1; + Tcl_AppendResult(interp, " << /FunctionType 2 /Domain [0 1] /N 1 ", NULL); + sprintf(path, "/C0 [%.8g %.8g %.8g] /C1 [%.8g %.8g %.8g] >>\n", + gc1->rgb->red/65535.0, gc1->rgb->green/65535.0, gc1->rgb->blue/65535.0, + gc2->rgb->red/65535.0, gc2->rgb->green/65535.0, gc2->rgb->blue/65535.0); + Tcl_AppendResult(interp, path, NULL); + gc1 = gc2; + } + Tcl_AppendResult(interp, " ] >>\n", NULL); + Tcl_AppendResult(interp, " >> >>\n", NULL); + Tcl_AppendResult(interp, "matrix makepattern setpattern fill\n", NULL); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * TkImageGetColor -- + * + * This procedure converts a pixel value to three floating + * point numbers, representing the amount of red, green, and + * blue in that pixel on the screen. It makes use of colormap + * data passed as an argument, and should work for all Visual + * types. + * + * This implementation is bogus on Windows because the colormap + * data is never filled in. Instead all postscript generated + * data coming through here is expected to be RGB color data. + * To handle lower bit-depth images properly, XQueryColors + * must be implemented for Windows. + * + * Results: + * Returns red, green, and blue color values in the range + * 0 to 1. There are no error returns. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +/* + * The following definition is used in generating postscript for images + * and windows. + */ +typedef struct TkColormapData { /* Hold color information for a window */ + int separated; /* Whether to use separate color bands */ + int color; /* Whether window is color or black/white */ + int ncolors; /* Number of color values stored */ + XColor *colors; /* Pixel value -> RGB mappings */ + int red_mask, green_mask, blue_mask; /* Masks and shifts for each */ + int red_shift, green_shift, blue_shift; /* color band */ +} TkColormapData; + +#ifdef WIN32 +#include + +/* + * We could just define these instead of pulling in windows.h. + #define GetRValue(rgb) ((BYTE)(rgb)) + #define GetGValue(rgb) ((BYTE)(((WORD)(rgb)) >> 8)) + #define GetBValue(rgb) ((BYTE)((rgb)>>16)) +*/ +#else +#define GetRValue(rgb) ((rgb & cdata->red_mask) >> cdata->red_shift) +#define GetGValue(rgb) ((rgb & cdata->green_mask) >> cdata->green_shift) +#define GetBValue(rgb) ((rgb & cdata->blue_mask) >> cdata->blue_shift) +#endif + +#if defined(WIN32) || defined(MAC_OSX_TK) +static void +TkImageGetColor(cdata, pixel, red, green, blue) + TkColormapData *cdata; /* Colormap data */ + unsigned long pixel; /* Pixel value to look up */ + double *red, *green, *blue; /* Color data to return */ +{ + *red = (double) GetRValue(pixel) / 255.0; + *green = (double) GetGValue(pixel) / 255.0; + *blue = (double) GetBValue(pixel) / 255.0; +} +#else +static void +TkImageGetColor(cdata, pixel, red, green, blue) + TkColormapData *cdata; /* Colormap data */ + unsigned long pixel; /* Pixel value to look up */ + double *red, *green, *blue; /* Color data to return */ +{ + if (cdata->separated) { + int r = GetRValue(pixel); + int g = GetGValue(pixel); + int b = GetBValue(pixel); + *red = cdata->colors[r].red / 65535.0; + *green = cdata->colors[g].green / 65535.0; + *blue = cdata->colors[b].blue / 65535.0; + } else { + *red = cdata->colors[pixel].red / 65535.0; + *green = cdata->colors[pixel].green / 65535.0; + *blue = cdata->colors[pixel].blue / 65535.0; + } +} #endif + +/* + *-------------------------------------------------------------- + * + * ZnPostscriptXImage -- + * + * This procedure is called to output the contents of an + * XImage in Postscript, using a format appropriate for the + * current color mode (i.e. one bit per pixel in monochrome, + * one byte per pixel in gray, and three bytes per pixel in + * color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to interp->result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +/* TODO beaucoup de code à partager avec photo ci dessous + * sans compter qu'il faut une autre fonction pour emettre + * du code pour les tiling patterns. + * Il faudrait un operateur central qui emette dans une + * string postscript des bandes d'image afin de respecter + * la taille max des strings (on peut aussi mettre les + * bandes dans un tableau au préalable). Cet opérateur + * gére le niveau de couleur (0, 1, ...) et sait gérer les + * bits de transparence Postscript 3 en option. + */ +int +ZnPostscriptXImage(Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo psInfo, + XImage *ximage, + int x, + int y, + int width, + int height) +{ + TkPostscriptInfo *psi = (TkPostscriptInfo *) psInfo; + char buffer[256]; + int xx, yy, band, maxRows; + double red, green, blue; + int bytesPerLine=0, maxWidth=0; + int level = psi->colorLevel; + Colormap cmap; + int i, ncolors; + Visual *visual; + TkColormapData cdata; + + if (psi->prepass) { + return TCL_OK; + } + + Tcl_AppendResult(interp, "%%%%%% Start of ZnPostscriptXImage\n", NULL); + + cmap = Tk_Colormap(tkwin); + visual = Tk_Visual(tkwin); + + /* + * Obtain information about the colormap, ie the mapping between + * pixel values and RGB values. The code below should work + * for all Visual types. + */ + ncolors = visual->map_entries; + cdata.colors = (XColor *) ckalloc(sizeof(XColor) * ncolors); + cdata.ncolors = ncolors; + + if ((visual->class == DirectColor) || (visual->class == TrueColor)) { + cdata.separated = 1; + cdata.red_mask = visual->red_mask; + cdata.green_mask = visual->green_mask; + cdata.blue_mask = visual->blue_mask; + cdata.red_shift = 0; + cdata.green_shift = 0; + cdata.blue_shift = 0; + while ((0x0001 & (cdata.red_mask >> cdata.red_shift)) == 0) { + cdata.red_shift ++; + } + while ((0x0001 & (cdata.green_mask >> cdata.green_shift)) == 0) { + cdata.green_shift ++; + } + while ((0x0001 & (cdata.blue_mask >> cdata.blue_shift)) == 0) { + cdata.blue_shift ++; + } + for (i = 0; i < ncolors; i ++) { + cdata.colors[i].pixel = ((i << cdata.red_shift) & cdata.red_mask) | + ((i << cdata.green_shift) & cdata.green_mask) | + ((i << cdata.blue_shift) & cdata.blue_mask); + } + } + else { + cdata.separated=0; + for (i = 0; i < ncolors; i ++) { + cdata.colors[i].pixel = i; + } + } + if ((visual->class == StaticGray) || (visual->class == GrayScale)) { + cdata.color = 0; + } + else { + cdata.color = 1; + } + + XQueryColors(Tk_Display(tkwin), cmap, cdata.colors, ncolors); + + /* + * Figure out which color level to use (possibly lower than the + * one specified by the user). For example, if the user specifies + * color with monochrome screen, use gray or monochrome mode instead. + */ + + if (!cdata.color && level == 2) { + level = 1; + } + if (!cdata.color && cdata.ncolors == 2) { + level = 0; + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + switch (level) { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, "Can't generate Postscript for images more than %d pixels wide", maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + ckfree((char *) cdata.colors); + return TCL_ERROR; + } + + maxRows = 60000 / bytesPerLine; + + for (band = height-1; band >= 0; band -= maxRows) { + int rows = (band >= maxRows) ? maxRows : band + 1; + int lineLen = 0; + switch (level) { + case 0: + sprintf(buffer, "%d %d 1 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 1: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + case 2: + sprintf(buffer, "%d %d 8 matrix {\n<", width, rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + break; + } + for (yy = band; yy > band - rows; yy--) { + switch (level) { + case 0: + { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + */ + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = x; xx< x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + if (0.30 * red + 0.59 * green + 0.11 * blue > 0.5) + data |= mask; + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: + { + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + for (xx = x; xx < x+width; xx ++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X", (int) floor(0.5 + 255.0 * + (0.30 * red + 0.59 * green + 0.11 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + case 2: + { + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + for (xx = x; xx < x+width; xx++) { + TkImageGetColor(&cdata, XGetPixel(ximage, xx, yy), + &red, &green, &blue); + sprintf(buffer, "%02X%02X%02X", + (int) floor(0.5 + 255.0 * red), + (int) floor(0.5 + 255.0 * green), + (int) floor(0.5 + 255.0 * blue)); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen > 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + switch (level) { + case 0: sprintf(buffer, ">\n} image\n"); break; + case 1: sprintf(buffer, ">\n} image\n"); break; + case 2: sprintf(buffer, ">\n} false 3 colorimage\n"); break; + } + Tcl_AppendResult(interp, buffer, (char *) NULL); + sprintf(buffer, "0 %d translate\n", rows); + Tcl_AppendResult(interp, buffer, (char *) NULL); + } + ckfree((char *) cdata.colors); + + Tcl_AppendResult(interp, "%%%%%% End of ZnPostscriptXImage\n", NULL); + + return TCL_OK; +} + +/* + *-------------------------------------------------------------- + * + * ZnPostscriptPhoto -- + * + * This procedure is called to output the contents of a + * photo image in Postscript, using a format appropriate for + * the requested postscript color mode (i.e. one byte per pixel + * in gray, and three bytes per pixel in color). + * + * Results: + * Returns a standard Tcl return value. If an error occurs + * then an error message will be left in interp->result. + * If no error occurs, then additional Postscript will be + * appended to the interpreter's result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ +int +ZnPostscriptPhoto(Tcl_Interp *interp, + Tk_PhotoImageBlock *blockPtr, + Tk_PostscriptInfo ps_info, + int width, + int height) +{ + TkPostscriptInfo *psi = (TkPostscriptInfo *) ps_info; + static int codeIncluded = 0; + unsigned char *pixelPtr; + char buffer[256], cspace[40], decode[40]; + int bpc; + int xx, yy, lineLen; + float red, green, blue; + int alpha; + int bytesPerLine=0, maxWidth=0; + unsigned char opaque = 255; + unsigned char *alphaPtr; + int alphaOffset, alphaPitch, alphaIncr; + + if (psi->prepass) { + codeIncluded = 0; + return TCL_OK; + } + + /* + * Define the "TkPhoto" function, which is a modified version + * of the original "transparentimage" function posted + * by ian@five-d.com (Ian Kemmish) to comp.lang.postscript. + * For a monochrome colorLevel this is a slightly different + * version that uses the imagemask command instead of image. + */ + if( !codeIncluded && (psi->colorLevel != 0) ) { + /* + * Color and gray-scale code. + */ + codeIncluded = !0; + Tcl_AppendResult(interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /tinteger exch def \n", + " /transparent 1 string def \n", + " transparent 0 tinteger put \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /crpp newdict /Decode get length 2 idiv def \n", + " /str w string def \n", + " /pix w crpp mul string def \n", + " /substrlen 2 w log 2 log div floor exp cvi def \n", + " /substrs [ \n", + " { \n", + " substrlen string \n", + " 0 1 substrlen 1 sub { \n", + " 1 index exch tinteger put \n", + " } for \n", + " /substrlen substrlen 2 idiv def \n", + " substrlen 0 eq {exit} if \n", + " } loop \n", + " ] def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " olddict /DataSource get str readstring pop pop \n", + " /tail str def \n", + " /x 0 def \n", + " olddict /DataSource get pix readstring pop pop \n", + " { \n", + " tail transparent search dup /done exch not def \n", + " {exch pop exch pop} if \n", + " /w1 exch length def \n", + " w1 0 ne { \n", + " newdict /DataSource ", + " pix x crpp mul w1 crpp mul getinterval put \n", + " newdict /Width w1 put \n", + " mat 4 x neg put \n", + " /x x w1 add def \n", + " newdict image \n", + " /tail tail w1 tail length w1 sub getinterval def \n", + " } if \n", + " done {exit} if \n", + " tail substrs { \n", + " anchorsearch {pop} if \n", + " } forall \n", + " /tail exch def \n", + " tail length 0 eq {exit} if \n", + " /x w tail length sub def \n", + " } loop \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } + else if (!codeIncluded && (psi->colorLevel == 0)) { + /* + * Monochrome-only code + */ + codeIncluded = !0; + Tcl_AppendResult(interp, + "/TkPhoto { \n", + " gsave \n", + " 32 dict begin \n", + " /dummyInteger exch def \n", + " /olddict exch def \n", + " olddict /DataSource get dup type /filetype ne { \n", + " olddict /DataSource 3 -1 roll \n", + " 0 () /SubFileDecode filter put \n", + " } { \n", + " pop \n", + " } ifelse \n", + " /newdict olddict maxlength dict def \n", + " olddict newdict copy pop \n", + " /w newdict /Width get def \n", + " /pix w 7 add 8 idiv string def \n", + " /h newdict /Height get def \n", + " 1 w div 1 h div matrix scale \n", + " olddict /ImageMatrix get exch matrix concatmatrix \n", + " matrix invertmatrix concat \n", + " newdict /Height 1 put \n", + " newdict /DataSource pix put \n", + " /mat [w 0 0 h 0 0] def \n", + " newdict /ImageMatrix mat put \n", + " 0 1 h 1 sub { \n", + " mat 5 3 -1 roll neg put \n", + " 0.000 0.000 0.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " 1.000 1.000 1.000 setrgbcolor \n", + " olddict /DataSource get pix readstring pop pop \n", + " newdict /DataSource pix put \n", + " newdict imagemask \n", + " } for \n", + " end \n", + " grestore \n", + "} bind def \n\n\n", (char *) NULL); + } + + /* + * Check that at least one row of the image can be represented + * with a string less than 64 KB long (this is a limit in the + * Postscript interpreter). + */ + switch (psi->colorLevel) + { + case 0: bytesPerLine = (width + 7) / 8; maxWidth = 240000; break; + case 1: bytesPerLine = width; maxWidth = 60000; break; + case 2: bytesPerLine = 3 * width; maxWidth = 20000; break; + } + if (bytesPerLine > 60000) { + Tcl_ResetResult(interp); + sprintf(buffer, "Can't generate Postscript for images more than %d pixels wide", + maxWidth); + Tcl_AppendResult(interp, buffer, (char *) NULL); + return TCL_ERROR; + } + + /* + * Set up the postscript code except for the image-data stream. + */ + switch (psi->colorLevel) { + case 0: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[1 0]"); + bpc = 1; + break; + case 1: + strcpy( cspace, "/DeviceGray"); + strcpy( decode, "[0 1]"); + bpc = 8; + break; + default: + strcpy( cspace, "/DeviceRGB"); + strcpy( decode, "[0 1 0 1 0 1]"); + bpc = 8; + break; + } + + Tcl_AppendResult(interp, cspace, " setcolorspace\n\n", (char *) NULL); + sprintf(buffer, " /Width %d\n /Height %d\n /BitsPerComponent %d\n", + width, height, bpc); + Tcl_AppendResult(interp, + "<<\n /ImageType 1\n", buffer, + " /DataSource currentfile /ASCIIHexDecode filter\n", (char *) NULL); + sprintf(buffer, " /ImageMatrix [1 0 0 -1 0 %d]\n", height); + Tcl_AppendResult(interp, buffer, " /Decode ", decode, "\n>>\n1 TkPhoto\n", (char *) NULL); + + /* + * Check the PhotoImageBlock information. + * We assume that: + * if pixelSize is 1,2 or 4, the image is R,G,B,A; + * if pixelSize is 3, the image is R,G,B and offset[3] is bogus. + */ + if (blockPtr->pixelSize == 3) { + /* + * No alpha information: the whole image is opaque. + */ + alphaPtr = &opaque; + alphaPitch = alphaIncr = alphaOffset = 0; + } + else { + /* + * Set up alpha handling. + */ + alphaPtr = blockPtr->pixelPtr; + alphaPitch = blockPtr->pitch; + alphaIncr = blockPtr->pixelSize; + alphaOffset = blockPtr->offset[3]; + } + + for (yy = 0, lineLen=0; yy < height; yy++) { + switch (psi->colorLevel) { + case 0: + { + /* + * Generate data for image in monochrome mode. + * No attempt at dithering is made--instead, just + * set a threshold. + * To handle transparencies we need to output two lines: + * one for the black pixels, one for the white ones. + */ + unsigned char mask=0x80; + unsigned char data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + (yy * blockPtr->pitch) + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is less than threshold, then it is black. + */ + if ((alpha != 0) && (0.3086 * red + 0.6094 * green + 0.082 * blue < 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + + mask=0x80; + data=0x00; + for (xx = 0; xx< width; xx ++) { + pixelPtr = blockPtr->pixelPtr + (yy * blockPtr->pitch) + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + alpha = *(alphaPtr + (yy * alphaPitch) + (xx * alphaIncr) + alphaOffset); + + /* + * If pixel is greater than threshold, then it is white. + */ + if ((alpha != 0) && (0.3086 * red + 0.6094 * green + 0.082 * blue >= 128)) { + data |= mask; + } + mask >>= 1; + if (mask == 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + mask=0x80; + data=0x00; + } + } + if ((width % 8) != 0) { + sprintf(buffer, "%02X", data); + Tcl_AppendResult(interp, buffer, (char *) NULL); + mask=0x80; + data=0x00; + } + break; + } + case 1: + { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + /* + * Generate data in gray mode--in this case, take a + * weighted sum of the red, green, and blue values. + */ + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + (yy * blockPtr->pitch) + (xx *blockPtr->pixelSize); + + red = pixelPtr[blockPtr->offset[0]]; + green = pixelPtr[blockPtr->offset[1]]; + blue = pixelPtr[blockPtr->offset[2]]; + + sprintf(buffer, "%02X", + (int) floor(0.5 + ( 0.3086 * red + 0.6094 * green + 0.0820 * blue))); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + default: + { + /* + * Generate transparency data. + * We must prevent a transparent value of 0 + * because of a bug in some HP printers. + */ + for (xx = 0; xx < width; xx ++) { + alpha = *(alphaPtr + (yy * alphaPitch) + (xx * alphaIncr) + alphaOffset); + sprintf(buffer, "%02X", alpha | 0x01); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 2; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + + /* + * Finally, color mode. Here, just output the red, green, + * and blue values directly. + */ + for (xx = 0; xx < width; xx ++) { + pixelPtr = blockPtr->pixelPtr + (yy * blockPtr->pitch) + (xx *blockPtr->pixelSize); + + sprintf(buffer, "%02X%02X%02X", pixelPtr[blockPtr->offset[0]], + pixelPtr[blockPtr->offset[1]], pixelPtr[blockPtr->offset[2]]); + Tcl_AppendResult(interp, buffer, (char *) NULL); + lineLen += 6; + if (lineLen >= 60) { + lineLen = 0; + Tcl_AppendResult(interp, "\n", (char *) NULL); + } + } + break; + } + } + } + + Tcl_AppendResult(interp, ">\n", (char *) NULL); + return TCL_OK; +} + +int +ZnPostscriptImage(Tcl_Interp *interp, + Tk_Window tkwin, + Tk_PostscriptInfo ps_info, + ZnImage image, + int x, + int y, + int w, + int h) +{ + int result; + XImage *ximage; + Tk_PhotoHandle tkphoto; + + if (((TkPostscriptInfo *) ps_info)->prepass) { + return TCL_OK; + } + + tkphoto = ZnImageTkPhoto(image); + if (tkphoto != NULL) { + Tk_PhotoImageBlock block; + + Tk_PhotoGetImage(tkphoto, &block); + block.pixelPtr += y * block.pitch + x * block.pixelSize; + + return ZnPostscriptPhoto(interp, &block, ps_info, w, h); + } + else { + Pixmap pix = ZnImagePixmap(image, tkwin); + XGCValues values; + GC gc; + + if (pix == None) { + /* + * Pixmap not cached (probably working under GL). + * Create a temporary pixmap. + */ + pix = Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin), w, h, Tk_Depth(tkwin)); + values.foreground = WhitePixelOfScreen(Tk_Screen(tkwin)); + gc = Tk_GetGC(tkwin, GCForeground, &values); + if (gc != None) { + XFillRectangle(Tk_Display(tkwin), pix, gc, 0, 0, (unsigned int) w, (unsigned int) h); + Tk_FreeGC(Tk_Display(tkwin), gc); + } + Tk_RedrawImage(image, x, y, w, h, pix, 0, 0); + Tk_FreePixmap(Tk_Display(tkwin), pix); + } + else { + ximage = XGetImage(Tk_Display(tkwin), pix, 0, 0, + (unsigned int) w, (unsigned int) h, AllPlanes, ZPixmap); + } + if (ximage == NULL) { + /* The XGetImage() function is apparently not + * implemented on this system. Just ignore it. + */ + return TCL_OK; + } + result = ZnPostscriptXImage(interp, tkwin, ps_info, ximage, x, y, w, h); + XDestroyImage(ximage); + } + + return result; +} + +void +EmitPhotoImageData() +{ +} + + +/* + * TODO gradients, tuiles, reliefs, flêches, clipping. + * TODO la fonction DrawText est buggée dans un environnement rotation + * l'erreur passe par un max autour de modulo 45° + * TODO Bugs de placement sur le texte et les bordures des fields + * TODO Problème : Si on utilise les transformations PostScript on + * génère un code plus concis et le rendu est potentiellement + * plus beau (on utilise les arcs et les beziers natifs) et on + * peut générer des dégradés identiques à ceux de zinc mais le + * tuilage/stencil, les flêches, l'épaisseur des lignes suivent + * la transformation. + * TODO Le code gérant les images ne sait pas traiter le canal alpha. + * TODO Inclure ici le code de gestion des stipples. + * TODO Pour images et stipples le code doit prendre en compte le contexte + * X et/ou OpenGL. + */ diff --git a/generic/PostScript.h b/generic/PostScript.h index cca589c..5af987e 100644 --- a/generic/PostScript.h +++ b/generic/PostScript.h @@ -23,15 +23,35 @@ #include "List.h" #include "Types.h" #include "Geo.h" +#include "Color.h" +#include "Image.h" #include #include struct _ZnWInfo; +struct _ZnItemStruct; int ZnPostScriptCmd(struct _ZnWInfo *wi, int argc, Tcl_Obj *CONST *args); - - -#endif /* _PostScript_h */ +void ZnFlushPsChan(Tcl_Interp *interp, Tk_PostscriptInfo ps_info); +int ZnPostscriptOutline(Tcl_Interp *interp, Tk_PostscriptInfo ps_info, + Tk_Window tkwin, ZnDim line_width, ZnLineStyle line_style, + ZnGradient *line_color, ZnImage line_pattern); +int ZnPostscriptBitmap(Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo ps_info, + ZnImage bitmap, ZnReal x, ZnReal y, int width, int height); +void ZnPostscriptString(Tcl_Interp *interp, char *str, int num_bytes); +void ZnPostscriptTrace(struct _ZnItemStruct *item, ZnBool enter); +int ZnPostscriptGradient(Tcl_Interp *interp, Tk_PostscriptInfo ps_info, + ZnGradient *gradient, ZnPoint *quad, ZnPoly *poly); +int ZnPostscriptXImage(Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo psInfo, + XImage *ximage, int x, int y, int width, int height); +int ZnPostscriptStipple(Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo ps_info, + ZnImage bitmap); +int ZnPostscriptTile(Tcl_Interp *interp, Tk_Window win, Tk_PostscriptInfo ps_info, + ZnImage image); +int ZnPostscriptImage(Tcl_Interp *interp, Tk_Window tkwin, Tk_PostscriptInfo ps_info, + ZnImage image, int x, int y, int width, int height); + +#endif /* _PostScript_h */ diff --git a/generic/Rectangle.c b/generic/Rectangle.c index 7cf4f8d..8afb38f 100644 --- a/generic/Rectangle.c +++ b/generic/Rectangle.c @@ -753,10 +753,87 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ZnWInfo *wi = item->wi; + RectangleItem rect = (RectangleItem) item; + char path[500]; + + if (ISCLEAR(rect->flags, FILLED_BIT) && (rect->line_width == 0)) { + return TCL_OK; + } + + /* + * Create the rectangle path. + */ + sprintf(path, "%.15g %.15g moveto %.15g %.15g lineto %.15g %.15g lineto %.15g %.15g lineto closepath\n", + rect->dev[0].x, rect->dev[0].y, rect->dev[1].x, rect->dev[1].y, + rect->dev[2].x, rect->dev[2].y, rect->dev[3].x, rect->dev[3].y); + Tcl_AppendResult(wi->interp, path, NULL); + + /* + * Emit code to draw the filled area. + */ + if (ISSET(rect->flags, FILLED_BIT)) { + if (rect->line_width) { + Tcl_AppendResult(wi->interp, "gsave\n", NULL); + } + if (!ZnGradientFlat(rect->fill_color)) { + if (ZnPostscriptGradient(wi->interp, wi->ps_info, rect->fill_color, + rect->grad_geo ? rect->grad_geo : rect->dev, NULL) != TCL_OK) { + return TCL_ERROR; + } + } + else if (rect->tile != ZnUnspecifiedImage) { + if (!ZnImageIsBitmap(rect->tile)) { /* Fill tiled */ + if (ZnPostscriptTile(wi->interp, wi->win, wi->ps_info, rect->tile) != TCL_OK) { + return TCL_ERROR; + } + } + else { /* Fill stippled */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(rect->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "clip ", NULL); + if (ZnPostscriptStipple(wi->interp, wi->win, wi->ps_info, rect->tile) != TCL_OK) { + return TCL_ERROR; + } + } + } + else { /* Fill solid */ + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(rect->fill_color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + Tcl_AppendResult(wi->interp, "fill\n", NULL); + } + if (rect->line_width) { + Tcl_AppendResult(wi->interp, "grestore\n", NULL); + } + } + + /* + * Then emit code code to stroke the outline. + */ + if (rect->line_width) { + if (rect->relief != ZN_RELIEF_FLAT) { + /* TODO No support yet */ + } + else { + Tcl_AppendResult(wi->interp, "0 setlinejoin 2 setlinecap\n", NULL); + if (ZnPostscriptOutline(wi->interp, wi->ps_info, wi->win, + rect->line_width, rect->line_style, + rect->line_color, rect->line_pattern) != TCL_OK) { + return TCL_ERROR; + } + } + } + + return TCL_OK; } diff --git a/generic/Reticle.c b/generic/Reticle.c index e9c811c..cebeb98 100644 --- a/generic/Reticle.c +++ b/generic/Reticle.c @@ -568,10 +568,12 @@ Coords(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + return TCL_OK; } diff --git a/generic/Tabular.c b/generic/Tabular.c index be61e88..c0d9886 100644 --- a/generic/Tabular.c +++ b/generic/Tabular.c @@ -399,10 +399,12 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + return ZnFIELD.PostScriptFields(&((TabularItem) item)->field_set, prepass, area); } diff --git a/generic/Text.c b/generic/Text.c index 5bf885f..bc7c843 100644 --- a/generic/Text.c +++ b/generic/Text.c @@ -1354,10 +1354,76 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ZnWInfo *wi = item->wi; + TextItem text = (TextItem) item; + Tk_FontMetrics fm; + TextLineInfo lines, lines_ptr; + ZnPoint origin; + ZnReal alignment; + int i, num_lines; + char path[150]; + + lines = (TextLineInfo) ZnListArray(text->text_info); + num_lines = ZnListSize(text->text_info); + + if (Tk_PostscriptFont(wi->interp, wi->ps_info, text->font) != TCL_OK) { + return TCL_ERROR; + } + if (Tk_PostscriptColor(wi->interp, wi->ps_info, + ZnGetGradientColor(text->color, 0.0, NULL)) != TCL_OK) { + return TCL_ERROR; + } + if (text->fill_pattern != ZnUnspecifiedImage) { + Tcl_AppendResult(wi->interp, "/StippleText {\n ", NULL); + Tk_PostscriptStipple(wi->interp, wi->win, wi->ps_info, + ZnImagePixmap(text->fill_pattern, wi->win)); + Tcl_AppendResult(wi->interp, "} bind def\n", NULL); + } + + ComputeTransfoAndOrigin(item, &origin); + + sprintf(path, "/InitialTransform load setmatrix\n" + "[%.15g %.15g %.15g %.15g %.15g %.15g] concat\n" + "1 -1 scale\n", + wi->current_transfo->_[0][0], wi->current_transfo->_[0][1], + wi->current_transfo->_[1][0], wi->current_transfo->_[1][1], + wi->current_transfo->_[2][0], wi->current_transfo->_[2][1]); + Tcl_AppendResult(wi->interp, path, NULL); + + sprintf(path, "%.15g %.15g [\n", origin.x, origin.y); + Tcl_AppendResult(wi->interp, path, NULL); + + /* + * Emit code to draw the lines. + */ + for (i = 0, lines_ptr = lines; i < num_lines; i++, lines_ptr++) { + ZnPostscriptString(wi->interp, lines_ptr->start, lines_ptr->num_bytes); + } + + switch (text->alignment) { + default: + case TK_JUSTIFY_LEFT: + alignment = 0; + break; + case TK_JUSTIFY_CENTER: + alignment = 0.5; + break; + case TK_JUSTIFY_RIGHT: + alignment = 1; + break; + } + Tk_GetFontMetrics(text->font, &fm); + /* DrawText should not mess with anchors, they are already accounted for */ + sprintf(path, "] %d %g %g %g %s DrawText\n", fm.linespace, 0.0, 0.0, + alignment, (text->fill_pattern == ZnUnspecifiedImage) ? "false" : "true"); + Tcl_AppendResult(wi->interp, path, NULL); + + return TCL_OK; } diff --git a/generic/Track.c b/generic/Track.c index b1aaf40..63686c4 100644 --- a/generic/Track.c +++ b/generic/Track.c @@ -1767,10 +1767,12 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + return TCL_OK; } diff --git a/generic/Triangles.c b/generic/Triangles.c index 4b3b8bb..1565b5b 100644 --- a/generic/Triangles.c +++ b/generic/Triangles.c @@ -573,10 +573,62 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) { + ZnWInfo *wi = item->wi; + TrianglesItem tr = (TrianglesItem) item; + ZnPoint *points; + int i, num_points, last_color_index; + int edge; + ZnGradient **grads; + XColor *color = NULL; + double red, green, blue; + ZnBBox bbox; + char path[150]; + + points = tr->dev_points.strips->points; + num_points = tr->dev_points.strips->num_points; + ZnResetBBox(&bbox); + ZnAddPointsToBBox(&bbox, points, num_points); + + grads = ZnListArray(tr->colors); + last_color_index = ZnListSize(tr->colors)-1; + + Tcl_AppendResult(wi->interp, + "/ShadingDict <<\n /ShadingType 4\n /ColorSpace /DeviceRGB\n", + " /DataSource [", NULL); + for (i = 0; i < num_points; i++) { + if (i <= last_color_index) { + color = ZnGetGradientColor(grads[i], 0.0, NULL); + } + if (i < 3) { + edge = 0; + } + else if (ISCLEAR(tr->flags, FAN_BIT)) { + edge = 1; + } + else { + edge = 2; + } + red = ((double) (color->red >> 8)) / 255.0; + green = ((double) (color->green >> 8)) / 255.0; + blue = ((double) (color->blue >> 8)) / 255.0; + + sprintf(path, "%d %.15g %.15g %.4g %.4g %.4g ", + edge, points[i].x, points[i].y, red, green, blue); + Tcl_AppendResult(wi->interp, path, NULL); + } + Tcl_AppendResult(wi->interp, "]\n>> def\n", NULL); + Tcl_AppendResult(wi->interp, "<<\n /PatternType 2\n /Shading ShadingDict\n>>\n", NULL); + Tcl_AppendResult(wi->interp, "matrix identmatrix makepattern setpattern\n", NULL); + sprintf(path, "%.15g %.15g %.15g %.15g rectfill\n", bbox.orig.x, bbox.orig.y, + bbox.corner.x - bbox.orig.x, bbox.corner.y - bbox.orig.y); + Tcl_AppendResult(wi->interp, path, NULL); + + return TCL_OK; } diff --git a/generic/WidgetInfo.h b/generic/WidgetInfo.h index 2ef78a8..8483dca 100644 --- a/generic/WidgetInfo.h +++ b/generic/WidgetInfo.h @@ -233,16 +233,17 @@ typedef struct _ZnWInfo { * viewing area past the scroll region. */ Tcl_Obj *region; /* Scroll region option string source of the * scroll_region above. */ + Tk_PostscriptInfo ps_info; /* Perf measurement variables. */ #ifndef _WIN32 ZnChrono this_draw_chrono; ZnChrono total_draw_chrono; - void *ps_info; #endif int num_items; int damaged_area_w; int damaged_area_h; + int debug; } ZnWInfo; diff --git a/generic/Window.c b/generic/Window.c index 4486af9..de12103 100644 --- a/generic/Window.c +++ b/generic/Window.c @@ -321,6 +321,54 @@ Query(ZnItem item, return TCL_OK; } +/* + * Compute the transformation to be used and the origin + * of the window (upper left point in item coordinates). + */ +static ZnTransfo * +ComputeTransfoAndOrigin(ZnItem item, + ZnPoint *origin) +{ + WindowItem wind = (WindowItem) item; + ZnTransfo *t; + + /* + * The connected item support anchors, this is checked by configure. + */ + if (item->connected_item != ZN_NO_ITEM) { + ZnTransfo inv; + + item->connected_item->class->GetAnchor(item->connected_item, + wind->connection_anchor, + origin); + + /* GetAnchor return a position in device coordinates not in + * the item coordinate space. To compute the icon origin + * (upper left corner), we must apply the inverse transform + * to the ref point before calling anchor2origin. + */ + ZnTransfoInvert(item->transfo, &inv); + ZnTransformPoint(&inv, origin, origin); + /* + * The relevant transform in case of an attachment is the item + * transform alone. This is case of local coordinate space where + * only the translation is a function of the whole transform + * stack, scale and rotation are reset. + */ + t = item->transfo; + } + else { + origin->x = origin->y = 0; + t = item->wi->current_transfo; + } + + ZnAnchor2Origin(origin, (ZnReal) wind->real_width, (ZnReal) wind->real_height, + wind->anchor, origin); + //origin->x = ZnNearestInt(origin->x); + //origin->y = ZnNearestInt(origin->y); + + return t; +} /* ********************************************************************************** @@ -333,8 +381,10 @@ static void ComputeCoordinates(ZnItem item, ZnBool force) { - ZnWInfo *wi = item->wi; - WindowItem wind = (WindowItem) item; + ZnWInfo *wi = item->wi; + WindowItem wind = (WindowItem) item; + ZnPoint origin; + ZnTransfo *t; ZnResetBBox(&item->item_bounding_box); @@ -357,23 +407,8 @@ ComputeCoordinates(ZnItem item, } } - /* - * The connected item support anchors, this is checked by - * configure. - */ - if (item->connected_item != ZN_NO_ITEM) { - item->connected_item->class->GetAnchor(item->connected_item, - wind->connection_anchor, - &wind->pos_dev); - } - else { - ZnPoint pos; - pos.x = pos.y = 0.0; - ZnTransformPoint(wi->current_transfo, &pos, &wind->pos_dev); - } - - ZnAnchor2Origin(&wind->pos_dev, (ZnReal) wind->real_width, (ZnReal) wind->real_height, - wind->anchor, &wind->pos_dev); + t = ComputeTransfoAndOrigin(item, &origin); + ZnTransformPoint(wi->current_transfo, &origin, &wind->pos_dev); wind->pos_dev.x = ZnNearestInt(wind->pos_dev.x); wind->pos_dev.y = ZnNearestInt(wind->pos_dev.y); @@ -533,10 +568,100 @@ Pick(ZnItem item, * ********************************************************************************** */ -static void -PostScript(ZnItem item, - ZnBool prepass) +#ifdef X_GetImage +static int +xerrorhandler(ClientData client_data, + XErrorEvent *e) { + return 0; +} +#endif + +static int +PostScript(ZnItem item, + ZnBool prepass, + ZnBBox *area) +{ + ZnWInfo *wi = item->wi; + WindowItem wind = (WindowItem) item; + char path[256]; + XImage *ximage; + int result; + ZnPoint origin; + Tcl_DString buffer1, buffer2; +#ifdef X_GetImage + Tk_ErrorHandler handle; +#endif + + sprintf(path, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", + Tk_Class(wind->win), Tk_PathName(wind->win), wind->real_width, wind->real_height, + wind->pos_dev.x, wind->pos_dev.y); + Tcl_AppendResult(wi->interp, path, NULL); + + ComputeTransfoAndOrigin(item, &origin); + + sprintf(path, "/InitialTransform load setmatrix\n" + "%.15g %.15g translate\n" + "1 -1 scale\n", + wind->pos_dev.x, wind->pos_dev.y + wind->real_height); + Tcl_AppendResult(wi->interp, path, NULL); + + /* first try if the widget has its own "postscript" command. If it + * exists, this will produce much better postscript than + * when a pixmap is used. + */ + Tcl_DStringInit(&buffer1); + Tcl_DStringInit(&buffer2); + Tcl_DStringGetResult(wi->interp, &buffer2); + sprintf(path, "%s postscript -prolog 0\n", Tk_PathName(wind->win)); + result = Tcl_Eval(wi->interp, path); + Tcl_DStringGetResult(wi->interp, &buffer1); + Tcl_DStringResult(wi->interp, &buffer2); + Tcl_DStringFree(&buffer2); + + if (result == TCL_OK) { + Tcl_AppendResult(wi->interp, "50 dict begin\nsave\ngsave\n", NULL); + sprintf (path, "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", + wind->real_height, wind->real_width, wind->real_height, wind->real_width); + Tcl_AppendResult(wi->interp, path, NULL); + Tcl_AppendResult(wi->interp, " 0 rlineto closepath\n", + "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", + Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", NULL); + Tcl_DStringFree(&buffer1); + + return result; + } + Tcl_DStringFree(&buffer1); + + /* + * If the window is off the screen it will generate an BadMatch/XError + * We catch any BadMatch errors here + */ +#ifdef X_GetImage + handle = Tk_CreateErrorHandler(wi->dpy, BadMatch, X_GetImage, -1, + xerrorhandler, (ClientData) wind->win); +#endif + + /* + * Generate an XImage from the window. We can then read pixel + * values out of the XImage. + */ + ximage = XGetImage(wi->dpy, Tk_WindowId(wind->win), 0, 0, (unsigned int) wind->real_width, + (unsigned int) wind->real_height, AllPlanes, ZPixmap); + +#ifdef X_GetImage + Tk_DeleteErrorHandler(handle); +#endif + + if (ximage == NULL) { + return TCL_OK; + } + + result = ZnPostscriptXImage(wi->interp, wind->win, wi->ps_info, ximage, + 0, 0, wind->real_width, wind->real_height); + XDestroyImage(ximage); + + return result; } diff --git a/generic/tkZinc.c b/generic/tkZinc.c index c7af899..6e6c87b 100644 --- a/generic/tkZinc.c +++ b/generic/tkZinc.c @@ -289,6 +289,7 @@ static Tk_ObjCustomOption gradientOption = { #define CONFIG_MAP_SYMBOL 1<<15 #define CONFIG_TRACK_SYMBOL 1<<16 #define CONFIG_TILE 1<<17 +#define CONFIG_DEBUG 1<<18 #endif /* @@ -400,6 +401,8 @@ static Tk_OptionSpec option_specs[] = { "1", -1, Tk_Offset(ZnWInfo, confine), 0, NULL, CONFIG_SET_ORIGIN}, {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor", "", -1, Tk_Offset(ZnWInfo, cursor), TK_CONFIG_NULL_OK, NULL, 0}, + {TK_OPTION_INT, "-debug", "debug", "Debug", + "0", -1, Tk_Offset(ZnWInfo, debug), 0, NULL, 0}, {TK_OPTION_FONT, "-font", "font", "Font", "-adobe-helvetica-bold-r-normal--*-120-*-*-*-*-*-*", -1, Tk_Offset(ZnWInfo, font), 0, NULL, CONFIG_FONT}, @@ -5414,11 +5417,9 @@ WidgetObjCmd(ClientData client_data, /* Information about the widget. */ case ZN_W_POSTSCRIPT: { -#if 0 if (ZnPostScriptCmd(wi, argc, args) != TCL_OK) { goto error; } -#endif } break; /* -- cgit v1.1