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
27 #include <libgnome/gnome-paper.h>
28 #include <libgnomeprint/gnome-printer.h>
38 #define GL_PRINT_DEFAULT_PAPER "US-Letter"
40 #define RED(x) ( (((x)>>24) & 0xff) / 255.0 )
41 #define GREEN(x) ( (((x)>>16) & 0xff) / 255.0 )
42 #define BLUE(x) ( (((x)>>8) & 0xff) / 255.0 )
43 #define ALPHA(x) ( ( (x) & 0xff) / 255.0 )
45 /*===========================================*/
47 /*===========================================*/
48 typedef struct _PrintInfo {
49 /* gnome print context */
50 GnomePrintContext *pc;
52 /* gLabels Template */
54 gboolean label_rotate_flag;
58 /*===========================================*/
59 /* Private function prototypes. */
60 /*===========================================*/
61 static PrintInfo *print_info_new (GnomePrintMaster * master, glLabel * label);
62 static void print_info_free (PrintInfo ** pi);
64 static void print_label (PrintInfo * pi, glLabel * label, gint i,
65 glMergeRecord * record, gboolean outline_flag,
66 gboolean reverse_flag);
68 static void draw_label (PrintInfo * pi, glLabel * label,
69 glMergeRecord * record);
71 static void draw_text_object (PrintInfo * pi, glLabelObject * object,
72 glMergeRecord * record);
73 static void draw_box_object (PrintInfo * pi, glLabelObject * object);
74 static void draw_line_object (PrintInfo * pi, glLabelObject * object);
75 static void draw_ellipse_object (PrintInfo * pi, glLabelObject * object);
76 static void draw_image_object (PrintInfo * pi, glLabelObject * object);
77 static void draw_barcode_object (PrintInfo * pi, glLabelObject * object,
78 glMergeRecord * record);
80 static void draw_outline (PrintInfo * pi, glLabel * label);
82 static void clip_to_outline (PrintInfo * pi, glLabel * label);
85 static void create_rectangle_path (GnomePrintContext * pc,
86 gdouble x0, gdouble y0,
87 gdouble w, gdouble h);
88 static void create_ellipse_path (GnomePrintContext * pc,
89 gdouble x0, gdouble y0,
90 gdouble rx, gdouble ry);
91 static void create_rounded_rectangle_path (GnomePrintContext * pc,
92 gdouble x0, gdouble y0,
93 gdouble w, gdouble h, gdouble r);
95 /*****************************************************************************/
96 /* Simple (no merge data) print command. */
97 /*****************************************************************************/
99 gl_print_simple (GnomePrintMaster * master,
104 gboolean outline_flag,
105 gboolean reverse_flag)
108 gint i_sheet, i_label;
109 gchar *page_str = NULL;
111 pi = print_info_new (master, label);
113 for (i_sheet = 0; i_sheet < n_sheets; i_sheet++) {
115 page_str = g_strdup_printf ("sheet %d", i_sheet + 1);
116 gnome_print_beginpage (pi->pc, page_str);
119 for (i_label = first - 1; i_label < last; i_label++) {
121 print_label (pi, label, i_label, NULL,
122 outline_flag, reverse_flag);
126 gnome_print_showpage (pi->pc);
129 print_info_free (&pi);
132 /*****************************************************************************/
133 /* Merge print command (collated copies) */
134 /*****************************************************************************/
136 gl_print_merge_collated (GnomePrintMaster * master,
141 gboolean outline_flag,
142 gboolean reverse_flag)
145 gint i_sheet, i_label, n_labels_per_page, i_copy;
147 glMergeRecord *record;
150 pi = print_info_new (master, label);
152 n_labels_per_page = (pi->template->nx) * (pi->template->ny);
157 for ( p=record_list; p!=NULL; p=p->next ) {
158 record = (glMergeRecord *)p->data;
160 if ( record->select_flag ) {
161 for (i_copy = 0; i_copy < n_copies; i_copy++) {
163 if ((i_label == 0) || (i_sheet == 0)) {
164 str = g_strdup_printf ("sheet %d",
166 gnome_print_beginpage (pi->pc, str);
170 print_label (pi, label, i_label, record,
171 outline_flag, reverse_flag);
173 i_label = (i_label + 1) % n_labels_per_page;
175 gnome_print_showpage (pi->pc);
182 gnome_print_showpage (pi->pc);
185 print_info_free (&pi);
188 /*****************************************************************************/
189 /* Merge print command (uncollated copies) */
190 /*****************************************************************************/
192 gl_print_merge_uncollated (GnomePrintMaster * master,
197 gboolean outline_flag,
198 gboolean reverse_flag)
201 gint i_sheet, i_label, n_labels_per_page, i_copy;
203 glMergeRecord *record;
206 pi = print_info_new (master, label);
208 n_labels_per_page = (pi->template->nx) * (pi->template->ny);
213 for (i_copy = 0; i_copy < n_copies; i_copy++) {
215 for ( p=record_list; p!=NULL; p=p->next ) {
216 record = (glMergeRecord *)p->data;
218 if ( record->select_flag ) {
221 if ((i_label == 0) || (i_sheet == 0)) {
222 str = g_strdup_printf ("sheet %d",
224 gnome_print_beginpage (pi->pc, str);
228 print_label (pi, label, i_label, record,
229 outline_flag, reverse_flag);
231 i_label = (i_label + 1) % n_labels_per_page;
233 gnome_print_showpage (pi->pc);
240 gnome_print_showpage (pi->pc);
243 print_info_free (&pi);
246 /*****************************************************************************/
247 /* Batch print. Call appropriate function above. */
248 /*****************************************************************************/
250 gl_print_batch (GnomePrintMaster * master, glLabel * label,
251 gint n_sheets, gint n_copies,
252 gboolean outline_flag, gboolean reverse_flag)
255 GList *record_list = NULL;
257 if ( label->merge_type == GL_MERGE_NONE ) {
258 n_per_page = (label->template->nx)*(label->template->ny);
260 gl_print_simple (master, label, n_sheets, 1, n_per_page,
261 outline_flag, reverse_flag);
263 record_list = gl_merge_read_data (label->merge_type,
267 gl_print_merge_collated (master, label, record_list,
269 outline_flag, reverse_flag);
273 /*---------------------------------------------------------------------------*/
274 /* PRIVATE. new print info structure */
275 /*---------------------------------------------------------------------------*/
277 print_info_new (GnomePrintMaster * master,
280 const GnomePaper *paper;
281 PrintInfo *pi = g_new0 (PrintInfo, 1);
282 glTemplate *template = label->template;
284 if (template == NULL) {
285 WARN ("Undefined template \"%s\"", label->template_name);
289 pi->pc = gnome_print_master_get_context (master);
291 if ((template != NULL) && (template->page_size != NULL)) {
292 paper = gnome_paper_with_name (template->page_size);
294 paper = gnome_paper_with_name (GL_PRINT_DEFAULT_PAPER);
296 gnome_print_master_set_paper (master, paper);
298 pi->template = template;
299 pi->label_rotate_flag = label->rotate_flag;
304 /*---------------------------------------------------------------------------*/
305 /* PRIVATE. free print info structure */
306 /*---------------------------------------------------------------------------*/
308 print_info_free (PrintInfo ** pi)
310 gnome_print_context_close ((*pi)->pc);
316 /*---------------------------------------------------------------------------*/
317 /* PRIVATE. Print i'th label. */
318 /*---------------------------------------------------------------------------*/
320 print_label (PrintInfo * pi,
323 glMergeRecord * record,
324 gboolean outline_flag,
325 gboolean reverse_flag)
330 ix = i_label % (pi->template->nx);
331 iy = ((pi->template->ny) - 1) - (i_label / (pi->template->nx));
333 gnome_print_gsave (pi->pc);
335 /* Transform coordinate system to be relative to upper corner */
336 /* of the current label */
337 gnome_print_translate (pi->pc,
338 ix * (pi->template->dx) + pi->template->x0,
339 iy * (pi->template->dy) + pi->template->y0);
340 if (!label->rotate_flag) {
341 art_affine_scale (a, 1.0, -1.0);
342 a[5] = label->height;
343 gnome_print_concat (pi->pc, a);
345 gnome_print_rotate (pi->pc, 90.0);
346 gnome_print_scale (pi->pc, 1.0, -1.0);
348 if ( reverse_flag ) {
349 gnome_print_translate (pi->pc, label->width, 0.0);
350 art_affine_scale (a, -1.0, 1.0);
351 gnome_print_concat (pi->pc, a);
354 draw_outline (pi, label);
356 #ifdef CLIP_LABEL /* FIXME: this may be causing problems for some people. */
357 clip_to_outline (pi, label);
359 draw_label (pi, label, record);
361 gnome_print_grestore (pi->pc);
365 /*---------------------------------------------------------------------------*/
366 /* PRIVATE. Draw label. */
367 /*---------------------------------------------------------------------------*/
369 draw_label (PrintInfo * pi,
371 glMergeRecord * record)
374 glLabelObject *object;
376 for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
377 object = (glLabelObject *) p_obj->data;
379 if (object->type == GL_LABEL_OBJECT_TEXT) {
380 draw_text_object (pi, object, record);
381 } else if (object->type == GL_LABEL_OBJECT_BOX) {
382 draw_box_object (pi, object);
383 } else if (object->type == GL_LABEL_OBJECT_LINE) {
384 draw_line_object (pi, object);
385 } else if (object->type == GL_LABEL_OBJECT_ELLIPSE) {
386 draw_ellipse_object (pi, object);
387 } else if (object->type == GL_LABEL_OBJECT_IMAGE) {
388 draw_image_object (pi, object);
389 } else if (object->type == GL_LABEL_OBJECT_BARCODE) {
390 draw_barcode_object (pi, object, record);
397 /*---------------------------------------------------------------------------*/
398 /* PRIVATE. Draw text object. */
399 /*---------------------------------------------------------------------------*/
401 draw_text_object (PrintInfo * pi,
402 glLabelObject * object,
403 glMergeRecord * record)
409 gdouble x_offset, y_offset;
411 gchar *text, *utf8_text;
413 font = gnome_font_new_closest (object->arg.text.font_family,
414 object->arg.text.font_weight,
415 object->arg.text.font_italic_flag,
416 object->arg.text.font_size);
417 gnome_print_setfont (pi->pc, font);
419 gnome_print_setrgbcolor (pi->pc,
420 RED (object->arg.text.color),
421 GREEN (object->arg.text.color),
422 BLUE (object->arg.text.color));
423 gnome_print_setopacity (pi->pc, ALPHA (object->arg.text.color));
425 text = gl_text_node_lines_expand (object->arg.text.lines, record);
426 line = g_strsplit (text, "\n", -1);
429 for (i = 0; line[i] != NULL; i++) {
431 utf8_text = gl_hack_text_to_utf8 (line[i]);
433 w = gl_hack_get_width_string (font, line[i]);
435 switch (object->arg.text.just) {
436 case GTK_JUSTIFY_LEFT:
439 case GTK_JUSTIFY_CENTER:
442 case GTK_JUSTIFY_RIGHT:
447 break; /* shouldn't happen */
450 y_offset = (i + 1) * object->arg.text.font_size
451 - gnome_font_get_descender (font);
453 x = object->x + x_offset;
454 y = object->y + y_offset;
455 gnome_print_moveto (pi->pc, x, y);
457 gnome_print_gsave (pi->pc);
458 gnome_print_scale (pi->pc, 1.0, -1.0);
459 gnome_print_show (pi->pc, utf8_text);
460 gnome_print_grestore (pi->pc);
469 /*---------------------------------------------------------------------------*/
470 /* PRIVATE. Draw box object. */
471 /*---------------------------------------------------------------------------*/
473 draw_box_object (PrintInfo * pi,
474 glLabelObject * object)
480 w = object->arg.box.w;
481 h = object->arg.box.h;
483 /* Paint fill color */
484 create_rectangle_path (pi->pc, x, y, w, h);
485 gnome_print_setrgbcolor (pi->pc,
486 RED (object->arg.box.fill_color),
487 GREEN (object->arg.box.fill_color),
488 BLUE (object->arg.box.fill_color));
489 gnome_print_setopacity (pi->pc, ALPHA (object->arg.box.fill_color));
490 gnome_print_fill (pi->pc);
493 create_rectangle_path (pi->pc, x, y, w, h);
494 gnome_print_setrgbcolor (pi->pc,
495 RED (object->arg.box.line_color),
496 GREEN (object->arg.box.line_color),
497 BLUE (object->arg.box.line_color));
498 gnome_print_setopacity (pi->pc, ALPHA (object->arg.box.line_color));
499 gnome_print_setlinewidth (pi->pc, object->arg.box.line_width);
500 gnome_print_stroke (pi->pc);
503 /*---------------------------------------------------------------------------*/
504 /* PRIVATE. Draw line object. */
505 /*---------------------------------------------------------------------------*/
507 draw_line_object (PrintInfo * pi,
508 glLabelObject * object)
510 gdouble x, y, dx, dy;
514 dx = object->arg.line.dx;
515 dy = object->arg.line.dy;
517 gnome_print_moveto (pi->pc, x, y);
518 gnome_print_lineto (pi->pc, x + dx, y + dy);
519 gnome_print_setrgbcolor (pi->pc,
520 RED (object->arg.line.line_color),
521 GREEN (object->arg.line.line_color),
522 BLUE (object->arg.line.line_color));
523 gnome_print_setopacity (pi->pc, ALPHA (object->arg.line.line_color));
524 gnome_print_setlinewidth (pi->pc, object->arg.line.line_width);
525 gnome_print_stroke (pi->pc);
528 /*---------------------------------------------------------------------------*/
529 /* PRIVATE. Draw ellipse object. */
530 /*---------------------------------------------------------------------------*/
532 draw_ellipse_object (PrintInfo * pi,
533 glLabelObject * object)
535 gdouble x0, y0, rx, ry;
537 rx = object->arg.ellipse.w / 2.0;
538 ry = object->arg.ellipse.h / 2.0;
542 /* Paint fill color */
543 create_ellipse_path (pi->pc, x0, y0, rx, ry);
544 gnome_print_setrgbcolor (pi->pc,
545 RED (object->arg.ellipse.fill_color),
546 GREEN (object->arg.ellipse.fill_color),
547 BLUE (object->arg.ellipse.fill_color));
548 gnome_print_setopacity (pi->pc, ALPHA (object->arg.ellipse.fill_color));
549 gnome_print_fill (pi->pc);
552 create_ellipse_path (pi->pc, x0, y0, rx, ry);
553 gnome_print_setrgbcolor (pi->pc,
554 RED (object->arg.ellipse.line_color),
555 GREEN (object->arg.ellipse.line_color),
556 BLUE (object->arg.ellipse.line_color));
557 gnome_print_setopacity (pi->pc, ALPHA (object->arg.ellipse.line_color));
558 gnome_print_setlinewidth (pi->pc, object->arg.ellipse.line_width);
559 gnome_print_stroke (pi->pc);
562 /*---------------------------------------------------------------------------*/
563 /* PRIVATE. Draw image object. */
564 /*---------------------------------------------------------------------------*/
566 draw_image_object (PrintInfo * pi,
567 glLabelObject * object)
574 w = object->arg.image.w;
575 h = object->arg.image.h;
577 pixbuf = object->arg.image.image;
579 gnome_print_gsave (pi->pc);
580 gnome_print_translate (pi->pc, x, y + h);
581 gnome_print_scale (pi->pc, w, -h);
582 gnome_print_pixbuf (pi->pc, pixbuf);
583 gnome_print_grestore (pi->pc);
587 /*---------------------------------------------------------------------------*/
588 /* PRIVATE. Draw box object. */
589 /*---------------------------------------------------------------------------*/
591 draw_barcode_object (PrintInfo * pi,
592 glLabelObject * object,
593 glMergeRecord * record)
597 glBarcodeChar *bchar;
599 gdouble x, y, y_offset;
601 gchar *text, *cstring;
606 text = gl_text_node_expand (object->arg.barcode.text_node, record);
607 gbc = gl_barcode (object->arg.barcode.style,
608 object->arg.barcode.text_flag,
609 object->arg.barcode.scale, text);
614 font = gnome_font_new_closest (GL_BARCODE_FONT_FAMILY,
615 GL_BARCODE_FONT_WEIGHT,
617 gnome_print_setfont (pi->pc, font);
619 gnome_print_setrgbcolor (pi->pc,
620 RED (object->arg.barcode.color),
621 GREEN (object->arg.barcode.color),
622 BLUE (object->arg.barcode.color));
623 gnome_print_setopacity (pi->pc,
624 ALPHA (object->arg.barcode.color));
626 y_offset = 12.0 - gnome_font_get_descender (font);
627 gnome_print_moveto (pi->pc, x, y + y_offset);
629 gnome_print_gsave (pi->pc);
630 gnome_print_scale (pi->pc, 1.0, -1.0);
631 gnome_print_show (pi->pc, _("Invalid barcode"));
632 gnome_print_grestore (pi->pc);
636 for (li = gbc->lines; li != NULL; li = li->next) {
637 line = (glBarcodeLine *) li->data;
639 gnome_print_moveto (pi->pc, x + line->x, y + line->y);
640 gnome_print_lineto (pi->pc, x + line->x,
641 y + line->y + line->length);
642 gnome_print_setrgbcolor (pi->pc,
643 RED (object->arg.barcode.
645 GREEN (object->arg.barcode.
647 BLUE (object->arg.barcode.
649 gnome_print_setopacity (pi->pc,
650 ALPHA (object->arg.barcode.
652 gnome_print_setlinewidth (pi->pc, line->width);
653 gnome_print_stroke (pi->pc);
656 for (li = gbc->chars; li != NULL; li = li->next) {
657 bchar = (glBarcodeChar *) li->data;
659 font = gnome_font_new_closest (GL_BARCODE_FONT_FAMILY,
660 GL_BARCODE_FONT_WEIGHT,
661 FALSE, bchar->fsize);
662 gnome_print_setfont (pi->pc, font);
664 gnome_print_setrgbcolor (pi->pc,
665 RED (object->arg.barcode.
667 GREEN (object->arg.barcode.
669 BLUE (object->arg.barcode.
671 gnome_print_setopacity (pi->pc,
672 ALPHA (object->arg.barcode.
676 bchar->y + bchar->fsize -
677 gnome_font_get_descender (font);
678 gnome_print_moveto (pi->pc, x + bchar->x, y + y_offset);
680 cstring = g_strdup_printf ("%c", bchar->c);
681 gnome_print_gsave (pi->pc);
682 gnome_print_scale (pi->pc, 1.0, -1.0);
683 gnome_print_show (pi->pc, cstring);
684 gnome_print_grestore (pi->pc);
689 gl_barcode_free (&gbc);
695 /*---------------------------------------------------------------------------*/
696 /* PRIVATE. Draw outline. */
697 /*---------------------------------------------------------------------------*/
699 draw_outline (PrintInfo * pi,
705 gnome_print_setrgbcolor (pi->pc, 0.25, 0.25, 0.25);
706 gnome_print_setopacity (pi->pc, 1.0);
707 gnome_print_setlinewidth (pi->pc, 0.25);
709 switch (label->template->style) {
711 case GL_TEMPLATE_STYLE_RECT:
714 r = label->template->label_round;
716 /* simple rectangle */
717 create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
719 /* rectangle with rounded corners */
720 create_rounded_rectangle_path (pi->pc, 0.0, 0.0,
723 gnome_print_stroke (pi->pc);
726 case GL_TEMPLATE_STYLE_ROUND:
728 r1 = label->template->label_radius;
729 create_ellipse_path (pi->pc, r1, r1, r1, r1);
730 gnome_print_stroke (pi->pc);
733 case GL_TEMPLATE_STYLE_CD:
734 /* CD style, round label w/ concentric round hole */
735 r1 = label->template->label_radius;
736 r2 = label->template->label_hole;
737 create_ellipse_path (pi->pc, r1, r1, r1, r1);
738 gnome_print_stroke (pi->pc);
739 create_ellipse_path (pi->pc, r1, r1, r2, r2);
740 gnome_print_stroke (pi->pc);
744 WARN ("Unknown template label style");
751 /*---------------------------------------------------------------------------*/
752 /* PRIVATE. Clip to outline. */
753 /*---------------------------------------------------------------------------*/
755 clip_to_outline (PrintInfo * pi,
761 switch (label->template->style) {
763 case GL_TEMPLATE_STYLE_RECT:
766 r = label->template->label_round;
768 /* simple rectangle */
769 create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
771 /* rectangle with rounded corners */
772 create_rounded_rectangle_path (pi->pc, 0.0, 0.0,
775 gnome_print_clip (pi->pc);
778 case GL_TEMPLATE_STYLE_ROUND:
779 case GL_TEMPLATE_STYLE_CD:
780 r1 = label->template->label_radius;
781 create_ellipse_path (pi->pc, r1, r1, r1, r1);
782 gnome_print_clip (pi->pc);
786 WARN ("Unknown template label style");
793 /*---------------------------------------------------------------------------*/
794 /* PRIVATE. Path creation utilities. */
795 /*---------------------------------------------------------------------------*/
797 create_rectangle_path (GnomePrintContext * pc,
803 gnome_print_newpath (pc);
804 gnome_print_moveto (pc, x0, y0);
805 gnome_print_lineto (pc, x0 + w, y0);
806 gnome_print_lineto (pc, x0 + w, y0 + h);
807 gnome_print_lineto (pc, x0, y0 + h);
808 gnome_print_lineto (pc, x0, y0);
809 gnome_print_closepath (pc);
813 create_ellipse_path (GnomePrintContext * pc,
822 gnome_print_newpath (pc);
823 gnome_print_moveto (pc, x0 + rx, y0);
824 for (i_theta = 2; i_theta <= 360; i_theta += 2) {
825 x = x0 + rx * cos (i_theta * M_PI / 180.0);
826 y = y0 + ry * sin (i_theta * M_PI / 180.0);
827 gnome_print_lineto (pc, x, y);
829 gnome_print_closepath (pc);
833 create_rounded_rectangle_path (GnomePrintContext * pc,
843 gnome_print_newpath (pc);
845 gnome_print_moveto (pc, x0 + r, y0);
846 for (i_theta = 5; i_theta <= 90; i_theta += 5) {
847 x = x0 + r - r * sin (i_theta * M_PI / 180.0);
848 y = y0 + r - r * cos (i_theta * M_PI / 180.0);
849 gnome_print_lineto (pc, x, y);
851 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
852 x = x0 + r - r * cos (i_theta * M_PI / 180.0);
853 y = y0 + (h - r) + r * sin (i_theta * M_PI / 180.0);
854 gnome_print_lineto (pc, x, y);
856 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
857 x = x0 + (w - r) + r * sin (i_theta * M_PI / 180.0);
858 y = y0 + (h - r) + r * cos (i_theta * M_PI / 180.0);
859 gnome_print_lineto (pc, x, y);
861 for (i_theta = 0; i_theta <= 90; i_theta += 5) {
862 x = x0 + (w - r) + r * cos (i_theta * M_PI / 180.0);
863 y = y0 + r - r * sin (i_theta * M_PI / 180.0);
864 gnome_print_lineto (pc, x, y);
866 gnome_print_lineto (pc, x0 + r, y0);
868 gnome_print_closepath (pc);