2 * (GLABELS) Label and Business Card Creation program for GNOME
4 * print.c: Print module
6 * Copyright (C) 2001 Jim Evins <evins@snaught.com>.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "label-text.h"
32 #include "label-box.h"
33 #include "label-line.h"
34 #include "label-ellipse.h"
35 #include "label-image.h"
36 #include "label-barcode.h"
38 #include <libglabels/template.h>
43 #define ARC_FINE 2 /* Resolution in degrees of large arcs */
44 #define ARC_COURSE 5 /* Resolution in degrees of small arcs */
46 #define TICK_OFFSET 2.25
47 #define TICK_LENGTH 18.0
49 /*=========================================================================*/
51 /*=========================================================================*/
53 typedef struct _PrintInfo {
54 /* gnome print context */
55 GnomePrintContext *pc;
57 /* gnome print configuration */
58 GnomePrintConfig *config;
60 /* gLabels Template */
62 gboolean label_rotate_flag;
73 /*=========================================================================*/
74 /* Private function prototypes. */
75 /*=========================================================================*/
76 static PrintInfo *print_info_new (GnomePrintJob *job,
79 static void print_info_free (PrintInfo **pi);
82 static void print_page_begin (PrintInfo *pi);
84 static void print_page_end (PrintInfo *pi);
86 static void print_crop_marks (PrintInfo *pi);
88 static void print_label (PrintInfo *pi,
92 glMergeRecord *record,
93 gboolean outline_flag,
94 gboolean reverse_flag);
97 static void draw_label (PrintInfo *pi,
99 glMergeRecord *record);
102 static void draw_object (PrintInfo *pi,
103 glLabelObject *object,
104 glMergeRecord *record);
106 static void draw_text_object (PrintInfo *pi,
108 glMergeRecord *record);
110 static void draw_box_object (PrintInfo *pi,
112 glMergeRecord *record);
114 static void draw_line_object (PrintInfo *pi,
116 glMergeRecord *record);
118 static void draw_ellipse_object (PrintInfo *pi,
119 glLabelEllipse *object,
120 glMergeRecord *record);
122 static void draw_image_object (PrintInfo *pi,
123 glLabelImage *object,
124 glMergeRecord *record);
126 static void draw_barcode_object (PrintInfo *pi,
127 glLabelBarcode *object,
128 glMergeRecord *record);
131 static void draw_outline (PrintInfo *pi,
134 static void clip_to_outline (PrintInfo *pi,
137 static void clip_punchouts (PrintInfo *pi,
141 static void create_rectangle_path (GnomePrintContext *pc,
147 static void create_ellipse_path (GnomePrintContext *pc,
153 static void create_rounded_rectangle_path (GnomePrintContext *pc,
160 static void create_clipped_circle_path (GnomePrintContext *pc,
167 #ifndef NO_ALPHA_HACK
168 static guchar * get_pixels_as_rgb (const GdkPixbuf *pixbuf);
172 /*****************************************************************************/
173 /* Simple (no merge data) print command. */
174 /*****************************************************************************/
176 gl_print_simple (GnomePrintJob *job,
184 const glTemplateLabelType *label_type;
185 gint i_sheet, i_label;
186 glTemplateOrigin *origins;
188 gl_debug (DEBUG_PRINT, "START");
190 pi = print_info_new (job, label);
191 label_type = gl_template_get_first_label_type (pi->template);
193 origins = gl_template_get_origins (label_type);
195 for (i_sheet = 0; i_sheet < n_sheets; i_sheet++) {
197 print_page_begin (pi);
198 if (flags->crop_marks) {
199 print_crop_marks (pi);
202 for (i_label = first - 1; i_label < last; i_label++) {
204 print_label (pi, label,
205 origins[i_label].x, origins[i_label].y,
206 NULL, flags->outline, flags->reverse);
215 print_info_free (&pi);
217 gl_debug (DEBUG_PRINT, "END");
220 /*****************************************************************************/
221 /* Merge print command (collated copies) */
222 /*****************************************************************************/
224 gl_print_merge_collated (GnomePrintJob *job,
231 const GList *record_list;
233 const glTemplateLabelType *label_type;
234 gint i_sheet, i_label, n_labels_per_page, i_copy;
235 glMergeRecord *record;
237 glTemplateOrigin *origins;
239 gl_debug (DEBUG_PRINT, "START");
241 merge = gl_label_get_merge (label);
242 record_list = gl_merge_get_record_list (merge);
244 pi = print_info_new (job, label);
245 label_type = gl_template_get_first_label_type (pi->template);
247 n_labels_per_page = gl_template_get_n_labels (label_type);
248 origins = gl_template_get_origins (label_type);
253 for ( p=(GList *)record_list; p!=NULL; p=p->next ) {
254 record = (glMergeRecord *)p->data;
256 if ( record->select_flag ) {
257 for (i_copy = 0; i_copy < n_copies; i_copy++) {
259 if ((i_label == 0) || (i_sheet == 0)) {
261 print_page_begin (pi);
262 if (flags->crop_marks) {
263 print_crop_marks (pi);
267 print_label (pi, label,
271 flags->outline, flags->reverse);
273 i_label = (i_label + 1) % n_labels_per_page;
287 print_info_free (&pi);
289 gl_debug (DEBUG_PRINT, "END");
292 /*****************************************************************************/
293 /* Merge print command (uncollated copies) */
294 /*****************************************************************************/
296 gl_print_merge_uncollated (GnomePrintJob *job,
303 const GList *record_list;
305 const glTemplateLabelType *label_type;
306 gint i_sheet, i_label, n_labels_per_page, i_copy;
307 glMergeRecord *record;
309 glTemplateOrigin *origins;
311 gl_debug (DEBUG_PRINT, "START");
313 merge = gl_label_get_merge (label);
314 record_list = gl_merge_get_record_list (merge);
316 pi = print_info_new (job, label);
317 label_type = gl_template_get_first_label_type (pi->template);
319 n_labels_per_page = gl_template_get_n_labels (label_type);
320 origins = gl_template_get_origins (label_type);
325 for (i_copy = 0; i_copy < n_copies; i_copy++) {
327 for ( p=(GList *)record_list; p!=NULL; p=p->next ) {
328 record = (glMergeRecord *)p->data;
330 if ( record->select_flag ) {
333 if ((i_label == 0) || (i_sheet == 0)) {
335 print_page_begin (pi);
336 if (flags->crop_marks) {
337 print_crop_marks (pi);
341 print_label (pi, label,
345 flags->outline, flags->reverse);
347 i_label = (i_label + 1) % n_labels_per_page;
361 print_info_free (&pi);
363 gl_debug (DEBUG_PRINT, "END");
366 /*****************************************************************************/
367 /* Batch print. Call appropriate function above. */
368 /*****************************************************************************/
370 gl_print_batch (GnomePrintJob *job,
378 glTemplate *template;
379 const glTemplateLabelType *label_type;
382 gl_debug (DEBUG_PRINT, "START");
384 merge = gl_label_get_merge (label);
385 template = gl_label_get_template (label);
386 label_type = gl_template_get_first_label_type (template);
388 if ( merge == NULL ) {
389 n_per_page = gl_template_get_n_labels(label_type);
391 gl_print_simple (job, label, n_sheets, first, n_per_page, flags);
393 gl_print_merge_collated (job, label, n_copies, first, flags);
395 gl_template_free (template);
397 gl_debug (DEBUG_PRINT, "END");
400 /*---------------------------------------------------------------------------*/
401 /* PRIVATE. new print info structure */
402 /*---------------------------------------------------------------------------*/
404 print_info_new (GnomePrintJob *job,
407 PrintInfo *pi = g_new0 (PrintInfo, 1);
408 glTemplate *template;
410 gl_debug (DEBUG_PRINT, "START");
412 g_return_val_if_fail (job && GNOME_IS_PRINT_JOB (job), NULL);
413 g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
415 template = gl_label_get_template (label);
417 g_return_val_if_fail (template, NULL);
418 g_return_val_if_fail (template->page_size, NULL);
419 g_return_val_if_fail (template->page_width > 0, NULL);
420 g_return_val_if_fail (template->page_height > 0, NULL);
422 pi->pc = gnome_print_job_get_context (job);
423 pi->config = gnome_print_job_get_config (job);
425 gl_debug (DEBUG_PRINT,
426 "setting page size = \"%s\"", template->page_size);
428 gnome_print_config_set_length (pi->config,
429 GNOME_PRINT_KEY_PAPER_WIDTH,
430 template->page_width,
431 GNOME_PRINT_PS_UNIT);
432 gnome_print_config_set_length (pi->config,
433 GNOME_PRINT_KEY_PAPER_HEIGHT,
434 template->page_height,
435 GNOME_PRINT_PS_UNIT);
437 pi->page_width = template->page_width;
438 pi->page_height = template->page_height;
440 pi->template = template;
441 pi->label_rotate_flag = gl_label_get_rotate_flag (label);
445 gl_debug (DEBUG_PRINT, "END");
450 /*---------------------------------------------------------------------------*/
451 /* PRIVATE. free print info structure */
452 /*---------------------------------------------------------------------------*/
454 print_info_free (PrintInfo **pi)
456 gl_debug (DEBUG_PRINT, "START");
458 gl_template_free ((*pi)->template);
459 (*pi)->template = NULL;
461 gnome_print_context_close ((*pi)->pc);
466 gl_debug (DEBUG_PRINT, "END");
469 /*---------------------------------------------------------------------------*/
470 /* PRIVATE. Begin a new page. */
471 /*---------------------------------------------------------------------------*/
473 print_page_begin (PrintInfo *pi)
477 gl_debug (DEBUG_PRINT, "START");
481 str = g_strdup_printf ("sheet%02d", pi->sheet);
482 gnome_print_beginpage (pi->pc, str);
485 /* Translate and scale, so that our origin is at the upper left. */
486 gnome_print_translate (pi->pc, 0.0, pi->page_height);
487 gnome_print_scale (pi->pc, 1.0, -1.0);
489 gl_debug (DEBUG_PRINT, "END");
492 /*---------------------------------------------------------------------------*/
493 /* PRIVATE. End a page. */
494 /*---------------------------------------------------------------------------*/
496 print_page_end (PrintInfo *pi)
498 gl_debug (DEBUG_PRINT, "START");
500 gnome_print_showpage (pi->pc);
502 gl_debug (DEBUG_PRINT, "END");
505 /*---------------------------------------------------------------------------*/
506 /* PRIVATE. Print crop tick marks. */
507 /*---------------------------------------------------------------------------*/
509 print_crop_marks (PrintInfo *pi)
511 const glTemplateLabelType *label_type;
512 gdouble w, h, page_w, page_h;
514 glTemplateLayout *layout;
515 gdouble xmin, ymin, xmax, ymax, dx, dy;
516 gdouble x1, y1, x2, y2, x3, y3, x4, y4;
519 gl_debug (DEBUG_PRINT, "START");
521 label_type = gl_template_get_first_label_type (pi->template);
523 gl_template_get_label_size (label_type, &w, &h);
525 page_w = pi->page_width;
526 page_h = pi->page_height;
528 gnome_print_setrgbcolor (pi->pc, 0.0, 0.0, 0.0);
529 gnome_print_setopacity (pi->pc, 1.0);
530 gnome_print_setlinewidth (pi->pc, 0.25);
532 for (p=label_type->layouts; p != NULL; p=p->next) {
534 layout = (glTemplateLayout *)p->data;
538 xmax = layout->x0 + layout->dx*(layout->nx - 1) + w;
539 ymax = layout->y0 + layout->dy*(layout->ny - 1) + h;
547 for (ix=0; ix < nx; ix++) {
552 y1 = MAX((ymin - TICK_OFFSET), 0.0);
553 y2 = MAX((y1 - TICK_LENGTH), 0.0);
555 y3 = MIN((ymax + TICK_OFFSET), page_h);
556 y4 = MIN((y3 + TICK_LENGTH), page_h);
558 gnome_print_moveto (pi->pc, x1, y1);
559 gnome_print_lineto (pi->pc, x1, y2);
560 gnome_print_stroke (pi->pc);
562 gnome_print_moveto (pi->pc, x2, y1);
563 gnome_print_lineto (pi->pc, x2, y2);
564 gnome_print_stroke (pi->pc);
566 gnome_print_moveto (pi->pc, x1, y3);
567 gnome_print_lineto (pi->pc, x1, y4);
568 gnome_print_stroke (pi->pc);
570 gnome_print_moveto (pi->pc, x2, y3);
571 gnome_print_lineto (pi->pc, x2, y4);
572 gnome_print_stroke (pi->pc);
576 for (iy=0; iy < ny; iy++) {
581 x1 = MAX((xmin - TICK_OFFSET), 0.0);
582 x2 = MAX((x1 - TICK_LENGTH), 0.0);
584 x3 = MIN((xmax + TICK_OFFSET), page_w);
585 x4 = MIN((x3 + TICK_LENGTH), page_w);
587 gnome_print_moveto (pi->pc, x1, y1);
588 gnome_print_lineto (pi->pc, x2, y1);
589 gnome_print_stroke (pi->pc);
591 gnome_print_moveto (pi->pc, x1, y2);
592 gnome_print_lineto (pi->pc, x2, y2);
593 gnome_print_stroke (pi->pc);
595 gnome_print_moveto (pi->pc, x3, y1);
596 gnome_print_lineto (pi->pc, x4, y1);
597 gnome_print_stroke (pi->pc);
599 gnome_print_moveto (pi->pc, x3, y2);
600 gnome_print_lineto (pi->pc, x4, y2);
601 gnome_print_stroke (pi->pc);
607 gl_debug (DEBUG_PRINT, "END");
610 /*---------------------------------------------------------------------------*/
611 /* PRIVATE. Print i'th label. */
612 /*---------------------------------------------------------------------------*/
614 print_label (PrintInfo *pi,
618 glMergeRecord *record,
619 gboolean outline_flag,
620 gboolean reverse_flag)
622 const glTemplateLabelType *label_type;
623 gdouble width, height;
625 gl_debug (DEBUG_PRINT, "START");
627 label_type = gl_template_get_first_label_type (pi->template);
629 gl_label_get_size (label, &width, &height);
631 gnome_print_gsave (pi->pc);
633 /* Transform coordinate system to be relative to upper corner */
634 /* of the current label */
635 gnome_print_translate (pi->pc, x, y);
636 if (gl_label_get_rotate_flag (label)) {
637 gl_debug (DEBUG_PRINT, "Rotate flag set");
638 gnome_print_rotate (pi->pc, -90.0);
639 gnome_print_translate (pi->pc, -width, 0.0);
641 if ( reverse_flag ) {
642 gnome_print_translate (pi->pc, width, 0.0);
643 gnome_print_scale (pi->pc, -1.0, 1.0);
646 clip_to_outline (pi, label);
647 draw_label (pi, label, record);
649 draw_outline (pi, label);
651 clip_punchouts (pi, label);
653 gnome_print_grestore (pi->pc);
655 gl_debug (DEBUG_PRINT, "END");
658 /*---------------------------------------------------------------------------*/
659 /* PRIVATE. Draw label. */
660 /*---------------------------------------------------------------------------*/
662 draw_label (PrintInfo *pi,
664 glMergeRecord *record)
667 glLabelObject *object;
669 gl_debug (DEBUG_PRINT, "START");
671 for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
672 object = (glLabelObject *) p_obj->data;
674 draw_object (pi, object, record);
677 gl_debug (DEBUG_PRINT, "END");
680 /*---------------------------------------------------------------------------*/
681 /* PRIVATE. Draw object. */
682 /*---------------------------------------------------------------------------*/
684 draw_object (PrintInfo *pi,
685 glLabelObject *object,
686 glMergeRecord *record)
691 gl_debug (DEBUG_PRINT, "START");
693 gl_label_object_get_position (object, &x0, &y0);
694 gl_label_object_get_affine (object, affine);
696 gnome_print_gsave (pi->pc);
698 gnome_print_translate (pi->pc, x0, y0);
699 gnome_print_concat (pi->pc, affine);
701 if (GL_IS_LABEL_TEXT(object)) {
702 draw_text_object (pi, GL_LABEL_TEXT(object), record);
703 } else if (GL_IS_LABEL_BOX(object)) {
704 draw_box_object (pi, GL_LABEL_BOX(object), record);
705 } else if (GL_IS_LABEL_LINE(object)) {
706 draw_line_object (pi, GL_LABEL_LINE(object), record);
707 } else if (GL_IS_LABEL_ELLIPSE(object)) {
708 draw_ellipse_object (pi, GL_LABEL_ELLIPSE(object), record);
709 } else if (GL_IS_LABEL_IMAGE(object)) {
710 draw_image_object (pi, GL_LABEL_IMAGE(object), record);
711 } else if (GL_IS_LABEL_BARCODE(object)) {
712 draw_barcode_object (pi, GL_LABEL_BARCODE(object), record);
715 gnome_print_grestore (pi->pc);
717 gl_debug (DEBUG_PRINT, "END");
720 /*---------------------------------------------------------------------------*/
721 /* PRIVATE. Draw text object. */
722 /*---------------------------------------------------------------------------*/
724 draw_text_object (PrintInfo *pi,
726 glMergeRecord *record)
731 gdouble x_offset, y_offset, w, object_w, object_h;
736 GnomeFontWeight font_weight;
737 gboolean font_italic_flag;
739 glColorNode *color_node;
740 GtkJustification just;
741 gboolean auto_shrink;
742 GnomeGlyphList *glyphlist;
745 gdouble text_line_spacing;
748 gl_debug (DEBUG_PRINT, "START");
750 gl_label_object_get_size (GL_LABEL_OBJECT(object), &object_w, &object_h);
751 lines = gl_label_text_get_lines (object);
752 font_family = gl_label_object_get_font_family (GL_LABEL_OBJECT(object));
753 font_size = gl_label_object_get_font_size (GL_LABEL_OBJECT(object));
754 font_weight = gl_label_object_get_font_weight (GL_LABEL_OBJECT(object));
755 font_italic_flag = gl_label_object_get_font_italic_flag (GL_LABEL_OBJECT(object));
757 color_node = gl_label_object_get_text_color (GL_LABEL_OBJECT(object));
758 color = gl_color_node_expand (color_node, record);
759 gl_color_node_free (&color_node);
761 just = gl_label_object_get_text_alignment (GL_LABEL_OBJECT(object));
763 gl_label_object_get_text_line_spacing (GL_LABEL_OBJECT(object));
764 auto_shrink = gl_label_text_get_auto_shrink (object);
766 text = gl_text_node_lines_expand (lines, record);
767 line = g_strsplit (text, "\n", -1);
770 art_affine_identity (affine);
772 if (record && auto_shrink) {
773 /* auto shrink text size to keep within text box limits. */
774 for (i = 0; line[i] != NULL; i++) {
776 font = gnome_font_find_closest_from_weight_slant (font_family,
780 glyphlist = gnome_glyphlist_from_text_dumb (font,
784 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
786 gnome_glyphlist_unref (glyphlist);
788 /* If width is too large, iteratively shrink font_size until this
789 line fits the width, or until the font size is ridiculously
791 while ( (w > object_w) && (font_size >= 1.0) ) {
795 font = gnome_font_find_closest_from_weight_slant (
800 glyphlist = gnome_glyphlist_from_text_dumb (font,
804 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
806 gnome_glyphlist_unref (glyphlist);
812 font = gnome_font_find_closest_from_weight_slant (
817 gnome_print_setfont (pi->pc, font);
819 gnome_print_setrgbcolor (pi->pc,
820 GL_COLOR_F_RED (color),
821 GL_COLOR_F_GREEN (color),
822 GL_COLOR_F_BLUE (color));
823 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (color));
825 for (i = 0; line[i] != NULL; i++) {
827 glyphlist = gnome_glyphlist_from_text_dumb (font, color,
831 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
833 gnome_glyphlist_unref (glyphlist);
836 case GTK_JUSTIFY_LEFT:
837 x_offset = GL_LABEL_TEXT_MARGIN;
839 case GTK_JUSTIFY_CENTER:
840 x_offset = (object_w - GL_LABEL_TEXT_MARGIN - w) / 2.0;
842 case GTK_JUSTIFY_RIGHT:
843 x_offset = object_w - GL_LABEL_TEXT_MARGIN - w;
847 break; /* shouldn't happen */
850 /* Work out the y position to the BOTTOM of the first line */
851 y_offset = GL_LABEL_TEXT_MARGIN +
852 + gnome_font_get_descender (font)
853 + (i + 1) * font_size * text_line_spacing;
855 /* Remove any text line spacing from the first row. */
856 y_offset -= font_size * (text_line_spacing - 1);
859 gnome_print_moveto (pi->pc, x_offset, y_offset);
861 gnome_print_gsave (pi->pc);
862 gnome_print_scale (pi->pc, 1.0, -1.0);
863 gnome_print_show (pi->pc, line[i]);
864 gnome_print_grestore (pi->pc);
869 gl_text_node_lines_free (&lines);
870 g_free (font_family);
872 gl_debug (DEBUG_PRINT, "END");
875 /*---------------------------------------------------------------------------*/
876 /* PRIVATE. Draw box object. */
877 /*---------------------------------------------------------------------------*/
879 draw_box_object (PrintInfo *pi,
881 glMergeRecord *record)
886 glColorNode *line_color_node;
887 glColorNode *fill_color_node;
890 gl_debug (DEBUG_PRINT, "START");
892 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
893 line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
895 line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
896 fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
897 line_color = gl_color_node_expand (line_color_node, record);
898 fill_color = gl_color_node_expand (fill_color_node, record);
899 gl_color_node_free (&line_color_node);
900 gl_color_node_free (&fill_color_node);
902 /* Paint fill color */
903 create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
904 gnome_print_setrgbcolor (pi->pc,
905 GL_COLOR_F_RED (fill_color),
906 GL_COLOR_F_GREEN (fill_color),
907 GL_COLOR_F_BLUE (fill_color));
908 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (fill_color));
909 gnome_print_fill (pi->pc);
912 create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
913 gnome_print_setrgbcolor (pi->pc,
914 GL_COLOR_F_RED (line_color),
915 GL_COLOR_F_GREEN (line_color),
916 GL_COLOR_F_BLUE (line_color));
917 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
918 gnome_print_setlinewidth (pi->pc, line_width);
919 gnome_print_stroke (pi->pc);
921 gl_debug (DEBUG_PRINT, "END");
924 /*---------------------------------------------------------------------------*/
925 /* PRIVATE. Draw line object. */
926 /*---------------------------------------------------------------------------*/
928 draw_line_object (PrintInfo *pi,
930 glMergeRecord *record)
935 glColorNode *line_color_node;
937 gl_debug (DEBUG_PRINT, "START");
939 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
940 line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
942 line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
943 line_color = gl_color_node_expand (line_color_node, record);
944 gl_color_node_free (&line_color_node);
946 gnome_print_moveto (pi->pc, 0.0, 0.0);
947 gnome_print_lineto (pi->pc, w, h);
948 gnome_print_setrgbcolor (pi->pc,
949 GL_COLOR_F_RED (line_color),
950 GL_COLOR_F_GREEN (line_color),
951 GL_COLOR_F_BLUE (line_color));
952 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
953 gnome_print_setlinewidth (pi->pc, line_width);
954 gnome_print_stroke (pi->pc);
956 gl_debug (DEBUG_PRINT, "END");
959 /*---------------------------------------------------------------------------*/
960 /* PRIVATE. Draw ellipse object. */
961 /*---------------------------------------------------------------------------*/
963 draw_ellipse_object (PrintInfo *pi,
964 glLabelEllipse *object,
965 glMergeRecord *record)
967 gdouble x0, y0, rx, ry, w, h;
969 glColorNode *line_color_node;
970 glColorNode *fill_color_node;
974 gl_debug (DEBUG_PRINT, "START");
976 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
977 line_width = gl_label_object_get_line_width (GL_LABEL_OBJECT(object));
979 line_color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
980 fill_color_node = gl_label_object_get_fill_color (GL_LABEL_OBJECT(object));
981 line_color = gl_color_node_expand (line_color_node, record);
982 fill_color = gl_color_node_expand (fill_color_node, record);
983 gl_color_node_free (&line_color_node);
984 gl_color_node_free (&fill_color_node);
991 /* Paint fill color */
992 create_ellipse_path (pi->pc, x0, y0, rx, ry);
993 gnome_print_setrgbcolor (pi->pc,
994 GL_COLOR_F_RED (fill_color),
995 GL_COLOR_F_GREEN (fill_color),
996 GL_COLOR_F_BLUE (fill_color));
997 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (fill_color));
998 gnome_print_fill (pi->pc);
1001 create_ellipse_path (pi->pc, x0, y0, rx, ry);
1002 gnome_print_setrgbcolor (pi->pc,
1003 GL_COLOR_F_RED (line_color),
1004 GL_COLOR_F_GREEN (line_color),
1005 GL_COLOR_F_BLUE (line_color));
1006 gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
1007 gnome_print_setlinewidth (pi->pc, line_width);
1008 gnome_print_stroke (pi->pc);
1010 gl_debug (DEBUG_PRINT, "END");
1013 /*---------------------------------------------------------------------------*/
1014 /* PRIVATE. Draw image object. */
1015 /*---------------------------------------------------------------------------*/
1017 draw_image_object (PrintInfo *pi,
1018 glLabelImage *object,
1019 glMergeRecord *record)
1022 const GdkPixbuf *pixbuf;
1024 gint image_w, image_h, image_stride;
1025 gboolean image_alpha_flag;
1028 gl_debug (DEBUG_PRINT, "START");
1030 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1032 pixbuf = gl_label_image_get_pixbuf (object, record);
1033 image_data = gdk_pixbuf_get_pixels (pixbuf);
1034 image_w = gdk_pixbuf_get_width (pixbuf);
1035 image_h = gdk_pixbuf_get_height (pixbuf);
1036 image_stride = gdk_pixbuf_get_rowstride(pixbuf);
1037 image_alpha_flag = gdk_pixbuf_get_has_alpha(pixbuf);
1039 gnome_print_gsave (pi->pc);
1040 gnome_print_translate (pi->pc, 0.0, h);
1041 gnome_print_scale (pi->pc, w, -h);
1042 if (image_alpha_flag) {
1043 #ifndef NO_ALPHA_HACK
1044 guchar *image_data2;
1046 image_data2 = get_pixels_as_rgb (pixbuf);
1047 ret = gnome_print_rgbimage (pi->pc, image_data2,
1048 image_w, image_h, image_stride);
1049 g_free (image_data2);
1051 ret = gnome_print_rgbaimage (pi->pc, image_data,
1052 image_w, image_h, image_stride);
1055 ret = gnome_print_rgbimage (pi->pc, image_data,
1056 image_w, image_h, image_stride);
1058 gnome_print_grestore (pi->pc);
1060 gl_debug (DEBUG_PRINT, "END");
1063 /*---------------------------------------------------------------------------*/
1064 /* PRIVATE. Draw box object. */
1065 /*---------------------------------------------------------------------------*/
1067 draw_barcode_object (PrintInfo *pi,
1068 glLabelBarcode *object,
1069 glMergeRecord *record)
1072 glBarcodeLine *line;
1073 glBarcodeChar *bchar;
1077 gchar *text, *cstring;
1078 glTextNode *text_node;
1081 gboolean checksum_flag;
1083 glColorNode *color_node;
1084 guint format_digits;
1087 gl_debug (DEBUG_PRINT, "START");
1089 text_node = gl_label_barcode_get_data (object);
1090 gl_label_barcode_get_props (object,
1091 &id, &text_flag, &checksum_flag, &format_digits);
1093 color_node = gl_label_object_get_line_color (GL_LABEL_OBJECT(object));
1094 color = gl_color_node_expand (color_node, record);
1095 gl_color_node_free (&color_node);
1097 gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
1099 text = gl_text_node_expand (text_node, record);
1100 gbc = gl_barcode_new (id, text_flag, checksum_flag, w, h, text);
1102 gl_text_node_free (&text_node);
1107 font = gnome_font_find_closest_from_weight_slant (
1108 GL_BARCODE_FONT_FAMILY,
1109 GL_BARCODE_FONT_WEIGHT,
1111 gnome_print_setfont (pi->pc, font);
1113 gnome_print_setrgbcolor (pi->pc,
1114 GL_COLOR_F_RED (color),
1115 GL_COLOR_F_GREEN (color),
1116 GL_COLOR_F_BLUE (color));
1117 gnome_print_setopacity (pi->pc,
1118 GL_COLOR_F_ALPHA (color));
1120 y_offset = 12.0 - fabs (gnome_font_get_descender (font));
1121 gnome_print_moveto (pi->pc, 0.0, y_offset);
1123 gnome_print_gsave (pi->pc);
1124 gnome_print_scale (pi->pc, 1.0, -1.0);
1125 gnome_print_show (pi->pc, _("Invalid barcode data"));
1126 gnome_print_grestore (pi->pc);
1130 for (li = gbc->lines; li != NULL; li = li->next) {
1131 line = (glBarcodeLine *) li->data;
1133 gnome_print_moveto (pi->pc, line->x, line->y);
1134 gnome_print_lineto (pi->pc, line->x, line->y + line->length);
1135 gnome_print_setrgbcolor (pi->pc,
1136 GL_COLOR_F_RED (color),
1137 GL_COLOR_F_GREEN (color),
1138 GL_COLOR_F_BLUE (color));
1139 gnome_print_setopacity (pi->pc,
1140 GL_COLOR_F_ALPHA (color));
1141 gnome_print_setlinewidth (pi->pc, line->width);
1142 gnome_print_stroke (pi->pc);
1145 for (li = gbc->chars; li != NULL; li = li->next) {
1146 bchar = (glBarcodeChar *) li->data;
1148 font = gnome_font_find_closest_from_weight_slant (
1149 GL_BARCODE_FONT_FAMILY,
1150 GL_BARCODE_FONT_WEIGHT,
1151 FALSE, bchar->fsize);
1152 gnome_print_setfont (pi->pc, font);
1154 gnome_print_setrgbcolor (pi->pc,
1155 GL_COLOR_F_RED (color),
1156 GL_COLOR_F_GREEN (color),
1157 GL_COLOR_F_BLUE (color));
1158 gnome_print_setopacity (pi->pc,
1159 GL_COLOR_F_ALPHA (color));
1162 bchar->fsize - fabs (gnome_font_get_descender (font));
1164 gnome_print_moveto (pi->pc, bchar->x, bchar->y+y_offset);
1166 cstring = g_strdup_printf ("%c", bchar->c);
1167 gnome_print_gsave (pi->pc);
1168 gnome_print_scale (pi->pc, 1.0, -1.0);
1169 gnome_print_show (pi->pc, cstring);
1170 gnome_print_grestore (pi->pc);
1175 gl_barcode_free (&gbc);
1179 gl_debug (DEBUG_PRINT, "END");
1182 /*---------------------------------------------------------------------------*/
1183 /* PRIVATE. Draw outline. */
1184 /*---------------------------------------------------------------------------*/
1186 draw_outline (PrintInfo *pi,
1189 const glTemplateLabelType *label_type;
1193 gl_debug (DEBUG_PRINT, "START");
1195 label_type = gl_template_get_first_label_type (pi->template);
1197 gnome_print_setrgbcolor (pi->pc, 0.0, 0.0, 0.0);
1198 gnome_print_setopacity (pi->pc, 1.0);
1199 gnome_print_setlinewidth (pi->pc, 0.25);
1201 switch (label_type->shape) {
1203 case GL_TEMPLATE_SHAPE_RECT:
1204 gl_label_get_size (label, &w, &h);
1205 r = label_type->size.rect.r;
1207 /* simple rectangle */
1208 create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
1210 /* rectangle with rounded corners */
1211 create_rounded_rectangle_path (pi->pc, 0.0, 0.0,
1214 gnome_print_stroke (pi->pc);
1217 case GL_TEMPLATE_SHAPE_ROUND:
1219 r1 = label_type->size.round.r;
1220 create_ellipse_path (pi->pc, r1, r1, r1, r1);
1221 gnome_print_stroke (pi->pc);
1224 case GL_TEMPLATE_SHAPE_CD:
1225 if ((label_type->size.cd.h == 0) && (label_type->size.cd.w == 0)) {
1226 /* CD style, round label w/ concentric round hole */
1227 r1 = label_type->size.cd.r1;
1228 r2 = label_type->size.cd.r2;
1229 create_ellipse_path (pi->pc, r1, r1, r1, r1);
1230 gnome_print_stroke (pi->pc);
1231 create_ellipse_path (pi->pc, r1, r1, r2, r2);
1232 gnome_print_stroke (pi->pc);
1234 /* Business Card CD style, clipped round label w/ hole */
1235 gl_label_get_size (label, &w, &h);
1236 r1 = label_type->size.cd.r1;
1237 r2 = label_type->size.cd.r2;
1238 create_clipped_circle_path (pi->pc, w/2, h/2, w, h, r1);
1239 gnome_print_stroke (pi->pc);
1240 create_ellipse_path (pi->pc, w/2, h/2, r2, r2);
1241 gnome_print_stroke (pi->pc);
1246 g_warning ("Unknown template label style");
1250 gl_debug (DEBUG_PRINT, "END");
1253 /*---------------------------------------------------------------------------*/
1254 /* PRIVATE. Clip to outline. */
1255 /*---------------------------------------------------------------------------*/
1257 clip_to_outline (PrintInfo *pi,
1260 const glTemplateLabelType *label_type;
1263 gdouble waste, x_waste, y_waste;
1265 gl_debug (DEBUG_PRINT, "START");
1267 label_type = gl_template_get_first_label_type (pi->template);
1269 switch (label_type->shape) {
1271 case GL_TEMPLATE_SHAPE_RECT:
1272 gl_label_get_size (label, &w, &h);
1273 r = label_type->size.rect.r;
1274 x_waste = label_type->size.rect.x_waste;
1275 y_waste = label_type->size.rect.y_waste;
1277 /* simple rectangle */
1278 create_rectangle_path (pi->pc,
1280 w+2*x_waste, h+2*y_waste);
1282 /* rectangle with rounded corners */
1283 create_rounded_rectangle_path (pi->pc,
1285 w+2*x_waste, h+2*y_waste, r);
1287 gnome_print_clip (pi->pc);
1290 case GL_TEMPLATE_SHAPE_ROUND:
1291 r1 = label_type->size.round.r;
1292 waste = label_type->size.round.waste;
1293 create_ellipse_path (pi->pc, r1, r1, r1+waste, r1+waste);
1294 gnome_print_clip (pi->pc);
1297 case GL_TEMPLATE_SHAPE_CD:
1298 waste = label_type->size.cd.waste;
1299 if ((label_type->size.cd.h == 0) && (label_type->size.cd.w == 0)) {
1300 /* CD style, round label w/ concentric round hole */
1301 r1 = label_type->size.cd.r1;
1302 create_ellipse_path (pi->pc, r1, r1, r1+waste, r1+waste);
1304 /* Business Card CD style, clipped round label w/ hole */
1305 gl_label_get_size (label, &w, &h);
1306 r1 = label_type->size.cd.r1;
1307 create_clipped_circle_path (pi->pc,
1309 w+2*waste, h+2*waste,
1312 gnome_print_clip (pi->pc);
1316 g_warning ("Unknown template label style");
1320 gl_debug (DEBUG_PRINT, "END");
1323 /*---------------------------------------------------------------------------*/
1324 /* PRIVATE. Clip punchouts. (Save some ink by not printing in CD holes) */
1326 /* Ideally this would be done in clip_to_outline, but I am not sure how to */
1327 /* invert the region for gnome_print_clip, so instead, I will just draw */
1328 /* a white circle on top of everything else. */
1329 /*---------------------------------------------------------------------------*/
1331 clip_punchouts (PrintInfo *pi,
1334 const glTemplateLabelType *label_type;
1338 gl_debug (DEBUG_PRINT, "START");
1340 label_type = gl_template_get_first_label_type (pi->template);
1342 switch (label_type->shape) {
1344 case GL_TEMPLATE_SHAPE_RECT:
1345 case GL_TEMPLATE_SHAPE_ROUND:
1348 case GL_TEMPLATE_SHAPE_CD:
1349 gl_label_get_size (label, &w, &h);
1350 waste = label_type->size.cd.waste;
1351 r2 = label_type->size.cd.r2;
1352 create_ellipse_path (pi->pc, w/2, h/2, r2-waste, r2-waste);
1353 gnome_print_setrgbcolor (pi->pc, 1.0, 1.0, 1.0);
1354 gnome_print_setopacity (pi->pc, 1.0);
1355 gnome_print_fill (pi->pc);
1359 g_warning ("Unknown template label style");
1363 gl_debug (DEBUG_PRINT, "END");
1366 /*---------------------------------------------------------------------------*/
1367 /* PRIVATE. Path creation utilities. */
1368 /*---------------------------------------------------------------------------*/
1370 create_rectangle_path (GnomePrintContext *pc,
1376 gl_debug (DEBUG_PRINT, "START");
1378 gnome_print_newpath (pc);
1379 gnome_print_moveto (pc, x0, y0);
1380 gnome_print_lineto (pc, x0 + w, y0);
1381 gnome_print_lineto (pc, x0 + w, y0 + h);
1382 gnome_print_lineto (pc, x0, y0 + h);
1383 gnome_print_lineto (pc, x0, y0);
1384 gnome_print_closepath (pc);
1386 gl_debug (DEBUG_PRINT, "END");
1390 create_ellipse_path (GnomePrintContext *pc,
1399 gl_debug (DEBUG_PRINT, "START");
1401 gnome_print_newpath (pc);
1402 gnome_print_moveto (pc, x0 + rx, y0);
1403 for (i_theta = ARC_FINE; i_theta <= 360; i_theta += ARC_FINE) {
1404 x = x0 + rx * cos (i_theta * G_PI / 180.0);
1405 y = y0 + ry * sin (i_theta * G_PI / 180.0);
1406 gnome_print_lineto (pc, x, y);
1408 gnome_print_closepath (pc);
1410 gl_debug (DEBUG_PRINT, "END");
1414 create_rounded_rectangle_path (GnomePrintContext *pc,
1424 gl_debug (DEBUG_PRINT, "START");
1426 gnome_print_newpath (pc);
1428 gnome_print_moveto (pc, x0 + r, y0);
1429 for (i_theta = ARC_COURSE; i_theta <= 90; i_theta += ARC_COURSE) {
1430 x = x0 + r - r * sin (i_theta * G_PI / 180.0);
1431 y = y0 + r - r * cos (i_theta * G_PI / 180.0);
1432 gnome_print_lineto (pc, x, y);
1434 for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1435 x = x0 + r - r * cos (i_theta * G_PI / 180.0);
1436 y = y0 + (h - r) + r * sin (i_theta * G_PI / 180.0);
1437 gnome_print_lineto (pc, x, y);
1439 for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1440 x = x0 + (w - r) + r * sin (i_theta * G_PI / 180.0);
1441 y = y0 + (h - r) + r * cos (i_theta * G_PI / 180.0);
1442 gnome_print_lineto (pc, x, y);
1444 for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1445 x = x0 + (w - r) + r * cos (i_theta * G_PI / 180.0);
1446 y = y0 + r - r * sin (i_theta * G_PI / 180.0);
1447 gnome_print_lineto (pc, x, y);
1449 gnome_print_lineto (pc, x0 + r, y0);
1451 gnome_print_closepath (pc);
1453 gl_debug (DEBUG_PRINT, "END");
1457 create_clipped_circle_path (GnomePrintContext *pc,
1465 gdouble theta1, theta2;
1468 gl_debug (DEBUG_PRINT, "START");
1470 theta1 = (180.0/G_PI) * acos (w / (2.0*r));
1471 theta2 = (180.0/G_PI) * asin (h / (2.0*r));
1473 gnome_print_newpath (pc);
1475 x = x0 + r * cos (theta1 * G_PI / 180.0);
1476 y = y0 + r * sin (theta1 * G_PI / 180.0);
1477 gnome_print_moveto (pc, x, y);
1479 for ( i_theta = theta1 + ARC_FINE; i_theta < theta2; i_theta +=ARC_FINE ) {
1480 x = x0 + r * cos (i_theta * G_PI / 180.0);
1481 y = y0 + r * sin (i_theta * G_PI / 180.0);
1482 gnome_print_lineto (pc, x, y);
1485 x = x0 + r * cos (theta2 * G_PI / 180.0);
1486 y = y0 + r * sin (theta2 * G_PI / 180.0);
1487 gnome_print_lineto (pc, x, y);
1489 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1490 x = x0 + r * cos ((180-theta2) * G_PI / 180.0);
1491 y = y0 + r * sin ((180-theta2) * G_PI / 180.0);
1492 gnome_print_lineto (pc, x, y);
1495 for ( i_theta = 180-theta2+ARC_FINE; i_theta < (180-theta1); i_theta +=ARC_FINE ) {
1496 x = x0 + r * cos (i_theta * G_PI / 180.0);
1497 y = y0 + r * sin (i_theta * G_PI / 180.0);
1498 gnome_print_lineto (pc, x, y);
1501 x = x0 + r * cos ((180-theta1) * G_PI / 180.0);
1502 y = y0 + r * sin ((180-theta1) * G_PI / 180.0);
1503 gnome_print_lineto (pc, x, y);
1505 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1506 x = x0 + r * cos ((180+theta1) * G_PI / 180.0);
1507 y = y0 + r * sin ((180+theta1) * G_PI / 180.0);
1508 gnome_print_lineto (pc, x, y);
1511 for ( i_theta = 180+theta1+ARC_FINE; i_theta < (180+theta2); i_theta +=ARC_FINE ) {
1512 x = x0 + r * cos (i_theta * G_PI / 180.0);
1513 y = y0 + r * sin (i_theta * G_PI / 180.0);
1514 gnome_print_lineto (pc, x, y);
1517 x = x0 + r * cos ((180+theta2) * G_PI / 180.0);
1518 y = y0 + r * sin ((180+theta2) * G_PI / 180.0);
1519 gnome_print_lineto (pc, x, y);
1521 if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1522 x = x0 + r * cos ((360-theta2) * G_PI / 180.0);
1523 y = y0 + r * sin ((360-theta2) * G_PI / 180.0);
1524 gnome_print_lineto (pc, x, y);
1527 for ( i_theta = 360-theta2+ARC_FINE; i_theta < (360-theta1); i_theta +=ARC_FINE ) {
1528 x = x0 + r * cos (i_theta * G_PI / 180.0);
1529 y = y0 + r * sin (i_theta * G_PI / 180.0);
1530 gnome_print_lineto (pc, x, y);
1533 if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1534 x = x0 + r * cos ((360-theta1) * G_PI / 180.0);
1535 y = y0 + r * sin ((360-theta1) * G_PI / 180.0);
1536 gnome_print_lineto (pc, x, y);
1539 x = x0 + r * cos (theta1 * G_PI / 180.0);
1540 y = y0 + r * sin (theta1 * G_PI / 180.0);
1541 gnome_print_lineto (pc, x, y);
1543 gnome_print_closepath (pc);
1545 gl_debug (DEBUG_PRINT, "END");
1548 #ifndef NO_ALPHA_HACK
1549 /*---------------------------------------------------------------------------*/
1550 /* PRIVATE. Extract a copy of rgba pixels, removing alpha by compositing */
1551 /* with a white background. */
1553 /* This is currently needed due to the lousy job gnome-print does in */
1554 /* rendering images with alpha channels to PS. This sacrafices the ability */
1555 /* to do compositing of images with other items in the background. */
1556 /*---------------------------------------------------------------------------*/
1558 get_pixels_as_rgb (const GdkPixbuf *pixbuf)
1560 gint bits_per_sample, channels;
1562 gint width, height, rowstride;
1564 guchar *buf_src, *buf_dest;
1565 guchar *p_src, *p_dest;
1568 gdouble alpha, beta;
1570 gl_debug (DEBUG_PRINT, "START");
1572 g_return_val_if_fail (pixbuf && GDK_IS_PIXBUF (pixbuf), NULL);
1574 /* extract pixels and parameters from pixbuf. */
1575 buf_src = gdk_pixbuf_get_pixels (pixbuf);
1576 bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
1577 channels = gdk_pixbuf_get_n_channels (pixbuf);
1578 has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
1579 width = gdk_pixbuf_get_width (pixbuf);
1580 height = gdk_pixbuf_get_height (pixbuf);
1581 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1583 /* validate assumptions about pixbuf. */
1584 g_return_val_if_fail (buf_src, NULL);
1585 g_return_val_if_fail (bits_per_sample == 8, NULL);
1586 g_return_val_if_fail (channels == 4, NULL);
1587 g_return_val_if_fail (has_alpha, NULL);
1588 g_return_val_if_fail (width > 0, NULL);
1589 g_return_val_if_fail (height > 0, NULL);
1590 g_return_val_if_fail (rowstride > 0, NULL);
1592 /* Allocate a destination buffer */
1593 bytes = height * rowstride;
1594 gl_debug (DEBUG_PRINT, "bytes = %d", bytes);
1595 buf_dest = g_try_malloc (bytes);
1599 gl_debug (DEBUG_PRINT, "buf_dest = %x", buf_dest);
1601 /* Copy pixels, transforming rgba to rgb by compositing with a white bg. */
1604 for ( iy=0; iy < height; iy++ ) {
1606 p_src = buf_src + iy*rowstride;
1607 p_dest = buf_dest + iy*rowstride;
1609 for ( ix=0; ix < width; ix++ ) {
1619 *p_dest++ = (guchar) (alpha*r + beta*255 + 0.5);
1620 *p_dest++ = (guchar) (alpha*g + beta*255 + 0.5);
1621 *p_dest++ = (guchar) (alpha*b + beta*255 + 0.5);
1627 gl_debug (DEBUG_PRINT, "START");