]> git.sur5r.net Git - glabels/blob - glabels2/src/print.c
In clip_punchouts(), center hole correctly on business card CDs.
[glabels] / glabels2 / src / print.c
1 /*
2  *  (GLABELS) Label and Business Card Creation program for GNOME
3  *
4  *  print.c:  Print module
5  *
6  *  Copyright (C) 2001  Jim Evins <evins@snaught.com>.
7  *
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.
12  *
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.
17  *
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
21  */
22 #include <config.h>
23
24 #include <math.h>
25 #include <time.h>
26 #include <ctype.h>
27 #include <gtk/gtk.h>
28
29 #include "print.h"
30 #include "label.h"
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"
37 #include "bc.h"
38 #include "template.h"
39 #include "color.h"
40
41 #include "debug.h"
42
43 #define ARC_FINE   2  /* Resolution in degrees of large arcs */
44 #define ARC_COURSE 5  /* Resolution in degrees of small arcs */
45
46 /*=========================================================================*/
47 /* Private types.                                                          */
48 /*=========================================================================*/
49
50 typedef struct _PrintInfo {
51         /* gnome print context */
52         GnomePrintContext *pc;
53
54         /* gnome print configuration */
55         GnomePrintConfig *config;
56
57         /* gLabels Template */
58         glTemplate *template;
59         gboolean label_rotate_flag;
60
61         /* page size */
62         gdouble page_width;
63         gdouble page_height;
64
65         /* page counter */
66         gint sheet;
67 } PrintInfo;
68
69
70 /*=========================================================================*/
71 /* Private function prototypes.                                            */
72 /*=========================================================================*/
73 static PrintInfo *print_info_new              (GnomePrintJob    *job,
74                                                glLabel          *label);
75
76 static void       print_info_free             (PrintInfo       **pi);
77
78
79 static void       print_page_begin            (PrintInfo        *pi);
80
81 static void       print_page_end              (PrintInfo        *pi);
82
83 static void       print_label                 (PrintInfo        *pi,
84                                                glLabel          *label,
85                                                gdouble           x,
86                                                gdouble           y,
87                                                glMergeRecord    *record,
88                                                gboolean          outline_flag,
89                                                gboolean          reverse_flag);
90
91
92 static void       draw_label                  (PrintInfo        *pi,
93                                                glLabel          *label,
94                                                glMergeRecord    *record);
95
96
97 static void       draw_object                 (PrintInfo        *pi,
98                                                glLabelObject    *object,
99                                                glMergeRecord    *record);
100
101 static void       draw_text_object            (PrintInfo        *pi,
102                                                glLabelText      *object,
103                                                glMergeRecord    *record);
104
105 static void       draw_box_object             (PrintInfo        *pi,
106                                                glLabelBox       *object);
107
108 static void       draw_line_object            (PrintInfo        *pi,
109                                                glLabelLine      *object);
110
111 static void       draw_ellipse_object         (PrintInfo        *pi,
112                                                glLabelEllipse   *object);
113
114 static void       draw_image_object           (PrintInfo        *pi,
115                                                glLabelImage     *object,
116                                                glMergeRecord    *record);
117
118 static void       draw_barcode_object         (PrintInfo        *pi,
119                                                glLabelBarcode   *object,
120                                                glMergeRecord    *record);
121
122
123 static void       draw_outline                (PrintInfo        *pi,
124                                                glLabel          *label);
125
126 static void       clip_to_outline             (PrintInfo        *pi,
127                                                glLabel          *label);
128
129 static void       clip_punchouts              (PrintInfo        *pi,
130                                                glLabel          *label);
131
132
133 static void       create_rectangle_path         (GnomePrintContext *pc,
134                                                  gdouble            x0,
135                                                  gdouble            y0,
136                                                  gdouble            w,
137                                                  gdouble            h);
138
139 static void       create_ellipse_path           (GnomePrintContext *pc,
140                                                  gdouble            x0,
141                                                  gdouble            y0,
142                                                  gdouble            rx,
143                                                  gdouble            ry);
144
145 static void       create_rounded_rectangle_path (GnomePrintContext *pc,
146                                                  gdouble            x0,
147                                                  gdouble            y0,
148                                                  gdouble            w,
149                                                  gdouble            h,
150                                                  gdouble            r);
151
152 static void       create_clipped_circle_path    (GnomePrintContext *pc,
153                                                  gdouble            x0,
154                                                  gdouble            y0,
155                                                  gdouble            w,
156                                                  gdouble            h,
157                                                  gdouble            r);
158
159 \f
160 /*****************************************************************************/
161 /* Simple (no merge data) print command.                                     */
162 /*****************************************************************************/
163 void
164 gl_print_simple (GnomePrintJob    *job,
165                  glLabel          *label,
166                  gint              n_sheets,
167                  gint              first,
168                  gint              last,
169                  gboolean          outline_flag,
170                  gboolean          reverse_flag)
171 {
172         PrintInfo *pi;
173         gint i_sheet, i_label;
174         glTemplateOrigin *origins;
175
176         gl_debug (DEBUG_PRINT, "START");
177
178         pi = print_info_new (job, label);
179
180         origins = gl_template_get_origins (pi->template);
181
182         for (i_sheet = 0; i_sheet < n_sheets; i_sheet++) {
183
184                 print_page_begin (pi);
185
186                 for (i_label = first - 1; i_label < last; i_label++) {
187
188                         print_label (pi, label,
189                                      origins[i_label].x, origins[i_label].y,
190                                      NULL, outline_flag, reverse_flag);
191
192                 }
193
194                 print_page_end (pi);
195         }
196
197         g_free (origins);
198
199         print_info_free (&pi);
200
201         gl_debug (DEBUG_PRINT, "END");
202 }
203
204 /*****************************************************************************/
205 /* Merge print command (collated copies)                                     */
206 /*****************************************************************************/
207 void
208 gl_print_merge_collated (GnomePrintJob    *job,
209                          glLabel          *label,
210                          gint              n_copies,
211                          gint              first,
212                          gboolean          outline_flag,
213                          gboolean          reverse_flag)
214 {
215         glMerge                *merge;
216         const GList            *record_list;
217         PrintInfo              *pi;
218         gint                    i_sheet, i_label, n_labels_per_page, i_copy;
219         glMergeRecord          *record;
220         GList                  *p;
221         glTemplateOrigin       *origins;
222
223         gl_debug (DEBUG_PRINT, "START");
224
225         merge = gl_label_get_merge (label);
226         record_list = gl_merge_get_record_list (merge);
227
228         pi = print_info_new (job, label);
229
230         n_labels_per_page = gl_template_get_n_labels (pi->template);
231         origins = gl_template_get_origins (pi->template);
232
233         i_sheet = 0;
234         i_label = first - 1;
235
236         for ( p=(GList *)record_list; p!=NULL; p=p->next ) {
237                 record = (glMergeRecord *)p->data;
238                         
239                 if ( record->select_flag ) {
240                         for (i_copy = 0; i_copy < n_copies; i_copy++) {
241
242                                 if ((i_label == 0) || (i_sheet == 0)) {
243                                         i_sheet++;
244                                         print_page_begin (pi);
245                                 }
246
247                                 print_label (pi, label,
248                                              origins[i_label].x,
249                                              origins[i_label].y,
250                                              record,
251                                              outline_flag, reverse_flag);
252
253                                 i_label = (i_label + 1) % n_labels_per_page;
254                                 if (i_label == 0) {
255                                         print_page_end (pi);
256                                 }
257                         }
258                 }
259         }
260
261         if (i_label != 0) {
262                 print_page_end (pi);
263         }
264
265         g_free (origins);
266
267         print_info_free (&pi);
268
269         gl_debug (DEBUG_PRINT, "END");
270 }
271
272 /*****************************************************************************/
273 /* Merge print command (uncollated copies)                                   */
274 /*****************************************************************************/
275 void
276 gl_print_merge_uncollated (GnomePrintJob    *job,
277                            glLabel          *label,
278                            gint              n_copies,
279                            gint              first,
280                            gboolean          outline_flag,
281                            gboolean          reverse_flag)
282 {
283         glMerge                *merge;
284         const GList            *record_list;
285         PrintInfo              *pi;
286         gint                    i_sheet, i_label, n_labels_per_page, i_copy;
287         glMergeRecord          *record;
288         GList                  *p;
289         glTemplateOrigin       *origins;
290
291         gl_debug (DEBUG_PRINT, "START");
292
293         merge = gl_label_get_merge (label);
294         record_list = gl_merge_get_record_list (merge);
295
296         pi = print_info_new (job, label);
297
298         n_labels_per_page = gl_template_get_n_labels (pi->template);
299         origins = gl_template_get_origins (pi->template);
300
301         i_sheet = 0;
302         i_label = first - 1;
303
304         for (i_copy = 0; i_copy < n_copies; i_copy++) {
305
306                 for ( p=(GList *)record_list; p!=NULL; p=p->next ) {
307                         record = (glMergeRecord *)p->data;
308                         
309                         if ( record->select_flag ) {
310
311
312                                 if ((i_label == 0) || (i_sheet == 0)) {
313                                         i_sheet++;
314                                         print_page_begin (pi);
315                                 }
316
317                                 print_label (pi, label,
318                                              origins[i_label].x,
319                                              origins[i_label].y,
320                                              record,
321                                              outline_flag, reverse_flag);
322
323                                 i_label = (i_label + 1) % n_labels_per_page;
324                                 if (i_label == 0) {
325                                         print_page_end (pi);
326                                 }
327                         }
328                 }
329
330         }
331         if (i_label != 0) {
332                 print_page_end (pi);
333         }
334
335         g_free (origins);
336
337         print_info_free (&pi);
338
339         gl_debug (DEBUG_PRINT, "END");
340 }
341
342 /*****************************************************************************/
343 /* Batch print.  Call appropriate function above.                            */
344 /*****************************************************************************/
345 void
346 gl_print_batch (GnomePrintJob    *job,
347                 glLabel          *label,
348                 gint              n_sheets,
349                 gint              n_copies,
350                 gboolean          outline_flag,
351                 gboolean          reverse_flag)
352 {
353         gint n_per_page;
354         glMerge *merge;
355         glTemplate *template;
356         
357         gl_debug (DEBUG_PRINT, "START");
358
359         merge = gl_label_get_merge (label);
360         template = gl_label_get_template (label);
361
362         if ( merge == NULL ) {
363                 n_per_page = gl_template_get_n_labels(template);
364
365                 gl_print_simple (job, label, n_sheets, 1, n_per_page,
366                                  outline_flag, reverse_flag);
367         } else {
368                 gl_print_merge_collated (job, label, n_copies, 1,
369                                          outline_flag, reverse_flag);
370         }
371         gl_template_free (&template);
372
373         g_object_unref (G_OBJECT(merge));
374
375         gl_debug (DEBUG_PRINT, "END");
376 }
377
378 /*---------------------------------------------------------------------------*/
379 /* PRIVATE.  new print info structure                                        */
380 /*---------------------------------------------------------------------------*/
381 static PrintInfo *
382 print_info_new (GnomePrintJob    *job,
383                 glLabel          *label)
384 {
385         PrintInfo            *pi = g_new0 (PrintInfo, 1);
386         glTemplate           *template;
387
388         gl_debug (DEBUG_PRINT, "START");
389
390         g_return_val_if_fail (job && GNOME_IS_PRINT_JOB (job), NULL);
391         g_return_val_if_fail (label && GL_IS_LABEL (label), NULL);
392
393         template = gl_label_get_template (label);
394
395         g_return_val_if_fail (template, NULL);
396         g_return_val_if_fail (template->page_size, NULL);
397         g_return_val_if_fail (template->page_width > 0, NULL);
398         g_return_val_if_fail (template->page_height > 0, NULL);
399
400         pi->pc = gnome_print_job_get_context (job);
401         pi->config = gnome_print_job_get_config (job);
402
403         gl_debug (DEBUG_PRINT,
404                   "setting page size = \"%s\"", template->page_size);
405
406         gnome_print_config_set_length (pi->config,
407                                        GNOME_PRINT_KEY_PAPER_WIDTH,
408                                        template->page_width,
409                                        GNOME_PRINT_PS_UNIT);
410         gnome_print_config_set_length (pi->config,
411                                        GNOME_PRINT_KEY_PAPER_HEIGHT,
412                                        template->page_height,
413                                        GNOME_PRINT_PS_UNIT);
414
415         pi->page_width  = template->page_width;
416         pi->page_height = template->page_height;
417
418         pi->template = template;
419         pi->label_rotate_flag = gl_label_get_rotate_flag (label);
420
421         pi->sheet = 0;
422
423         gl_debug (DEBUG_PRINT, "END");
424
425         return pi;
426 }
427
428 /*---------------------------------------------------------------------------*/
429 /* PRIVATE.  free print info structure                                       */
430 /*---------------------------------------------------------------------------*/
431 static void
432 print_info_free (PrintInfo **pi)
433 {
434         gl_debug (DEBUG_PRINT, "START");
435
436         gl_template_free (&(*pi)->template);
437
438         gnome_print_context_close ((*pi)->pc);
439
440         g_free (*pi);
441         *pi = NULL;
442
443         gl_debug (DEBUG_PRINT, "END");
444 }
445
446 /*---------------------------------------------------------------------------*/
447 /* PRIVATE.  Begin a new page.                                               */
448 /*---------------------------------------------------------------------------*/
449 static void
450 print_page_begin (PrintInfo *pi)
451 {
452         gchar *str;
453
454         gl_debug (DEBUG_PRINT, "START");
455
456         pi->sheet++;
457
458         str = g_strdup_printf ("sheet%02d", pi->sheet);
459         gnome_print_beginpage (pi->pc, str);
460         g_free (str);
461
462         /* Translate and scale, so that our origin is at the upper left. */
463         gnome_print_translate (pi->pc, 0.0, pi->page_height);
464         gnome_print_scale (pi->pc, 1.0, -1.0);
465
466         gl_debug (DEBUG_PRINT, "END");
467 }
468
469 /*---------------------------------------------------------------------------*/
470 /* PRIVATE.  End a page.                                                     */
471 /*---------------------------------------------------------------------------*/
472 static void
473 print_page_end (PrintInfo *pi)
474 {
475         gl_debug (DEBUG_PRINT, "START");
476
477         gnome_print_showpage (pi->pc);
478
479         gl_debug (DEBUG_PRINT, "END");
480 }
481
482 /*---------------------------------------------------------------------------*/
483 /* PRIVATE.  Print i'th label.                                               */
484 /*---------------------------------------------------------------------------*/
485 static void
486 print_label (PrintInfo     *pi,
487              glLabel       *label,
488              gdouble        x,
489              gdouble        y,
490              glMergeRecord *record,
491              gboolean       outline_flag,
492              gboolean       reverse_flag)
493 {
494         gdouble width, height;
495         glTemplate *template;
496
497         gl_debug (DEBUG_PRINT, "START");
498
499         template = gl_label_get_template (label);
500
501         gl_label_get_size (label, &width, &height);
502
503         gnome_print_gsave (pi->pc);
504
505         /* Transform coordinate system to be relative to upper corner */
506         /* of the current label */
507         gnome_print_translate (pi->pc, x, y);
508         if (gl_label_get_rotate_flag (label)) {
509                 gl_debug (DEBUG_PRINT, "Rotate flag set");
510                 gnome_print_rotate (pi->pc, -90.0);
511                 gnome_print_translate (pi->pc, -width, 0.0);
512         }
513         if ( reverse_flag ) {
514                 gnome_print_translate (pi->pc, width, 0.0);
515                 gnome_print_scale (pi->pc, -1.0, 1.0);
516         }
517
518         clip_to_outline (pi, label);
519         draw_label (pi, label, record);
520         if (outline_flag) {
521                 draw_outline (pi, label);
522         }
523         clip_punchouts (pi, label);
524
525         gnome_print_grestore (pi->pc);
526
527         gl_template_free (&template);
528
529         gl_debug (DEBUG_PRINT, "END");
530 }
531
532 /*---------------------------------------------------------------------------*/
533 /* PRIVATE.  Draw label.                                                     */
534 /*---------------------------------------------------------------------------*/
535 static void
536 draw_label (PrintInfo     *pi,
537             glLabel       *label,
538             glMergeRecord *record)
539 {
540         GList *p_obj;
541         glLabelObject *object;
542
543         gl_debug (DEBUG_PRINT, "START");
544
545         for (p_obj = label->objects; p_obj != NULL; p_obj = p_obj->next) {
546                 object = (glLabelObject *) p_obj->data;
547
548                 draw_object (pi, object, record);
549         }
550
551         gl_debug (DEBUG_PRINT, "END");
552 }
553
554 /*---------------------------------------------------------------------------*/
555 /* PRIVATE.  Draw object.                                                    */
556 /*---------------------------------------------------------------------------*/
557 static void
558 draw_object (PrintInfo     *pi,
559              glLabelObject *object,
560              glMergeRecord *record)
561 {
562         gdouble x0, y0;
563         gdouble affine[6];
564
565         gl_debug (DEBUG_PRINT, "START");
566
567         gl_label_object_get_position (object, &x0, &y0);
568         gl_label_object_get_affine (object, affine);
569
570         gnome_print_gsave (pi->pc);
571
572         gnome_print_translate (pi->pc, x0, y0);
573         gnome_print_concat (pi->pc, affine);
574
575         if (GL_IS_LABEL_TEXT(object)) {
576                 draw_text_object (pi, GL_LABEL_TEXT(object), record);
577         } else if (GL_IS_LABEL_BOX(object)) {
578                 draw_box_object (pi, GL_LABEL_BOX(object));
579         } else if (GL_IS_LABEL_LINE(object)) {
580                 draw_line_object (pi, GL_LABEL_LINE(object));
581         } else if (GL_IS_LABEL_ELLIPSE(object)) {
582                 draw_ellipse_object (pi, GL_LABEL_ELLIPSE(object));
583         } else if (GL_IS_LABEL_IMAGE(object)) {
584                 draw_image_object (pi, GL_LABEL_IMAGE(object), record);
585         } else if (GL_IS_LABEL_BARCODE(object)) {
586                 draw_barcode_object (pi, GL_LABEL_BARCODE(object), record);
587         }
588
589         gnome_print_grestore (pi->pc);
590
591         gl_debug (DEBUG_PRINT, "END");
592 }
593
594 /*---------------------------------------------------------------------------*/
595 /* PRIVATE.  Draw text object.                                               */
596 /*---------------------------------------------------------------------------*/
597 static void
598 draw_text_object (PrintInfo     *pi,
599                   glLabelText   *object,
600                   glMergeRecord *record)
601 {
602         GnomeFont *font;
603         gchar **line;
604         gint i;
605         gdouble x_offset, y_offset, w, object_w, object_h;
606         gchar *text;
607         GList *lines;
608         gchar *font_family;
609         gdouble font_size;
610         GnomeFontWeight font_weight;
611         gboolean font_italic_flag;
612         guint color;
613         GtkJustification just;
614         GnomeGlyphList *glyphlist;
615         ArtDRect bbox;
616         gdouble affine[6];
617
618
619         gl_debug (DEBUG_PRINT, "START");
620
621         gl_label_object_get_size (GL_LABEL_OBJECT(object), &object_w, &object_h);
622         lines = gl_label_text_get_lines (object);
623         gl_label_text_get_props (object,
624                                  &font_family, &font_size, &font_weight,
625                                  &font_italic_flag,
626                                  &color, &just);
627
628         font = gnome_font_find_closest_from_weight_slant (
629                                        font_family,
630                                        font_weight,
631                                        font_italic_flag,
632                                        font_size);
633         gnome_print_setfont (pi->pc, font);
634
635         gnome_print_setrgbcolor (pi->pc,
636                                  GL_COLOR_F_RED (color),
637                                  GL_COLOR_F_GREEN (color),
638                                  GL_COLOR_F_BLUE (color));
639         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (color));
640
641         text = gl_text_node_lines_expand (lines, record);
642         line = g_strsplit (text, "\n", -1);
643         g_free (text);
644
645         art_affine_identity (affine);
646
647         for (i = 0; line[i] != NULL; i++) {
648
649                 glyphlist = gnome_glyphlist_from_text_dumb (font, color,
650                                                             0.0, 0.0,
651                                                             line[i]);
652
653                 gnome_glyphlist_bbox (glyphlist, affine, 0, &bbox);
654                 w = bbox.x1;
655
656                 switch (just) {
657                 case GTK_JUSTIFY_LEFT:
658                         x_offset = GL_LABEL_TEXT_MARGIN;
659                         break;
660                 case GTK_JUSTIFY_CENTER:
661                         x_offset = (object_w - GL_LABEL_TEXT_MARGIN - w) / 2.0;
662                         break;
663                 case GTK_JUSTIFY_RIGHT:
664                         x_offset = object_w - GL_LABEL_TEXT_MARGIN - w;
665                         break;
666                 default:
667                         x_offset = 0.0;
668                         break;  /* shouldn't happen */
669                 }
670
671                 y_offset = GL_LABEL_TEXT_MARGIN + (i + 1) * font_size
672                         + gnome_font_get_descender (font);
673
674                 gnome_print_moveto (pi->pc, x_offset, y_offset);
675
676                 gnome_print_gsave (pi->pc);
677                 gnome_print_scale (pi->pc, 1.0, -1.0);
678                 gnome_print_show (pi->pc, line[i]);
679                 gnome_print_grestore (pi->pc);
680         }
681
682         g_strfreev (line);
683
684         gl_text_node_lines_free (&lines);
685         g_free (font_family);
686
687         gl_debug (DEBUG_PRINT, "END");
688 }
689
690 /*---------------------------------------------------------------------------*/
691 /* PRIVATE.  Draw box object.                                                */
692 /*---------------------------------------------------------------------------*/
693 static void
694 draw_box_object (PrintInfo  *pi,
695                  glLabelBox *object)
696 {
697         gdouble w, h;
698         gdouble line_width;
699         guint line_color, fill_color;
700
701         gl_debug (DEBUG_PRINT, "START");
702
703         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
704         line_width = gl_label_box_get_line_width (object);
705         line_color = gl_label_box_get_line_color (object);
706         fill_color = gl_label_box_get_fill_color (object);
707
708         /* Paint fill color */
709         create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
710         gnome_print_setrgbcolor (pi->pc,
711                                  GL_COLOR_F_RED (fill_color),
712                                  GL_COLOR_F_GREEN (fill_color),
713                                  GL_COLOR_F_BLUE (fill_color));
714         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (fill_color));
715         gnome_print_fill (pi->pc);
716
717         /* Draw outline */
718         create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
719         gnome_print_setrgbcolor (pi->pc,
720                                  GL_COLOR_F_RED (line_color),
721                                  GL_COLOR_F_GREEN (line_color),
722                                  GL_COLOR_F_BLUE (line_color));
723         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
724         gnome_print_setlinewidth (pi->pc, line_width);
725         gnome_print_stroke (pi->pc);
726
727         gl_debug (DEBUG_PRINT, "END");
728 }
729
730 /*---------------------------------------------------------------------------*/
731 /* PRIVATE.  Draw line object.                                               */
732 /*---------------------------------------------------------------------------*/
733 static void
734 draw_line_object (PrintInfo   *pi,
735                   glLabelLine *object)
736 {
737         gdouble w, h;
738         gdouble line_width;
739         guint line_color;
740
741         gl_debug (DEBUG_PRINT, "START");
742
743         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
744         line_width = gl_label_line_get_line_width (object);
745         line_color = gl_label_line_get_line_color (object);
746
747         gnome_print_moveto (pi->pc, 0.0, 0.0);
748         gnome_print_lineto (pi->pc, w, h);
749         gnome_print_setrgbcolor (pi->pc,
750                                  GL_COLOR_F_RED (line_color),
751                                  GL_COLOR_F_GREEN (line_color),
752                                  GL_COLOR_F_BLUE (line_color));
753         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
754         gnome_print_setlinewidth (pi->pc, line_width);
755         gnome_print_stroke (pi->pc);
756
757         gl_debug (DEBUG_PRINT, "END");
758 }
759
760 /*---------------------------------------------------------------------------*/
761 /* PRIVATE.  Draw ellipse object.                                            */
762 /*---------------------------------------------------------------------------*/
763 static void
764 draw_ellipse_object (PrintInfo      *pi,
765                      glLabelEllipse *object)
766 {
767         gdouble x0, y0, rx, ry, w, h;
768         gdouble line_width;
769         guint line_color, fill_color;
770
771         gl_debug (DEBUG_PRINT, "START");
772
773         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
774         line_width = gl_label_ellipse_get_line_width (object);
775         line_color = gl_label_ellipse_get_line_color (object);
776         fill_color = gl_label_ellipse_get_fill_color (object);
777
778         rx = w / 2.0;
779         ry = h / 2.0;
780         x0 = rx;
781         y0 = ry;
782
783         /* Paint fill color */
784         create_ellipse_path (pi->pc, x0, y0, rx, ry);
785         gnome_print_setrgbcolor (pi->pc,
786                                  GL_COLOR_F_RED (fill_color),
787                                  GL_COLOR_F_GREEN (fill_color),
788                                  GL_COLOR_F_BLUE (fill_color));
789         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (fill_color));
790         gnome_print_fill (pi->pc);
791
792         /* Draw outline */
793         create_ellipse_path (pi->pc, x0, y0, rx, ry);
794         gnome_print_setrgbcolor (pi->pc,
795                                  GL_COLOR_F_RED (line_color),
796                                  GL_COLOR_F_GREEN (line_color),
797                                  GL_COLOR_F_BLUE (line_color));
798         gnome_print_setopacity (pi->pc, GL_COLOR_F_ALPHA (line_color));
799         gnome_print_setlinewidth (pi->pc, line_width);
800         gnome_print_stroke (pi->pc);
801
802         gl_debug (DEBUG_PRINT, "END");
803 }
804
805 /*---------------------------------------------------------------------------*/
806 /* PRIVATE.  Draw image object.                                              */
807 /*---------------------------------------------------------------------------*/
808 static void
809 draw_image_object (PrintInfo     *pi,
810                    glLabelImage  *object,
811                    glMergeRecord *record)
812 {
813         gdouble w, h;
814         const GdkPixbuf *pixbuf;
815         guchar *image_data;
816         gint image_w, image_h, image_stride;
817         gboolean image_alpha_flag;
818         gint ret;
819
820         gl_debug (DEBUG_PRINT, "START");
821
822         gl_label_object_get_size     (GL_LABEL_OBJECT(object), &w, &h);
823
824         pixbuf = gl_label_image_get_pixbuf (object, record);
825         image_data = gdk_pixbuf_get_pixels (pixbuf);
826         image_w = gdk_pixbuf_get_width (pixbuf);
827         image_h = gdk_pixbuf_get_height (pixbuf);
828         image_stride = gdk_pixbuf_get_rowstride(pixbuf);
829         image_alpha_flag = gdk_pixbuf_get_has_alpha(pixbuf);
830
831         gnome_print_gsave (pi->pc);
832         gnome_print_translate (pi->pc, 0.0, h);
833         gnome_print_scale (pi->pc, w, -h);
834         if (image_alpha_flag) {
835                 ret = gnome_print_rgbaimage (pi->pc, image_data,
836                                              image_w, image_h, image_stride);
837                 gl_debug (DEBUG_PRINT, "Ret a = %d", ret);
838         } else {
839                 ret = gnome_print_rgbimage (pi->pc, image_data,
840                                             image_w, image_h, image_stride);
841                 gl_debug (DEBUG_PRINT, "Ret = %d", ret);
842         }
843         gnome_print_grestore (pi->pc);
844
845         gl_debug (DEBUG_PRINT, "END");
846 }
847
848 /*---------------------------------------------------------------------------*/
849 /* PRIVATE.  Draw box object.                                                */
850 /*---------------------------------------------------------------------------*/
851 static void
852 draw_barcode_object (PrintInfo      *pi,
853                      glLabelBarcode *object,
854                      glMergeRecord  *record)
855 {
856         glBarcode *gbc;
857         glBarcodeLine *line;
858         glBarcodeChar *bchar;
859         GList *li;
860         gdouble y_offset;
861         GnomeFont *font;
862         gchar *text, *cstring;
863         glTextNode          *text_node;
864         glBarcodeStyle      style;
865         gboolean            text_flag;
866         gboolean            checksum_flag;
867         guint               color;
868         gdouble             w, h;
869
870         gl_debug (DEBUG_PRINT, "START");
871
872         text_node = gl_label_barcode_get_data (object);
873         gl_label_barcode_get_props (object,
874                                     &style, &text_flag, &checksum_flag, &color);
875         gl_label_object_get_size (GL_LABEL_OBJECT(object), &w, &h);
876
877         text = gl_text_node_expand (text_node, record);
878         gbc = gl_barcode_new (style, text_flag, checksum_flag, w, h, text);
879         g_free (text);
880         gl_text_node_free (&text_node);
881
882         if (gbc == NULL) {
883
884                 font = gnome_font_find_closest_from_weight_slant (
885                                                GL_BARCODE_FONT_FAMILY,
886                                                GL_BARCODE_FONT_WEIGHT,
887                                                FALSE, 12.0);
888                 gnome_print_setfont (pi->pc, font);
889
890                 gnome_print_setrgbcolor (pi->pc,
891                                          GL_COLOR_F_RED (color),
892                                          GL_COLOR_F_GREEN (color),
893                                          GL_COLOR_F_BLUE (color));
894                 gnome_print_setopacity (pi->pc,
895                                         GL_COLOR_F_ALPHA (color));
896
897                 y_offset = 12.0 - gnome_font_get_descender (font);
898                 gnome_print_moveto (pi->pc, 0.0, y_offset);
899
900                 gnome_print_gsave (pi->pc);
901                 gnome_print_scale (pi->pc, 1.0, -1.0);
902                 gnome_print_show (pi->pc, _("Invalid barcode"));
903                 gnome_print_grestore (pi->pc);
904
905         } else {
906
907                 for (li = gbc->lines; li != NULL; li = li->next) {
908                         line = (glBarcodeLine *) li->data;
909
910                         gnome_print_moveto (pi->pc, line->x, line->y);
911                         gnome_print_lineto (pi->pc, line->x, line->y + line->length);
912                         gnome_print_setrgbcolor (pi->pc,
913                                                  GL_COLOR_F_RED (color),
914                                                  GL_COLOR_F_GREEN (color),
915                                                  GL_COLOR_F_BLUE (color));
916                         gnome_print_setopacity (pi->pc,
917                                                 GL_COLOR_F_ALPHA (color));
918                         gnome_print_setlinewidth (pi->pc, line->width);
919                         gnome_print_stroke (pi->pc);
920                 }
921
922                 for (li = gbc->chars; li != NULL; li = li->next) {
923                         bchar = (glBarcodeChar *) li->data;
924
925                         font = gnome_font_find_closest_from_weight_slant (
926                                                        GL_BARCODE_FONT_FAMILY,
927                                                        GL_BARCODE_FONT_WEIGHT,
928                                                        FALSE, bchar->fsize);
929                         gnome_print_setfont (pi->pc, font);
930
931                         gnome_print_setrgbcolor (pi->pc,
932                                                  GL_COLOR_F_RED (color),
933                                                  GL_COLOR_F_GREEN (color),
934                                                  GL_COLOR_F_BLUE (color));
935                         gnome_print_setopacity (pi->pc,
936                                                 GL_COLOR_F_ALPHA (color));
937
938                         y_offset =
939                             bchar->y + bchar->fsize -
940                             gnome_font_get_descender (font);
941                         gnome_print_moveto (pi->pc, bchar->x, y_offset);
942
943                         cstring = g_strdup_printf ("%c", bchar->c);
944                         gnome_print_gsave (pi->pc);
945                         gnome_print_scale (pi->pc, 1.0, -1.0);
946                         gnome_print_show (pi->pc, cstring);
947                         gnome_print_grestore (pi->pc);
948                         g_free (cstring);
949
950                 }
951
952                 gl_barcode_free (&gbc);
953
954         }
955
956         gl_debug (DEBUG_PRINT, "END");
957 }
958
959 /*---------------------------------------------------------------------------*/
960 /* PRIVATE.  Draw outline.                                                   */
961 /*---------------------------------------------------------------------------*/
962 static void
963 draw_outline (PrintInfo *pi,
964               glLabel   *label)
965 {
966         gdouble w, h, r;
967         gdouble r1, r2;
968         glTemplate *template;
969
970         gl_debug (DEBUG_PRINT, "START");
971
972         template = gl_label_get_template (label);
973
974         gnome_print_setrgbcolor (pi->pc, 0.25, 0.25, 0.25);
975         gnome_print_setopacity (pi->pc, 1.0);
976         gnome_print_setlinewidth (pi->pc, 0.25);
977
978         switch (template->label.style) {
979
980         case GL_TEMPLATE_STYLE_RECT:
981                 gl_label_get_size (label, &w, &h);
982                 r = template->label.rect.r;
983                 if (r == 0.0) {
984                         /* simple rectangle */
985                         create_rectangle_path (pi->pc, 0.0, 0.0, w, h);
986                 } else {
987                         /* rectangle with rounded corners */
988                         create_rounded_rectangle_path (pi->pc, 0.0, 0.0,
989                                                        w, h, r);
990                 }
991                 gnome_print_stroke (pi->pc);
992                 break;
993
994         case GL_TEMPLATE_STYLE_ROUND:
995                 /* Round style */
996                 r1 = template->label.round.r;
997                 create_ellipse_path (pi->pc, r1, r1, r1, r1);
998                 gnome_print_stroke (pi->pc);
999                 break;
1000
1001         case GL_TEMPLATE_STYLE_CD:
1002                 if ((template->label.cd.h == 0) && (template->label.cd.w == 0)) {
1003                         /* CD style, round label w/ concentric round hole */
1004                         r1 = template->label.cd.r1;
1005                         r2 = template->label.cd.r2;
1006                         create_ellipse_path (pi->pc, r1, r1, r1, r1);
1007                         gnome_print_stroke (pi->pc);
1008                         create_ellipse_path (pi->pc, r1, r1, r2, r2);
1009                         gnome_print_stroke (pi->pc);
1010                 } else {
1011                         /* Business Card CD style, clipped round label w/ hole */
1012                         gl_label_get_size (label, &w, &h);
1013                         r1 = template->label.cd.r1;
1014                         r2 = template->label.cd.r2;
1015                         create_clipped_circle_path (pi->pc, w/2, h/2, w, h, r1);
1016                         gnome_print_stroke (pi->pc);
1017                         create_ellipse_path (pi->pc, w/2, h/2, r2, r2);
1018                         gnome_print_stroke (pi->pc);
1019                 }
1020                 break;
1021
1022         default:
1023                 g_warning ("Unknown template label style");
1024                 break;
1025         }
1026
1027         gl_template_free (&template);
1028
1029         gl_debug (DEBUG_PRINT, "END");
1030 }
1031
1032 /*---------------------------------------------------------------------------*/
1033 /* PRIVATE.  Clip to outline.                                                */
1034 /*---------------------------------------------------------------------------*/
1035 static void
1036 clip_to_outline (PrintInfo *pi,
1037                  glLabel   *label)
1038 {
1039         gdouble w, h, r;
1040         gdouble r1;
1041         gdouble waste;
1042         glTemplate *template;
1043
1044         gl_debug (DEBUG_PRINT, "START");
1045
1046         template = gl_label_get_template (label);
1047
1048         switch (template->label.style) {
1049
1050         case GL_TEMPLATE_STYLE_RECT:
1051                 gl_label_get_size (label, &w, &h);
1052                 r = template->label.rect.r;
1053                 waste = template->label.rect.waste;
1054                 if (r == 0.0) {
1055                         /* simple rectangle */
1056                         create_rectangle_path (pi->pc, -waste, -waste, w+waste, h+waste);
1057                 } else {
1058                         /* rectangle with rounded corners */
1059                         create_rounded_rectangle_path (pi->pc, -waste, -waste,
1060                                                        w+waste, h+waste, r);
1061                 }
1062                 gnome_print_clip (pi->pc);
1063                 break;
1064
1065         case GL_TEMPLATE_STYLE_ROUND:
1066                 r1 = template->label.round.r;
1067                 waste = template->label.round.waste;
1068                 create_ellipse_path (pi->pc, r1, r1, r1+waste, r1+waste);
1069                 gnome_print_clip (pi->pc);
1070                 break;
1071
1072         case GL_TEMPLATE_STYLE_CD:
1073                 waste = template->label.cd.waste;
1074                 if ((template->label.cd.h == 0) && (template->label.cd.w == 0)) {
1075                         /* CD style, round label w/ concentric round hole */
1076                         r1 = template->label.cd.r1;
1077                         create_ellipse_path (pi->pc, r1, r1, r1+waste, r1+waste);
1078                 } else {
1079                         /* Business Card CD style, clipped round label w/ hole */
1080                         gl_label_get_size (label, &w, &h);
1081                         r1 = template->label.cd.r1;
1082                         create_clipped_circle_path (pi->pc,
1083                                                     w/2, h/2,
1084                                                     w+2*waste, h+2*waste,
1085                                                     r1+waste);
1086                 }
1087                 gnome_print_clip (pi->pc);
1088                 break;
1089
1090         default:
1091                 g_warning ("Unknown template label style");
1092                 break;
1093         }
1094
1095         gl_template_free (&template);
1096
1097         gl_debug (DEBUG_PRINT, "END");
1098 }
1099
1100 /*---------------------------------------------------------------------------*/
1101 /* PRIVATE.  Clip punchouts.  (Save some ink by not printing in CD holes)    */
1102 /*                                                                           */
1103 /* Ideally this would be done in clip_to_outline, but I am not sure how to   */
1104 /* invert the region for gnome_print_clip, so instead, I will just draw      */
1105 /* a white circle on top of everything else.                                 */
1106 /*---------------------------------------------------------------------------*/
1107 static void
1108 clip_punchouts (PrintInfo *pi,
1109                 glLabel   *label)
1110 {
1111         gdouble w, h, r2;
1112         gdouble waste;
1113         glTemplate *template;
1114
1115         gl_debug (DEBUG_PRINT, "START");
1116
1117         template = gl_label_get_template (label);
1118
1119         switch (template->label.style) {
1120
1121         case GL_TEMPLATE_STYLE_RECT:
1122         case GL_TEMPLATE_STYLE_ROUND:
1123                 break;
1124
1125         case GL_TEMPLATE_STYLE_CD:
1126                 gl_label_get_size (label, &w, &h);
1127                 waste = template->label.cd.waste;
1128                 r2    = template->label.cd.r2;
1129                 create_ellipse_path (pi->pc, w/2, h/2, r2-waste, r2-waste);
1130                 gnome_print_setrgbcolor (pi->pc, 1.0, 1.0, 1.0);
1131                 gnome_print_setopacity (pi->pc, 1.0);
1132                 gnome_print_fill (pi->pc);
1133                 break;
1134
1135         default:
1136                 g_warning ("Unknown template label style");
1137                 break;
1138         }
1139
1140         gl_template_free (&template);
1141
1142         gl_debug (DEBUG_PRINT, "END");
1143 }
1144
1145 /*---------------------------------------------------------------------------*/
1146 /* PRIVATE.  Path creation utilities.                                        */
1147 /*---------------------------------------------------------------------------*/
1148 static void
1149 create_rectangle_path (GnomePrintContext *pc,
1150                        gdouble            x0,
1151                        gdouble            y0,
1152                        gdouble            w,
1153                        gdouble            h)
1154 {
1155         gl_debug (DEBUG_PRINT, "START");
1156
1157         gnome_print_newpath (pc);
1158         gnome_print_moveto (pc, x0, y0);
1159         gnome_print_lineto (pc, x0 + w, y0);
1160         gnome_print_lineto (pc, x0 + w, y0 + h);
1161         gnome_print_lineto (pc, x0, y0 + h);
1162         gnome_print_lineto (pc, x0, y0);
1163         gnome_print_closepath (pc);
1164
1165         gl_debug (DEBUG_PRINT, "END");
1166 }
1167
1168 static void
1169 create_ellipse_path (GnomePrintContext *pc,
1170                      gdouble            x0,
1171                      gdouble            y0,
1172                      gdouble            rx,
1173                      gdouble            ry)
1174 {
1175         gdouble x, y;
1176         gint i_theta;
1177
1178         gl_debug (DEBUG_PRINT, "START");
1179
1180         gnome_print_newpath (pc);
1181         gnome_print_moveto (pc, x0 + rx, y0);
1182         for (i_theta = ARC_FINE; i_theta <= 360; i_theta += ARC_FINE) {
1183                 x = x0 + rx * cos (i_theta * G_PI / 180.0);
1184                 y = y0 + ry * sin (i_theta * G_PI / 180.0);
1185                 gnome_print_lineto (pc, x, y);
1186         }
1187         gnome_print_closepath (pc);
1188
1189         gl_debug (DEBUG_PRINT, "END");
1190 }
1191
1192 static void
1193 create_rounded_rectangle_path (GnomePrintContext *pc,
1194                                gdouble            x0,
1195                                gdouble            y0,
1196                                gdouble            w,
1197                                gdouble            h,
1198                                gdouble            r)
1199 {
1200         gdouble x, y;
1201         gint i_theta;
1202
1203         gl_debug (DEBUG_PRINT, "START");
1204
1205         gnome_print_newpath (pc);
1206
1207         gnome_print_moveto (pc, x0 + r, y0);
1208         for (i_theta = ARC_COURSE; i_theta <= 90; i_theta += ARC_COURSE) {
1209                 x = x0 + r - r * sin (i_theta * G_PI / 180.0);
1210                 y = y0 + r - r * cos (i_theta * G_PI / 180.0);
1211                 gnome_print_lineto (pc, x, y);
1212         }
1213         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1214                 x = x0 + r - r * cos (i_theta * G_PI / 180.0);
1215                 y = y0 + (h - r) + r * sin (i_theta * G_PI / 180.0);
1216                 gnome_print_lineto (pc, x, y);
1217         }
1218         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1219                 x = x0 + (w - r) + r * sin (i_theta * G_PI / 180.0);
1220                 y = y0 + (h - r) + r * cos (i_theta * G_PI / 180.0);
1221                 gnome_print_lineto (pc, x, y);
1222         }
1223         for (i_theta = 0; i_theta <= 90; i_theta += ARC_COURSE) {
1224                 x = x0 + (w - r) + r * cos (i_theta * G_PI / 180.0);
1225                 y = y0 + r - r * sin (i_theta * G_PI / 180.0);
1226                 gnome_print_lineto (pc, x, y);
1227         }
1228         gnome_print_lineto (pc, x0 + r, y0);
1229
1230         gnome_print_closepath (pc);
1231
1232         gl_debug (DEBUG_PRINT, "END");
1233 }
1234
1235 static void
1236 create_clipped_circle_path (GnomePrintContext *pc,
1237                             gdouble            x0,
1238                             gdouble            y0,
1239                             gdouble            w,
1240                             gdouble            h,
1241                             gdouble            r)
1242 {
1243         gdouble x, y;
1244         gdouble theta1, theta2;
1245         gint    i_theta;
1246
1247         gl_debug (DEBUG_PRINT, "START");
1248
1249         theta1 = (180.0/G_PI) * acos (w / (2.0*r));
1250         theta2 = (180.0/G_PI) * asin (h / (2.0*r));
1251
1252         gnome_print_newpath (pc);
1253
1254         x = x0 + r * cos (theta1 * G_PI / 180.0);
1255         y = y0 + r * sin (theta1 * G_PI / 180.0);
1256         gnome_print_moveto (pc, x, y);
1257
1258         for ( i_theta = theta1 + ARC_FINE; i_theta < theta2; i_theta +=ARC_FINE ) {
1259                 x = x0 + r * cos (i_theta * G_PI / 180.0);
1260                 y = y0 + r * sin (i_theta * G_PI / 180.0);
1261                 gnome_print_lineto (pc, x, y);
1262         }
1263
1264         x = x0 + r * cos (theta2 * G_PI / 180.0);
1265         y = y0 + r * sin (theta2 * G_PI / 180.0);
1266         gnome_print_lineto (pc, x, y);
1267
1268         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1269                 x = x0 + r * cos ((180-theta2) * G_PI / 180.0);
1270                 y = y0 + r * sin ((180-theta2) * G_PI / 180.0);
1271                 gnome_print_lineto (pc, x, y);
1272         }
1273
1274         for ( i_theta = 180-theta2+ARC_FINE; i_theta < (180-theta1); i_theta +=ARC_FINE ) {
1275                 x = x0 + r * cos (i_theta * G_PI / 180.0);
1276                 y = y0 + r * sin (i_theta * G_PI / 180.0);
1277                 gnome_print_lineto (pc, x, y);
1278         }
1279
1280         x = x0 + r * cos ((180-theta1) * G_PI / 180.0);
1281         y = y0 + r * sin ((180-theta1) * G_PI / 180.0);
1282         gnome_print_lineto (pc, x, y);
1283
1284         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1285                 x = x0 + r * cos ((180+theta1) * G_PI / 180.0);
1286                 y = y0 + r * sin ((180+theta1) * G_PI / 180.0);
1287                 gnome_print_lineto (pc, x, y);
1288         }
1289
1290         for ( i_theta = 180+theta1+ARC_FINE; i_theta < (180+theta2); i_theta +=ARC_FINE ) {
1291                 x = x0 + r * cos (i_theta * G_PI / 180.0);
1292                 y = y0 + r * sin (i_theta * G_PI / 180.0);
1293                 gnome_print_lineto (pc, x, y);
1294         }
1295
1296         x = x0 + r * cos ((180+theta2) * G_PI / 180.0);
1297         y = y0 + r * sin ((180+theta2) * G_PI / 180.0);
1298         gnome_print_lineto (pc, x, y);
1299
1300         if ( fabs (theta2 - 90.0) > GNOME_CANVAS_EPSILON ) {
1301                 x = x0 + r * cos ((360-theta2) * G_PI / 180.0);
1302                 y = y0 + r * sin ((360-theta2) * G_PI / 180.0);
1303                 gnome_print_lineto (pc, x, y);
1304         }
1305
1306         for ( i_theta = 360-theta2+ARC_FINE; i_theta < (360-theta1); i_theta +=ARC_FINE ) {
1307                 x = x0 + r * cos (i_theta * G_PI / 180.0);
1308                 y = y0 + r * sin (i_theta * G_PI / 180.0);
1309                 gnome_print_lineto (pc, x, y);
1310         }
1311
1312         if ( fabs (theta1) > GNOME_CANVAS_EPSILON ) {
1313                 x = x0 + r * cos ((360-theta1) * G_PI / 180.0);
1314                 y = y0 + r * sin ((360-theta1) * G_PI / 180.0);
1315                 gnome_print_lineto (pc, x, y);
1316         }
1317
1318         x = x0 + r * cos (theta1 * G_PI / 180.0);
1319         y = y0 + r * sin (theta1 * G_PI / 180.0);
1320         gnome_print_lineto (pc, x, y);
1321
1322         gnome_print_closepath (pc);
1323
1324         gl_debug (DEBUG_PRINT, "END");
1325 }
1326