4 * PCB, interactive printed circuit board design
5 * Copyright (C) 2006 Dan McMahill
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Heavily based on the ps HID written by DJ Delorie
45 #include "../hidint.h"
46 #include "hid/common/hidnogui.h"
47 #include "hid/common/draw_helpers.h"
50 /* the gd library which makes this all so easy */
53 #include "hid/common/hidinit.h"
55 #ifdef HAVE_LIBDMALLOC
59 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
62 static HID_DRAW png_graphics
;
63 static HID_DRAW_CLASS png_graphics_class
;
65 static void *color_cache
= NULL
;
66 static void *brush_cache
= NULL
;
68 static double bloat
= 0;
69 static double scale
= 1;
70 static Coord x_shift
= 0;
71 static Coord y_shift
= 0;
72 static int show_bottom_side
;
73 #define SCALE(w) ((int)round((w)/scale))
74 #define SCALE_X(x) ((int)round(((x) - x_shift)/scale))
75 #define SCALE_Y(y) ((int)round(((show_bottom_side ? (PCB->MaxHeight-(y)) : (y)) - y_shift)/scale))
76 #define SWAP_IF_SOLDER(a,b) do { Coord c; if (show_bottom_side) { c=a; a=b; b=c; }} while (0)
78 /* Used to detect non-trivial outlines */
79 #define NOT_EDGE_X(x) ((x) != 0 && (x) != PCB->MaxWidth)
80 #define NOT_EDGE_Y(y) ((y) != 0 && (y) != PCB->MaxHeight)
81 #define NOT_EDGE(x,y) (NOT_EDGE_X(x) || NOT_EDGE_Y(y))
83 static void png_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
85 /* The result of a failed gdImageColorAllocate() call */
88 typedef struct color_struct
90 /* the descriptor used by the gd library */
93 /* so I can figure out what rgb value c refers to */
94 unsigned int r
, g
, b
, a
;
98 typedef struct png_gc_struct
100 struct hid_gc_struct hid_gc
; /* Parent */
104 unsigned char r
, g
, b
;
110 static color_struct
*black
= NULL
, *white
= NULL
;
111 static gdImagePtr im
= NULL
, master_im
, mask_im
= NULL
;
113 static int linewidth
= -1;
114 static int lastgroup
= -1;
115 static gdImagePtr lastbrush
= (gdImagePtr
)((void *) -1);
116 static int lastcap
= -1;
117 static int print_group
[MAX_GROUP
];
118 static int print_layer
[MAX_LAYER
];
120 /* For photo-mode we need the following layers as monochrome masks:
128 #define PHOTO_FLIP_X 1
129 #define PHOTO_FLIP_Y 2
131 static int photo_mode
, photo_flip
;
132 static gdImagePtr photo_copper
[MAX_LAYER
+2];
133 static gdImagePtr photo_silk
, photo_mask
, photo_drill
, *photo_im
;
134 static gdImagePtr photo_outline
;
135 static int photo_groups
[MAX_LAYER
+2], photo_ngroups
;
136 static int photo_has_inners
;
138 static int doing_outline
, have_outline
;
140 #define FMT_gif "GIF"
141 #define FMT_jpg "JPEG"
142 #define FMT_png "PNG"
144 /* If this table has no elements in it, then we have no reason to
145 register this HID and will refrain from doing so at the end of this
148 #undef HAVE_SOME_FORMAT
150 static const char *filetypes
[] = {
151 #ifdef HAVE_GDIMAGEPNG
153 #define HAVE_SOME_FORMAT 1
156 #ifdef HAVE_GDIMAGEGIF
158 #define HAVE_SOME_FORMAT 1
161 #ifdef HAVE_GDIMAGEJPEG
163 #define HAVE_SOME_FORMAT 1
170 static const char *mask_colour_names
[] = {
180 // These values were arrived at through trial and error.
181 // One potential improvement (especially for white) is
182 // to use separate color_structs for the multiplication
183 // and addition parts of the mask math.
184 static const color_struct mask_colours
[] = {
185 #define MASK_COLOUR_GREEN 0
186 {.r
= 60, .g
= 160, .b
= 60},
187 #define MASK_COLOUR_RED 1
188 {.r
= 140, .g
= 25, .b
= 25},
189 #define MASK_COLOUR_BLUE 2
190 {.r
= 50, .g
= 50, .b
= 160},
191 #define MASK_COLOUR_PURPLE 3
192 {.r
= 60, .g
= 20, .b
= 70},
193 #define MASK_COLOUR_BLACK 4
194 {.r
= 20, .g
= 20, .b
= 20},
195 #define MASK_COLOUR_WHITE 5
196 {.r
= 167, .g
= 230, .b
= 162}, // <-- needs improvement over FR4
201 static const char *plating_type_names
[] = {
202 #define PLATING_TIN 0
204 #define PLATING_GOLD 1
206 #define PLATING_SILVER 2
208 #define PLATING_COPPER 3
215 static const char *silk_colour_names
[] = {
222 static const color_struct silk_colours
[] = {
223 #define SILK_COLOUR_WHITE 0
224 {.r
= 224, .g
= 224, .b
= 224},
225 #define SILK_COLOUR_BLACK 1
226 {.r
= 14, .g
= 14, .b
= 14},
227 #define SILK_COLOUR_YELLOW 2
228 {.r
= 185, .g
= 185, .b
= 10},
232 static const color_struct silk_top_shadow
= {.r
= 21, .g
= 21, .b
= 21};
233 static const color_struct silk_bottom_shadow
= {.r
= 14, .g
= 14, .b
= 14};
235 HID_Attribute png_attribute_list
[] = {
236 /* other HIDs expect this to be first. */
238 /* %start-doc options "93 PNG Options"
240 @item --outfile <string>
241 Name of the file to be exported to. Can contain a path.
245 {"outfile", "Graphics output file",
246 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
249 /* %start-doc options "93 PNG Options"
252 Scale factor in pixels/inch. Set to 0 to scale to size specified in the layout.
256 {"dpi", "Scale factor (pixels/inch). 0 to scale to specified size",
257 HID_Integer
, 0, 1000, {100, 0, 0}, 0, 0},
260 /* %start-doc options "93 PNG Options"
263 Width of the png image in pixels. No constraint, when set to 0.
267 {"x-max", "Maximum width (pixels). 0 to not constrain",
268 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
271 /* %start-doc options "93 PNG Options"
274 Height of the png output in pixels. No constraint, when set to 0.
278 {"y-max", "Maximum height (pixels). 0 to not constrain",
279 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
282 /* %start-doc options "93 PNG Options"
285 Maximum width and height of the PNG output in pixels. No constraint, when set to 0.
289 {"xy-max", "Maximum width and height (pixels). 0 to not constrain",
290 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
293 /* %start-doc options "93 PNG Options"
296 Export layers as shown on screen.
300 {"as-shown", "Export layers as shown on screen",
301 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
302 #define HA_as_shown 5
304 /* %start-doc options "93 PNG Options"
307 Convert output to monochrome.
311 {"monochrome", "Convert to monochrome",
312 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
315 /* %start-doc options "93 PNG Options"
318 Limit the bounds of the exported PNG image to the visible items.
322 {"only-visible", "Limit the bounds of the PNG image to the visible items",
323 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
324 #define HA_only_visible 7
326 /* %start-doc options "93 PNG Options"
329 Make the background and any holes transparent.
333 {"use-alpha", "Make the background and any holes transparent",
334 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
335 #define HA_use_alpha 8
337 /* %start-doc options "93 PNG Options"
340 Drill holes in pins/pads are filled, not hollow.
344 {"fill-holes", "Drill holes in pins/pads are filled, not hollow",
345 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
346 #define HA_fill_holes 9
348 /* %start-doc options "93 PNG Options"
350 @item --format <string>
351 File format to be exported. Parameter @code{<string>} can be @samp{PNG},
352 @samp{GIF}, or @samp{JPEG}.
356 {"format", "Export file format",
357 HID_Enum
, 0, 0, {0, 0, 0}, filetypes
, 0},
358 #define HA_filetype 10
360 /* %start-doc options "93 PNG Options"
362 @item --png-bloat <num><dim>
363 Amount of extra thickness to add to traces, pads, or pin edges. The parameter
364 @samp{<num><dim>} is a number, appended by a dimension @samp{mm}, @samp{mil}, or
365 @samp{pix}. If no dimension is given, the default dimension is 1/100 mil.
369 {"png-bloat", "Amount (in/mm/mil/pix) to add to trace/pad/pin edges (1 = 1/100 mil)",
370 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
373 /* %start-doc options "93 PNG Options"
377 Export a photo realistic image of the layout.
381 {"photo-mode", "Photo-realistic export mode",
382 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
383 #define HA_photo_mode 12
385 /* %start-doc options "93 PNG Options"
388 In photo-realistic mode, export the reverse side of the layout. Left-right flip.
392 {"photo-flip-x", "Show reverse side of the board, left-right flip",
393 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
394 #define HA_photo_flip_x 13
396 /* %start-doc options "93 PNG Options"
399 In photo-realistic mode, export the reverse side of the layout. Up-down flip.
403 {"photo-flip-y", "Show reverse side of the board, up-down flip",
404 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
405 #define HA_photo_flip_y 14
407 /* %start-doc options "93 PNG Options"
409 @cindex photo-mask-colour
410 @item --photo-mask-colour <colour>
411 In photo-realistic mode, export the solder mask as this colour. Parameter
412 @code{<colour>} can be @samp{green}, @samp{red}, @samp{blue}, or @samp{purple}.
416 {"photo-mask-colour", "Colour for the exported colour mask",
417 HID_Enum
, 0, 0, {0, 0, 0}, mask_colour_names
, 0},
418 #define HA_photo_mask_colour 15
420 /* %start-doc options "93 PNG Options"
422 @cindex photo-plating
423 @item --photo-plating
424 In photo-realistic mode, export the exposed copper as though it has this type
425 of plating. Parameter @code{<colour>} can be @samp{tinned}, @samp{gold},
426 @samp{silver}, or @samp{copper}.
430 {"photo-plating", "Type of plating applied to exposed copper in photo-mode",
431 HID_Enum
, 0, 0, {0, 0, 0}, plating_type_names
, 0},
432 #define HA_photo_plating 16
434 /* %start-doc options "93 PNG Options"
436 @cindex photo-silk-colour
437 @item --photo-silk-colour
438 In photo-realistic mode, export the silk screen as this colour. Parameter
439 @code{<colour>} can be @samp{white}, @samp{black}, or @samp{yellow}.
443 {"photo-silk-colour", "Colour for the exported colour mask",
444 HID_Enum
, 0, 0, {0, 0, 0}, silk_colour_names
, 0},
445 #define HA_photo_silk_colour 17
447 {"ben-mode", ATTR_UNDOCUMENTED
,
448 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
449 #define HA_ben_mode 12
451 {"ben-flip-x", ATTR_UNDOCUMENTED
,
452 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
453 #define HA_ben_flip_x 13
455 {"ben-flip-y", ATTR_UNDOCUMENTED
,
456 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
457 #define HA_ben_flip_y 14
460 #define NUM_OPTIONS (sizeof(png_attribute_list)/sizeof(png_attribute_list[0]))
462 REGISTER_ATTRIBUTES (png_attribute_list
)
464 static HID_Attr_Val png_values
[NUM_OPTIONS
];
466 static const char *get_file_suffix(void)
468 const char *result
= NULL
;
471 fmt
= filetypes
[png_attribute_list
[HA_filetype
].default_val
.int_value
];
475 else if (strcmp (fmt
, FMT_gif
) == 0)
477 else if (strcmp (fmt
, FMT_jpg
) == 0)
479 else if (strcmp (fmt
, FMT_png
) == 0)
484 fprintf (stderr
, "Error: Invalid graphic file format\n");
490 static HID_Attribute
*
491 png_get_export_options (int *n
)
493 static char *last_made_filename
= 0;
494 const char *suffix
= get_file_suffix();
497 derive_default_filename (PCB
->Filename
,
498 &png_attribute_list
[HA_pngfile
],
500 &last_made_filename
);
504 return png_attribute_list
;
507 static int top_group
, bottom_group
;
510 layer_stack_sort (const void *va
, const void *vb
)
512 int a_layer
= *(int *) va
;
513 int b_layer
= *(int *) vb
;
514 int a_group
= GetLayerGroupNumberByNumber (a_layer
);
515 int b_group
= GetLayerGroupNumberByNumber (b_layer
);
516 int aside
= (a_group
== bottom_group
? 0 : a_group
== top_group
? 2 : 1);
517 int bside
= (b_group
== bottom_group
? 0 : b_group
== top_group
? 2 : 1);
520 return bside
- aside
;
522 if (b_group
!= a_group
)
523 return b_group
- a_group
;
525 return b_layer
- a_layer
;
528 static const char *filename
;
529 static BoxType
*bounds
;
530 static int in_mono
, as_shown
, fill_holes
;
533 parse_bloat (const char *str
)
535 UnitList extra_units
= {
542 bloat
= GetValueEx (str
, NULL
, NULL
, extra_units
, "");
546 png_hid_export_to_file (FILE * the_file
, HID_Attr_Val
* options
)
549 static int saved_layer_stack
[MAX_LAYER
];
550 int saved_show_bottom_side
;
558 region
.X2
= PCB
->MaxWidth
;
559 region
.Y2
= PCB
->MaxHeight
;
561 if (options
[HA_only_visible
].int_value
)
562 bounds
= GetDataBoundingBox (PCB
->Data
);
566 memset (print_group
, 0, sizeof (print_group
));
567 memset (print_layer
, 0, sizeof (print_layer
));
569 for (i
= 0; i
< max_copper_layer
; i
++)
571 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
572 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
573 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
575 print_group
[GetLayerGroupNumberBySide (BOTTOM_SIDE
)] = 1;
576 print_group
[GetLayerGroupNumberBySide (TOP_SIDE
)] = 1;
577 for (i
= 0; i
< max_copper_layer
; i
++)
578 if (print_group
[GetLayerGroupNumberByNumber (i
)])
581 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
582 save_flags
= PCB
->Flags
;
583 saved_show_bottom_side
= Settings
.ShowBottomSide
;
585 as_shown
= options
[HA_as_shown
].int_value
;
586 fill_holes
= options
[HA_fill_holes
].int_value
;
588 if (!options
[HA_as_shown
].int_value
)
590 CLEAR_FLAG (SHOWMASKFLAG
, PCB
);
591 Settings
.ShowBottomSide
= 0;
593 top_group
= GetLayerGroupNumberBySide (TOP_SIDE
);
594 bottom_group
= GetLayerGroupNumberBySide (BOTTOM_SIDE
);
595 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_stack_sort
);
597 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
598 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
603 SET_FLAG (SHOWMASKFLAG
, PCB
);
604 photo_has_inners
= 0;
605 if (top_group
< bottom_group
)
606 for (i
= top_group
; i
<= bottom_group
; i
++)
608 photo_groups
[n
++] = i
;
609 if (i
!= top_group
&& i
!= bottom_group
610 && ! IsLayerGroupEmpty (i
))
611 photo_has_inners
= 1;
614 for (i
= top_group
; i
>= bottom_group
; i
--)
616 photo_groups
[n
++] = i
;
617 if (i
!= top_group
&& i
!= bottom_group
618 && ! IsLayerGroupEmpty (i
))
619 photo_has_inners
= 1;
621 if (!photo_has_inners
)
623 photo_groups
[1] = photo_groups
[n
- 1];
630 for (i
=0, n
=photo_ngroups
-1; i
<n
; i
++, n
--)
632 int tmp
= photo_groups
[i
];
633 photo_groups
[i
] = photo_groups
[n
];
634 photo_groups
[n
] = tmp
;
640 lastbrush
= (gdImagePtr
)((void *) -1);
643 show_bottom_side
= Settings
.ShowBottomSide
;
645 in_mono
= options
[HA_mono
].int_value
;
647 if (!photo_mode
&& Settings
.ShowBottomSide
)
650 for (i
=0, j
=max_copper_layer
-1; i
<j
; i
++, j
--)
652 int k
= LayerStack
[i
];
653 LayerStack
[i
] = LayerStack
[j
];
658 hid_expose_callback (&png_hid
, bounds
, 0);
660 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
661 PCB
->Flags
= save_flags
;
662 Settings
.ShowBottomSide
= saved_show_bottom_side
;
666 clip (color_struct
*dest
, color_struct
*source
)
669 dest->var = source->var; \
670 if (dest->var > 255) dest->var = 255; \
671 if (dest->var < 0) dest->var = 0;
680 blend (color_struct
*dest
, double a_amount
, color_struct
*a
, color_struct
*b
)
682 dest
->r
= a
->r
* a_amount
+ b
->r
* (1 - a_amount
);
683 dest
->g
= a
->g
* a_amount
+ b
->g
* (1 - a_amount
);
684 dest
->b
= a
->b
* a_amount
+ b
->b
* (1 - a_amount
);
688 multiply (color_struct
*dest
, color_struct
*a
, color_struct
*b
)
690 dest
->r
= (a
->r
* b
->r
) / 255;
691 dest
->g
= (a
->g
* b
->g
) / 255;
692 dest
->b
= (a
->b
* b
->b
) / 255;
696 add (color_struct
*dest
, double a_amount
, const color_struct
*a
, double b_amount
, const color_struct
*b
)
698 dest
->r
= a
->r
* a_amount
+ b
->r
* b_amount
;
699 dest
->g
= a
->g
* a_amount
+ b
->g
* b_amount
;
700 dest
->b
= a
->b
* a_amount
+ b
->b
* b_amount
;
706 subtract (color_struct
*dest
, double a_amount
, const color_struct
*a
, double b_amount
, const color_struct
*b
)
708 dest
->r
= a
->r
* a_amount
- b
->r
* b_amount
;
709 dest
->g
= a
->g
* a_amount
- b
->g
* b_amount
;
710 dest
->b
= a
->b
* a_amount
- b
->b
* b_amount
;
716 rgb (color_struct
*dest
, int r
, int g
, int b
)
723 static int smshadows
[3][3] = {
729 static int shadows
[5][5] = {
733 { 1, -1, -1, -1, -1 },
734 { -1, -1, -1, -1, -1 },
737 /* black and white are 0 and 1 */
739 #define BOTTOM_SHADOW 3
742 ts_bs (gdImagePtr im
)
744 int x
, y
, sx
, sy
, si
;
745 for (x
=0; x
<gdImageSX(im
); x
++)
746 for (y
=0; y
<gdImageSY(im
); y
++)
749 for (sx
=-2; sx
<3; sx
++)
750 for (sy
=-2; sy
<3; sy
++)
751 if (!gdImageGetPixel (im
, x
+sx
, y
+sy
))
752 si
+= shadows
[sx
+2][sy
+2];
753 if (gdImageGetPixel (im
, x
, y
))
756 gdImageSetPixel (im
, x
, y
, TOP_SHADOW
);
758 gdImageSetPixel (im
, x
, y
, BOTTOM_SHADOW
);
764 ts_bs_sm (gdImagePtr im
)
766 int x
, y
, sx
, sy
, si
;
767 for (x
=0; x
<gdImageSX(im
); x
++)
768 for (y
=0; y
<gdImageSY(im
); y
++)
771 for (sx
=-1; sx
<2; sx
++)
772 for (sy
=-1; sy
<2; sy
++)
773 if (!gdImageGetPixel (im
, x
+sx
, y
+sy
))
774 si
+= smshadows
[sx
+1][sy
+1];
775 if (gdImageGetPixel (im
, x
, y
))
778 gdImageSetPixel (im
, x
, y
, TOP_SHADOW
);
780 gdImageSetPixel (im
, x
, y
, BOTTOM_SHADOW
);
786 png_do_export (HID_Attr_Val
* options
)
788 int save_ons
[MAX_LAYER
+ 2];
795 bool format_error
= false;
811 png_get_export_options (0);
812 for (i
= 0; i
< NUM_OPTIONS
; i
++)
813 png_values
[i
] = png_attribute_list
[i
].default_val
;
814 options
= png_values
;
817 if (options
[HA_photo_mode
].int_value
818 || options
[HA_ben_mode
].int_value
)
821 options
[HA_mono
].int_value
= 1;
822 options
[HA_as_shown
].int_value
= 0;
823 memset (photo_copper
, 0, sizeof(photo_copper
));
824 photo_silk
= photo_mask
= photo_drill
= 0;
826 if (options
[HA_photo_flip_x
].int_value
827 || options
[HA_ben_flip_x
].int_value
)
828 photo_flip
= PHOTO_FLIP_X
;
829 else if (options
[HA_photo_flip_y
].int_value
830 || options
[HA_ben_flip_y
].int_value
)
831 photo_flip
= PHOTO_FLIP_Y
;
838 filename
= options
[HA_pngfile
].str_value
;
840 filename
= "pcb-out.png";
842 /* figure out width and height of the board */
843 if (options
[HA_only_visible
].int_value
)
845 bbox
= GetDataBoundingBox (PCB
->Data
);
848 h
= bbox
->Y2
- bbox
->Y1
;
849 w
= bbox
->X2
- bbox
->X1
;
860 * figure out the scale factor we need to make the image
861 * fit in our specified PNG file size
863 xmax
= ymax
= dpi
= 0;
864 if (options
[HA_dpi
].int_value
!= 0)
866 dpi
= options
[HA_dpi
].int_value
;
869 fprintf (stderr
, "ERROR: dpi may not be < 0\n");
874 if (options
[HA_xmax
].int_value
> 0)
876 xmax
= options
[HA_xmax
].int_value
;
880 if (options
[HA_ymax
].int_value
> 0)
882 ymax
= options
[HA_ymax
].int_value
;
886 if (options
[HA_xymax
].int_value
> 0)
889 if (options
[HA_xymax
].int_value
< xmax
|| xmax
== 0)
890 xmax
= options
[HA_xymax
].int_value
;
891 if (options
[HA_xymax
].int_value
< ymax
|| ymax
== 0)
892 ymax
= options
[HA_xymax
].int_value
;
895 if (xmax
< 0 || ymax
< 0)
897 fprintf (stderr
, "ERROR: xmax and ymax may not be < 0\n");
904 * a scale of 1 means 1 pixel is 1 inch
905 * a scale of 10 means 1 pixel is 10 inches
907 scale
= round(INCH_TO_COORD(1) / (double) dpi
);
911 else if( xmax
== 0 && ymax
== 0)
913 fprintf(stderr
, "ERROR: You may not set both xmax, ymax,"
914 "and xy-max to zero\n");
921 && ((w
/ xmax
) > (h
/ ymax
)) ) )
935 im
= gdImageCreate (w
, h
);
938 Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__
, w
, h
);
944 parse_bloat (options
[HA_bloat
].str_value
);
947 * Allocate white and black -- the first color allocated
948 * becomes the background color
951 white
= (color_struct
*) malloc (sizeof (color_struct
));
952 white
->r
= white
->g
= white
->b
= 255;
953 if (options
[HA_use_alpha
].int_value
)
957 white
->c
= gdImageColorAllocateAlpha (im
, white
->r
, white
->g
, white
->b
, white
->a
);
958 if (white
->c
== BADC
)
960 Message ("%s(): gdImageColorAllocateAlpha() returned NULL. Aborting export.\n", __FUNCTION__
);
964 gdImageFilledRectangle (im
, 0, 0, gdImageSX (im
), gdImageSY (im
), white
->c
);
966 black
= (color_struct
*) malloc (sizeof (color_struct
));
967 black
->r
= black
->g
= black
->b
= black
->a
= 0;
968 black
->c
= gdImageColorAllocate (im
, black
->r
, black
->g
, black
->b
);
969 if (black
->c
== BADC
)
971 Message ("%s(): gdImageColorAllocateAlpha() returned NULL. Aborting export.\n", __FUNCTION__
);
975 f
= fopen (filename
, "wb");
982 if (!options
[HA_as_shown
].int_value
)
983 hid_save_and_show_layer_ons (save_ons
);
985 png_hid_export_to_file (f
, options
);
987 if (!options
[HA_as_shown
].int_value
)
988 hid_restore_layer_ons (save_ons
);
993 color_struct white
, black
, fr4
;
995 rgb (&white
, 255, 255, 255);
996 rgb (&black
, 0, 0, 0);
997 rgb (&fr4
, 70, 70, 70);
1001 ts_bs (photo_copper
[photo_groups
[0]]);
1003 ts_bs_sm (photo_mask
);
1005 if (photo_outline
&& have_outline
) {
1006 int black
=gdImageColorResolve(photo_outline
, 0x00, 0x00, 0x00);
1008 // go all the way around the image, trying to fill the outline
1009 for (x
=0; x
<gdImageSX(im
); x
++) {
1010 gdImageFillToBorder(photo_outline
, x
, 0, black
, black
);
1011 gdImageFillToBorder(photo_outline
, x
, gdImageSY(im
)-1, black
, black
);
1013 for (y
=1; y
<gdImageSY(im
)-1; y
++) {
1014 gdImageFillToBorder(photo_outline
, 0, y
, black
, black
);
1015 gdImageFillToBorder(photo_outline
, gdImageSX(im
)-1, y
, black
, black
);
1021 for (x
=0; x
<gdImageSX (im
); x
++)
1023 for (y
=0; y
<gdImageSY (im
); y
++)
1025 color_struct p
, cop
;
1026 color_struct mask_colour
, silk_colour
;
1030 if (photo_outline
&& have_outline
) {
1031 transparent
=gdImageGetPixel(photo_outline
, x
, y
);
1036 mask
= photo_mask
? gdImageGetPixel (photo_mask
, x
, y
) : 0;
1037 silk
= photo_silk
? gdImageGetPixel (photo_silk
, x
, y
) : 0;
1039 if (photo_copper
[photo_groups
[1]]
1040 && gdImageGetPixel (photo_copper
[photo_groups
[1]], x
, y
))
1041 rgb (&cop
, 40, 40, 40);
1043 rgb (&cop
, 100, 100, 110);
1045 if (photo_ngroups
== 2)
1046 blend (&cop
, 0.3, &cop
, &fr4
);
1048 cc
= gdImageGetPixel (photo_copper
[photo_groups
[0]], x
, y
);
1054 rgb (&cop
, 220, 145, 230);
1057 if (options
[HA_photo_plating
].int_value
== PLATING_GOLD
)
1060 rgb (&cop
, 185, 146, 52);
1062 // increase top shadow to increase shininess
1063 if (cc
== TOP_SHADOW
)
1064 blend (&cop
, 0.7, &cop
, &white
);
1066 else if (options
[HA_photo_plating
].int_value
== PLATING_TIN
)
1069 rgb (&cop
, 140, 150, 160);
1071 // add some variation to make it look more matte
1072 r
= (rand() % 5 - 2) * 2;
1077 else if (options
[HA_photo_plating
].int_value
== PLATING_SILVER
)
1080 rgb (&cop
, 192, 192, 185);
1082 // increase top shadow to increase shininess
1083 if (cc
== TOP_SHADOW
)
1084 blend (&cop
, 0.7, &cop
, &white
);
1086 else if (options
[HA_photo_plating
].int_value
== PLATING_COPPER
)
1089 rgb (&cop
, 184, 115, 51);
1091 // increase top shadow to increase shininess
1092 if (cc
== TOP_SHADOW
)
1093 blend (&cop
, 0.7, &cop
, &white
);
1097 if (cc
== TOP_SHADOW
)
1098 blend (&cop
, 0.7, &cop
, &white
);
1099 if (cc
== BOTTOM_SHADOW
)
1100 blend (&cop
, 0.7, &cop
, &black
);
1103 if (photo_drill
&& !gdImageGetPixel (photo_drill
, x
, y
))
1110 silk_colour
= silk_colours
[options
[HA_photo_silk_colour
].int_value
];
1111 blend (&p
, 1.0, &silk_colour
, &silk_colour
);
1112 if (silk
== TOP_SHADOW
)
1113 add (&p
, 1.0, &p
, 1.0, &silk_top_shadow
);
1114 else if (silk
== BOTTOM_SHADOW
)
1115 subtract (&p
, 1.0, &p
, 1.0, &silk_bottom_shadow
);
1120 mask_colour
= mask_colours
[options
[HA_photo_mask_colour
].int_value
];
1121 multiply (&p
, &p
, &mask_colour
);
1122 add (&p
, 1, &p
, 0.2, &mask_colour
);
1123 if (mask
== TOP_SHADOW
)
1124 blend (&p
, 0.7, &p
, &white
);
1125 if (mask
== BOTTOM_SHADOW
)
1126 blend (&p
, 0.7, &p
, &black
);
1131 if (options
[HA_use_alpha
].int_value
) {
1133 cc
= (transparent
)?\
1134 gdImageColorResolveAlpha(im
, 0, 0, 0, 127):\
1135 gdImageColorResolveAlpha(im
, p
.r
, p
.g
, p
.b
, 0);
1138 cc
= (transparent
)?\
1139 gdImageColorResolve(im
, 0, 0, 0):\
1140 gdImageColorResolve(im
, p
.r
, p
.g
, p
.b
);
1143 if (photo_flip
== PHOTO_FLIP_X
)
1144 gdImageSetPixel (im
, gdImageSX (im
) - x
- 1, y
, cc
);
1145 else if (photo_flip
== PHOTO_FLIP_Y
)
1146 gdImageSetPixel (im
, x
, gdImageSY (im
) - y
- 1, cc
);
1148 gdImageSetPixel (im
, x
, y
, cc
);
1153 /* actually write out the image */
1154 fmt
= filetypes
[options
[HA_filetype
].int_value
];
1157 format_error
= true;
1158 else if (strcmp (fmt
, FMT_gif
) == 0)
1159 #ifdef HAVE_GDIMAGEGIF
1162 format_error
= true;
1164 else if (strcmp (fmt
, FMT_jpg
) == 0)
1165 #ifdef HAVE_GDIMAGEJPEG
1166 gdImageJpeg (im
, f
, -1);
1168 format_error
= true;
1170 else if (strcmp (fmt
, FMT_png
) == 0)
1171 #ifdef HAVE_GDIMAGEPNG
1174 format_error
= true;
1177 format_error
= true;
1180 fprintf (stderr
, "Error: Invalid graphic file format."
1181 " This is a bug. Please report it.\n");
1185 gdImageDestroy (im
);
1189 png_parse_arguments (int *argc
, char ***argv
)
1191 hid_register_attributes (png_attribute_list
,
1192 sizeof (png_attribute_list
) /
1193 sizeof (png_attribute_list
[0]));
1194 hid_parse_command_line (argc
, argv
);
1199 static int is_drill
;
1200 static int is_copper
;
1203 png_set_layer (const char *name
, int group
, int empty
)
1205 int idx
= (group
>= 0
1207 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
1209 name
= PCB
->Data
->Layer
[idx
].Name
;
1213 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
1215 if (SL_TYPE (idx
) == SL_ASSY
|| SL_TYPE (idx
) == SL_FAB
)
1218 if (strcmp (name
, "invisible") == 0)
1221 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
1222 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
1223 is_copper
= (SL_TYPE (idx
) == 0);
1225 if (is_drill
&& fill_holes
)
1228 if (SL_TYPE (idx
) == SL_PASTE
)
1235 case SL (SILK
, TOP
):
1238 photo_im
= &photo_silk
;
1240 case SL (SILK
, BOTTOM
):
1243 photo_im
= &photo_silk
;
1246 case SL (MASK
, TOP
):
1249 photo_im
= &photo_mask
;
1251 case SL (MASK
, BOTTOM
):
1254 photo_im
= &photo_mask
;
1257 case SL (PDRILL
, 0):
1258 case SL (UDRILL
, 0):
1259 photo_im
= &photo_drill
;
1266 if (strcmp (name
, "outline") == 0)
1270 photo_im
= &photo_outline
;
1273 photo_im
= photo_copper
+ group
;
1280 static color_struct
*black
= NULL
, *white
= NULL
;
1281 *photo_im
= gdImageCreate (gdImageSX (im
), gdImageSY (im
));
1282 if (photo_im
== NULL
)
1284 Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__
,
1285 gdImageSX (im
), gdImageSY (im
));
1290 white
= (color_struct
*) malloc (sizeof (color_struct
));
1291 white
->r
= white
->g
= white
->b
= 255;
1293 white
->c
= gdImageColorAllocate (*photo_im
, white
->r
, white
->g
, white
->b
);
1294 if (white
->c
== BADC
)
1296 Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__
);
1300 black
= (color_struct
*) malloc (sizeof (color_struct
));
1301 black
->r
= black
->g
= black
->b
= black
->a
= 0;
1302 black
->c
= gdImageColorAllocate (*photo_im
, black
->r
, black
->g
, black
->b
);
1303 if (black
->c
== BADC
)
1305 Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__
);
1309 if (idx
== SL (PDRILL
, 0)
1310 || idx
== SL (UDRILL
, 0))
1311 gdImageFilledRectangle (*photo_im
, 0, 0, gdImageSX (im
), gdImageSY (im
), black
->c
);
1321 case SL (SILK
, TOP
):
1322 case SL (SILK
, BOTTOM
):
1323 if (SL_MYSIDE (idx
))
1324 return PCB
->ElementOn
;
1327 case SL (MASK
, TOP
):
1328 case SL (MASK
, BOTTOM
):
1329 return TEST_FLAG (SHOWMASKFLAG
, PCB
) && SL_MYSIDE (idx
);
1339 case SL (SILK
, TOP
):
1341 case SL (SILK
, BOTTOM
):
1353 hidGC gc
= (hidGC
) calloc (1, sizeof (struct png_gc_struct
));
1354 pngGC png_gc
= (pngGC
)gc
;
1357 gc
->hid_draw
= &png_graphics
;
1359 png_gc
->cap
= Trace_Cap
;
1361 png_gc
->color
= (color_struct
*) malloc (sizeof (color_struct
));
1362 png_gc
->color
->r
= png_gc
->color
->g
= png_gc
->color
->b
= png_gc
->color
->a
= 0;
1363 png_gc
->color
->c
= 0;
1364 png_gc
->is_erase
= 0;
1370 png_destroy_gc (hidGC gc
)
1376 png_use_mask (enum mask_mode mode
)
1381 if (mode
== HID_MASK_CLEAR
)
1385 if (mode
!= HID_MASK_OFF
)
1387 if (mask_im
== NULL
)
1389 mask_im
= gdImageCreate (gdImageSX (im
), gdImageSY (im
));
1392 Message ("%s(): gdImageCreate(%d, %d) returned NULL. Corrupt export!\n",
1393 __FUNCTION__
, gdImageSY (im
), gdImageSY (im
));
1396 gdImagePaletteCopy (mask_im
, im
);
1399 gdImageFilledRectangle (mask_im
, 0, 0, gdImageSX (mask_im
), gdImageSY (mask_im
), white
->c
);
1407 for (x
=0; x
<gdImageSX (im
); x
++)
1408 for (y
=0; y
<gdImageSY (im
); y
++)
1410 c
= gdImageGetPixel (mask_im
, x
, y
);
1412 gdImageSetPixel (im
, x
, y
, c
);
1418 png_set_color (hidGC gc
, const char *name
)
1420 pngGC png_gc
= (pngGC
)gc
;
1429 if (strcmp (name
, "erase") == 0 || strcmp (name
, "drill") == 0)
1431 png_gc
->color
= white
;
1432 png_gc
->is_erase
= 1;
1435 png_gc
->is_erase
= 0;
1437 if (in_mono
|| (strcmp (name
, "#000000") == 0))
1439 png_gc
->color
= black
;
1443 if (hid_cache_color (0, name
, &cval
, &color_cache
))
1445 png_gc
->color
= (color_struct
*)cval
.ptr
;
1447 else if (name
[0] == '#')
1449 png_gc
->color
= (color_struct
*) malloc (sizeof (color_struct
));
1450 sscanf (name
+ 1, "%2x%2x%2x", &(png_gc
->color
->r
), &(png_gc
->color
->g
),
1451 &(png_gc
->color
->b
));
1453 gdImageColorAllocate (master_im
, png_gc
->color
->r
, png_gc
->color
->g
, png_gc
->color
->b
);
1454 if (png_gc
->color
->c
== BADC
)
1456 Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__
);
1459 cval
.ptr
= png_gc
->color
;
1460 hid_cache_color (1, name
, &cval
, &color_cache
);
1464 printf ("WE SHOULD NOT BE HERE!!!\n");
1465 png_gc
->color
= black
;
1471 png_set_line_cap (hidGC gc
, EndCapStyle style
)
1473 pngGC png_gc
= (pngGC
)gc
;
1475 png_gc
->cap
= style
;
1479 png_set_line_width (hidGC gc
, Coord width
)
1481 pngGC png_gc
= (pngGC
)gc
;
1483 png_gc
->width
= width
;
1487 png_set_draw_xor (hidGC gc
, int xor_
)
1495 pngGC png_gc
= (pngGC
)gc
;
1499 if (gc
->hid
!= &png_hid
)
1501 fprintf (stderr
, "Fatal: GC from another HID passed to png HID\n");
1505 if (linewidth
!= png_gc
->width
)
1507 /* Make sure the scaling doesn't erase lines completely */
1508 if (SCALE (png_gc
->width
) == 0 && png_gc
->width
> 0)
1509 gdImageSetThickness (im
, 1);
1511 gdImageSetThickness (im
, SCALE (png_gc
->width
+ 2*bloat
));
1512 linewidth
= png_gc
->width
;
1516 if (lastbrush
!= png_gc
->brush
|| need_brush
)
1523 switch (png_gc
->cap
)
1535 r
= SCALE (png_gc
->width
+ 2*bloat
);
1539 /* do not allow a brush size that is zero width. In this case limit to a single pixel. */
1545 sprintf (name
, "#%.2x%.2x%.2x_%c_%d", png_gc
->color
->r
, png_gc
->color
->g
,
1546 png_gc
->color
->b
, type
, r
);
1548 if (hid_cache_color (0, name
, &bval
, &brush_cache
))
1550 png_gc
->brush
= (gdImagePtr
)bval
.ptr
;
1555 png_gc
->brush
= gdImageCreate (r
, r
);
1556 if (png_gc
->brush
== NULL
)
1558 Message ("%s(): gdImageCreate(%d, %d) returned NULL. Aborting export.\n", __FUNCTION__
, r
, r
);
1562 bg
= gdImageColorAllocate (png_gc
->brush
, 255, 255, 255);
1565 Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__
);
1569 gdImageColorAllocateAlpha (png_gc
->brush
, png_gc
->color
->r
, png_gc
->color
->g
, png_gc
->color
->b
, 0);
1572 Message ("%s(): gdImageColorAllocate() returned NULL. Aborting export.\n", __FUNCTION__
);
1575 gdImageColorTransparent (png_gc
->brush
, bg
);
1578 * if we shrunk to a radius/box width of zero, then just use
1579 * a single pixel to draw with.
1582 gdImageFilledRectangle (png_gc
->brush
, 0, 0, 0, 0, fg
);
1587 gdImageFilledEllipse (png_gc
->brush
, r
/2, r
/2, r
, r
, fg
);
1588 /* Make sure the ellipse is the right exact size. */
1589 gdImageSetPixel (png_gc
->brush
, 0, r
/2, fg
);
1590 gdImageSetPixel (png_gc
->brush
, r
-1, r
/2, fg
);
1591 gdImageSetPixel (png_gc
->brush
, r
/2, 0, fg
);
1592 gdImageSetPixel (png_gc
->brush
, r
/2, r
-1, fg
);
1595 gdImageFilledRectangle (png_gc
->brush
, 0, 0, r
-1, r
-1, fg
);
1597 bval
.ptr
= png_gc
->brush
;
1598 hid_cache_color (1, name
, &bval
, &brush_cache
);
1601 gdImageSetBrush (im
, png_gc
->brush
);
1602 lastbrush
= png_gc
->brush
;
1608 png_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1610 pngGC png_gc
= (pngGC
)gc
;
1613 gdImageRectangle (im
,
1614 SCALE_X (x1
), SCALE_Y (y1
),
1615 SCALE_X (x2
), SCALE_Y (y2
), png_gc
->color
->c
);
1619 png_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1621 pngGC png_gc
= (pngGC
)gc
;
1624 gdImageSetThickness (im
, 0);
1629 SWAP_IF_SOLDER (y1
, y2
);
1631 gdImageFilledRectangle (im
, SCALE_X (x1
-bloat
), SCALE_Y (y1
),
1632 SCALE_X (x2
+bloat
)-1, SCALE_Y (y2
)-1, png_gc
->color
->c
);
1633 have_outline
|= doing_outline
;
1637 png_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1639 pngGC png_gc
= (pngGC
)gc
;
1641 if (x1
== x2
&& y1
== y2
)
1643 Coord w
= png_gc
->width
/ 2;
1644 if (png_gc
->cap
!= Square_Cap
)
1645 png_fill_circle (gc
, x1
, y1
, w
);
1647 png_fill_rect (gc
, x1
- w
, y1
- w
, x1
+ w
, y1
+ w
);
1652 if (NOT_EDGE (x1
, y1
) || NOT_EDGE (x2
, y2
))
1653 have_outline
|= doing_outline
;
1656 /* Special case - lines drawn along the bottom or right edges
1657 are brought in by a pixel to make sure we have contiguous
1659 if (x1
== PCB
->MaxWidth
&& x2
== PCB
->MaxWidth
)
1664 if (y1
== PCB
->MaxHeight
&& y2
== PCB
->MaxHeight
)
1671 gdImageSetThickness (im
, 0);
1673 if(png_gc
->cap
!= Square_Cap
|| x1
== x2
|| y1
== y2
)
1675 gdImageLine (im
, SCALE_X (x1
), SCALE_Y (y1
),
1676 SCALE_X (x2
), SCALE_Y (y2
), gdBrushed
);
1681 * if we are drawing a line with a square end cap and it is
1682 * not purely horizontal or vertical, then we need to draw
1683 * it as a filled polygon.
1685 int fg
= gdImageColorResolve (im
, png_gc
->color
->r
, png_gc
->color
->g
,
1687 Coord w
= png_gc
->width
;
1691 double l
= Distance(x1
, y1
, x2
, y2
) * 2;
1694 dwx
= -w
/ l
* (y2
- y1
); dwy
= w
/ l
* (x2
- x1
);
1695 p
[0].x
= SCALE_X (x1
+ dwx
- dwy
); p
[0].y
= SCALE_Y(y1
+ dwy
+ dwx
);
1696 p
[1].x
= SCALE_X (x1
- dwx
- dwy
); p
[1].y
= SCALE_Y(y1
- dwy
+ dwx
);
1697 p
[2].x
= SCALE_X (x2
- dwx
+ dwy
); p
[2].y
= SCALE_Y(y2
- dwy
- dwx
);
1698 p
[3].x
= SCALE_X (x2
+ dwx
+ dwy
); p
[3].y
= SCALE_Y(y2
+ dwy
- dwx
);
1699 gdImageFilledPolygon (im
, p
, 4, fg
);
1704 png_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
1705 Angle start_angle
, Angle delta_angle
)
1707 pngGC png_gc
= (pngGC
)gc
;
1711 * zero angle arcs need special handling as gd will output either
1712 * nothing at all or a full circle when passed delta angle of 0 or 360.
1714 if (delta_angle
== 0) {
1715 Coord x
= (width
* cos (start_angle
* M_PI
/ 180));
1716 Coord y
= (width
* sin (start_angle
* M_PI
/ 180));
1719 png_fill_circle (gc
, x
, y
, png_gc
->width
/ 2);
1724 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
1725 * in pcb, 0 degrees is to the left and +90 degrees is down
1727 start_angle
= 180 - start_angle
;
1728 delta_angle
= -delta_angle
;
1729 if (show_bottom_side
)
1731 start_angle
= - start_angle
;
1732 delta_angle
= -delta_angle
;
1734 if (delta_angle
> 0)
1737 ea
= start_angle
+ delta_angle
;
1741 sa
= start_angle
+ delta_angle
;
1746 * make sure we start between 0 and 360 otherwise gd does
1749 sa
= NormalizeAngle (sa
);
1750 ea
= NormalizeAngle (ea
);
1752 have_outline
|= doing_outline
;
1755 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
1756 cx
, cy
, width
, height
, start_angle
, delta_angle
, sa
, ea
);
1757 printf ("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
1758 im
, SCALE_X (cx
), SCALE_Y (cy
),
1759 SCALE (width
), SCALE (height
), sa
, ea
, png_gc
->color
->c
);
1762 gdImageSetThickness (im
, 0);
1764 gdImageArc (im
, SCALE_X (cx
), SCALE_Y (cy
),
1765 SCALE (2 * width
), SCALE (2 * height
), sa
, ea
, gdBrushed
);
1769 png_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
1771 pngGC png_gc
= (pngGC
)gc
;
1776 if (fill_holes
&& png_gc
->is_erase
&& is_copper
)
1779 if (png_gc
->is_erase
)
1780 my_bloat
= -2 * bloat
;
1782 my_bloat
= 2 * bloat
;
1785 have_outline
|= doing_outline
;
1787 gdImageSetThickness (im
, 0);
1789 gdImageFilledEllipse (im
, SCALE_X (cx
), SCALE_Y (cy
),
1790 SCALE (2 * radius
+ my_bloat
), SCALE (2 * radius
+ my_bloat
), png_gc
->color
->c
);
1795 png_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
1797 pngGC png_gc
= (pngGC
)gc
;
1801 points
= (gdPoint
*) malloc (n_coords
* sizeof (gdPoint
));
1804 fprintf (stderr
, "ERROR: png_fill_polygon(): malloc failed\n");
1809 for (i
= 0; i
< n_coords
; i
++)
1811 if (NOT_EDGE (x
[i
], y
[i
]))
1812 have_outline
|= doing_outline
;
1813 points
[i
].x
= SCALE_X (x
[i
]);
1814 points
[i
].y
= SCALE_Y (y
[i
]);
1816 gdImageSetThickness (im
, 0);
1818 gdImageFilledPolygon (im
, points
, n_coords
, png_gc
->color
->c
);
1823 png_calibrate (double xval
, double yval
)
1829 png_set_crosshair (int x
, int y
, int a
)
1833 #include "dolists.h"
1838 memset (&png_hid
, 0, sizeof (HID
));
1839 memset (&png_graphics
, 0, sizeof (HID_DRAW
));
1840 memset (&png_graphics_class
, 0, sizeof (HID_DRAW_CLASS
));
1842 common_nogui_init (&png_hid
);
1844 png_hid
.struct_size
= sizeof (HID
);
1845 png_hid
.name
= "png";
1846 png_hid
.description
= "GIF/JPEG/PNG export";
1847 png_hid
.exporter
= 1;
1849 png_hid
.get_export_options
= png_get_export_options
;
1850 png_hid
.do_export
= png_do_export
;
1851 png_hid
.parse_arguments
= png_parse_arguments
;
1852 png_hid
.calibrate
= png_calibrate
;
1853 png_hid
.set_crosshair
= png_set_crosshair
;
1855 png_hid
.graphics
= &png_graphics
;
1857 common_draw_helpers_class_init (&png_graphics_class
);
1859 png_graphics_class
.set_layer
= png_set_layer
;
1860 png_graphics_class
.make_gc
= png_make_gc
;
1861 png_graphics_class
.destroy_gc
= png_destroy_gc
;
1862 png_graphics_class
.use_mask
= png_use_mask
;
1863 png_graphics_class
.set_color
= png_set_color
;
1864 png_graphics_class
.set_line_cap
= png_set_line_cap
;
1865 png_graphics_class
.set_line_width
= png_set_line_width
;
1866 png_graphics_class
.set_draw_xor
= png_set_draw_xor
;
1867 png_graphics_class
.draw_line
= png_draw_line
;
1868 png_graphics_class
.draw_arc
= png_draw_arc
;
1869 png_graphics_class
.draw_rect
= png_draw_rect
;
1870 png_graphics_class
.fill_circle
= png_fill_circle
;
1871 png_graphics_class
.fill_polygon
= png_fill_polygon
;
1872 png_graphics_class
.fill_rect
= png_fill_rect
;
1874 png_graphics
.klass
= &png_graphics_class
;
1875 png_graphics
.poly_before
= true;
1876 common_draw_helpers_init (&png_graphics
);
1878 #ifdef HAVE_SOME_FORMAT
1879 hid_register_hid (&png_hid
);
1881 #include "png_lists.h"