2 /*Sept 2007: patch to enable slanted squared lines*/
6 * PCB, interactive printed circuit board design
7 * Copyright (C) 2006 Dan McMahill
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * Heavily based on the ps HID written by DJ Delorie
44 #include "../hidint.h"
45 #include "hid/common/draw_helpers.h"
48 /* the gd library which makes this all so easy */
51 #ifdef HAVE_LIBDMALLOC
57 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
59 static void *color_cache
= NULL
;
60 static void *brush_cache
= NULL
;
65 #define SCALE(x) ((int)((x)/scale + 0.5))
66 #define SCALE_X(x) ((int)(((x) - x_shift)/scale))
67 #define SCALE_Y(x) ((int)(((x) - y_shift)/scale))
69 typedef struct color_struct
71 /* the descriptor used by the gd library */
74 /* so I can figure out what rgb value c refers to */
75 unsigned int r
, g
, b
, a
;
79 typedef struct hid_gc_struct
84 unsigned char r
, g
, b
;
91 static color_struct
*black
= NULL
, *white
= NULL
;
92 static gdImagePtr im
= NULL
, master_im
;
94 static int linewidth
= -1;
95 static int lastgroup
= -1;
96 static gdImagePtr lastbrush
= (void *) -1;
97 static int lastcap
= -1;
98 static int lastcolor
= -1;
99 static int print_group
[MAX_LAYER
];
100 static int print_layer
[MAX_LAYER
];
102 /* For photo-mode we need the following layers as monochrome masks:
110 #define PHOTO_FLIP_X 1
111 #define PHOTO_FLIP_Y 2
113 static int photo_mode
, photo_flip
;
114 static gdImagePtr photo_copper
[MAX_LAYER
+2];
115 static gdImagePtr photo_silk
, photo_mask
, photo_drill
, *photo_im
;
116 static gdImagePtr photo_outline
;
117 static int photo_groups
[MAX_LAYER
+2], photo_ngroups
;
119 #define FMT_gif "GIF"
120 #define FMT_jpg "JPEG"
121 #define FMT_png "PNG"
123 static const char *filetypes
[] = {
124 #ifdef HAVE_GDIMAGEGIF
128 #ifdef HAVE_GDIMAGEJPEG
132 #ifdef HAVE_GDIMAGEPNG
139 HID_Attribute png_attribute_list
[] = {
140 /* other HIDs expect this to be first. */
141 {"outfile", "Graphics output file",
142 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
145 {"dpi", "Scale factor (pixels/inch). 0 to scale to fix specified size",
146 HID_Integer
, 0, 1000, {100, 0, 0}, 0, 0},
149 {"x-max", "Maximum width (pixels). 0 to not constrain.",
150 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
153 {"y-max", "Maximum height (pixels). 0 to not constrain.",
154 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
157 {"xy-max", "Maximum width and height (pixels). 0 to not constrain.",
158 HID_Integer
, 0, 10000, {0, 0, 0}, 0, 0},
161 {"as-shown", "Export layers as shown on screen",
162 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
163 #define HA_as_shown 5
165 {"monochrome", "Convert to monochrome",
166 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
169 {"only-visible", "Limit the bounds of the PNG file to the visible items",
170 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
171 #define HA_only_visible 7
173 {"use-alpha", "Make the background and any holes transparent",
174 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
175 #define HA_use_alpha 8
177 {"format", "Graphics file format",
178 HID_Enum
, 0, 0, {2, 0, 0}, filetypes
, 0},
179 #define HA_filetype 9
181 {"photo-mode", "Photo-realistic mode",
182 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
183 #define HA_photo_mode 10
185 {"photo-flip-x", "Show reverse side of the board, left-right flip",
186 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
187 #define HA_photo_flip_x 11
189 {"photo-flip-y", "Show reverse side of the board, up-down flip",
190 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
191 #define HA_photo_flip_y 12
193 {"ben-mode", ATTR_UNDOCUMENTED
,
194 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
195 #define HA_ben_mode 10
197 {"ben-flip-x", ATTR_UNDOCUMENTED
,
198 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
199 #define HA_ben_flip_x 11
201 {"ben-flip-y", ATTR_UNDOCUMENTED
,
202 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
203 #define HA_ben_flip_y 12
206 #define NUM_OPTIONS (sizeof(png_attribute_list)/sizeof(png_attribute_list[0]))
208 REGISTER_ATTRIBUTES (png_attribute_list
)
210 static HID_Attr_Val png_values
[NUM_OPTIONS
];
212 static const char *get_file_suffix(void)
216 fmt
= filetypes
[png_attribute_list
[HA_filetype
].default_val
.int_value
];
217 /* or is it filetypes[png_attribute_list[HA_filetype].default_val.int_value]; ? */
218 if (strcmp (fmt
, FMT_gif
) == 0) result
=".gif";
219 else if (strcmp (fmt
, FMT_jpg
) == 0) result
=".jpg";
220 else if (strcmp (fmt
, FMT_png
) == 0) result
=".png";
222 fprintf (stderr
, "Error: Invalid graphic file format\n");
228 static HID_Attribute
*
229 png_get_export_options (int *n
)
231 static char *last_made_filename
= 0;
232 const char *suffix
= get_file_suffix();
234 if (PCB
) derive_default_filename(PCB
->Filename
, &png_attribute_list
[HA_pngfile
], suffix
, &last_made_filename
);
238 return png_attribute_list
;
241 static int comp_layer
, solder_layer
;
244 group_for_layer (int l
)
246 if (l
< max_layer
+ 2 && l
>= 0)
247 return GetLayerGroupNumberByNumber (l
);
248 /* else something unique */
249 return max_layer
+ 3 + l
;
253 layer_sort (const void *va
, const void *vb
)
257 int al
= group_for_layer (a
);
258 int bl
= group_for_layer (b
);
261 if (a
>= 0 && a
<= max_layer
+ 1)
263 int aside
= (al
== solder_layer
? 0 : al
== comp_layer
? 2 : 1);
264 int bside
= (bl
== solder_layer
? 0 : bl
== comp_layer
? 2 : 1);
266 return bside
- aside
;
273 static char *filename
;
274 static BoxType
*bounds
;
275 static int in_mono
, as_shown
;
278 png_hid_export_to_file (FILE * the_file
, HID_Attr_Val
* options
)
281 static int saved_layer_stack
[MAX_LAYER
];
289 region
.X2
= PCB
->MaxWidth
;
290 region
.Y2
= PCB
->MaxHeight
;
292 if (options
[HA_only_visible
].int_value
)
293 bounds
= GetDataBoundingBox (PCB
->Data
);
297 memset (print_group
, 0, sizeof (print_group
));
298 memset (print_layer
, 0, sizeof (print_layer
));
300 for (i
= 0; i
< max_layer
; i
++)
302 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
303 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
304 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
306 print_group
[GetLayerGroupNumberByNumber (max_layer
)] = 1;
307 print_group
[GetLayerGroupNumberByNumber (max_layer
+ 1)] = 1;
308 for (i
= 0; i
< max_layer
; i
++)
309 if (print_group
[GetLayerGroupNumberByNumber (i
)])
312 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
313 as_shown
= options
[HA_as_shown
].int_value
;
314 if (!options
[HA_as_shown
].int_value
)
316 comp_layer
= GetLayerGroupNumberByNumber (max_layer
+ COMPONENT_LAYER
);
317 solder_layer
= GetLayerGroupNumberByNumber (max_layer
+ SOLDER_LAYER
);
318 qsort (LayerStack
, max_layer
, sizeof (LayerStack
[0]), layer_sort
);
320 save_flags
= PCB
->Flags
;
321 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
322 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
327 if (comp_layer
< solder_layer
)
328 for (i
= comp_layer
; i
<= solder_layer
; i
++)
329 photo_groups
[n
++] = i
;
331 for (i
= comp_layer
; i
>= solder_layer
; i
--)
332 photo_groups
[n
++] = i
;
337 for (i
=0, n
=photo_ngroups
-1; i
<n
; i
++, n
--)
339 int tmp
= photo_groups
[i
];
340 photo_groups
[i
] = photo_groups
[n
];
341 photo_groups
[n
] = tmp
;
347 lastbrush
= (void *) -1;
353 in_mono
= options
[HA_mono
].int_value
;
355 hid_expose_callback (&png_hid
, bounds
, 0);
357 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
359 if (!options
[HA_as_shown
].int_value
)
361 PCB
->Flags
= save_flags
;
366 blend (color_struct
*dest
, float a_amount
, color_struct
*a
, color_struct
*b
)
368 dest
->r
= a
->r
* a_amount
+ b
->r
* (1 - a_amount
);
369 dest
->g
= a
->g
* a_amount
+ b
->g
* (1 - a_amount
);
370 dest
->b
= a
->b
* a_amount
+ b
->b
* (1 - a_amount
);
374 rgb (color_struct
*dest
, int r
, int g
, int b
)
381 static int smshadows
[3][3] = {
387 static int shadows
[5][5] = {
391 { 1, -1, -1, -1, -1 },
392 { -1, -1, -1, -1, -1 },
395 /* black and white are 0 and 1 */
397 #define BOTTOM_SHADOW 3
400 ts_bs (gdImagePtr im
)
402 int x
, y
, sx
, sy
, si
;
403 for (x
=0; x
<gdImageSX(im
); x
++)
404 for (y
=0; y
<gdImageSY(im
); y
++)
407 for (sx
=-2; sx
<3; sx
++)
408 for (sy
=-2; sy
<3; sy
++)
409 if (!gdImageGetPixel (im
, x
+sx
, y
+sy
))
410 si
+= shadows
[sx
+2][sy
+2];
411 if (gdImageGetPixel (im
, x
, y
))
414 gdImageSetPixel (im
, x
, y
, TOP_SHADOW
);
416 gdImageSetPixel (im
, x
, y
, BOTTOM_SHADOW
);
422 ts_bs_sm (gdImagePtr im
)
424 int x
, y
, sx
, sy
, si
;
425 for (x
=0; x
<gdImageSX(im
); x
++)
426 for (y
=0; y
<gdImageSY(im
); y
++)
429 for (sx
=-1; sx
<2; sx
++)
430 for (sy
=-1; sy
<2; sy
++)
431 if (!gdImageGetPixel (im
, x
+sx
, y
+sy
))
432 si
+= smshadows
[sx
+1][sy
+1];
433 if (gdImageGetPixel (im
, x
, y
))
436 gdImageSetPixel (im
, x
, y
, TOP_SHADOW
);
438 gdImageSetPixel (im
, x
, y
, BOTTOM_SHADOW
);
444 png_do_export (HID_Attr_Val
* options
)
446 int save_ons
[MAX_LAYER
+ 2];
467 png_get_export_options (0);
468 for (i
= 0; i
< NUM_OPTIONS
; i
++)
469 png_values
[i
] = png_attribute_list
[i
].default_val
;
470 options
= png_values
;
473 if (options
[HA_photo_mode
].int_value
474 || options
[HA_ben_mode
].int_value
)
477 options
[HA_mono
].int_value
= 1;
478 options
[HA_as_shown
].int_value
= 0;
479 memset (photo_copper
, 0, sizeof(photo_copper
));
480 photo_silk
= photo_mask
= photo_drill
= 0;
482 if (options
[HA_photo_flip_x
].int_value
483 || options
[HA_ben_flip_x
].int_value
)
484 photo_flip
= PHOTO_FLIP_X
;
485 else if (options
[HA_photo_flip_y
].int_value
486 || options
[HA_ben_flip_y
].int_value
)
487 photo_flip
= PHOTO_FLIP_Y
;
494 filename
= options
[HA_pngfile
].str_value
;
496 filename
= "pcb-out.png";
498 /* figure out width and height of the board */
499 if (options
[HA_only_visible
].int_value
)
501 bbox
= GetDataBoundingBox (PCB
->Data
);
504 h
= bbox
->Y2
- bbox
->Y1
;
505 w
= bbox
->X2
- bbox
->X1
;
516 * figure out the scale factor we need to make the image
517 * fit in our specified PNG file size
519 xmax
= ymax
= dpi
= 0;
520 if (options
[HA_dpi
].int_value
!= 0)
522 dpi
= options
[HA_dpi
].int_value
;
525 fprintf (stderr
, "ERROR: dpi may not be < 0\n");
530 if (options
[HA_xmax
].int_value
> 0)
532 xmax
= options
[HA_xmax
].int_value
;
536 if (options
[HA_ymax
].int_value
> 0)
538 ymax
= options
[HA_ymax
].int_value
;
542 if (options
[HA_xymax
].int_value
> 0)
545 if (options
[HA_xymax
].int_value
< xmax
|| xmax
== 0)
546 xmax
= options
[HA_xymax
].int_value
;
547 if (options
[HA_xymax
].int_value
< ymax
|| ymax
== 0)
548 ymax
= options
[HA_xymax
].int_value
;
551 if (xmax
< 0 || ymax
< 0)
553 fprintf (stderr
, "ERROR: xmax and ymax may not be < 0\n");
560 * a scale of 1 means 1 pixel is 1/100 mil
561 * a scale of 100,000 means 1 pixel is 1 inch
562 * FIXME -- need to use a macro to go from PCB units
563 * so if we ever change pcb's internal units, this
566 scale
= 100000.0 / dpi
;
570 else if( xmax
== 0 && ymax
== 0)
572 fprintf(stderr
, "ERROR: You may not set both xmax, ymax,"
573 "and xy-max to zero\n");
580 && ((w
/ xmax
) > (h
/ ymax
)) ) )
594 im
= gdImageCreate (w
, h
);
598 * Allocate white and black -- the first color allocated
599 * becomes the background color
602 white
= (color_struct
*) malloc (sizeof (color_struct
));
603 white
->r
= white
->g
= white
->b
= 255;
604 if (options
[HA_use_alpha
].int_value
)
608 white
->c
= gdImageColorAllocateAlpha (im
, white
->r
, white
->g
, white
->b
, white
->a
);
610 black
= (color_struct
*) malloc (sizeof (color_struct
));
611 black
->r
= black
->g
= black
->b
= black
->a
= 0;
612 black
->c
= gdImageColorAllocate (im
, black
->r
, black
->g
, black
->b
);
614 f
= fopen (filename
, "wb");
621 if (!options
[HA_as_shown
].int_value
)
622 hid_save_and_show_layer_ons (save_ons
);
624 png_hid_export_to_file (f
, options
);
626 if (!options
[HA_as_shown
].int_value
)
627 hid_restore_layer_ons (save_ons
);
632 color_struct white
, black
, fr4
;
634 rgb (&white
, 255, 255, 255);
635 rgb (&black
, 0, 0, 0);
636 rgb (&fr4
, 70, 70, 70);
640 ts_bs (photo_copper
[photo_groups
[0]]);
642 ts_bs_sm (photo_mask
);
645 int black
=gdImageColorResolve(photo_outline
, 0x00, 0x00, 0x00);
647 // go all the way around the image, trying to fill the outline
648 for (x
=0; x
<gdImageSX(im
); x
++) {
649 gdImageFillToBorder(photo_outline
, x
, 0, black
, black
);
650 gdImageFillToBorder(photo_outline
, x
, gdImageSY(im
)-1, black
, black
);
652 for (y
=1; y
<gdImageSY(im
)-1; y
++) {
653 gdImageFillToBorder(photo_outline
, 0, y
, black
, black
);
654 gdImageFillToBorder(photo_outline
, gdImageSX(im
)-1, y
, black
, black
);
660 for (x
=0; x
<gdImageSX (im
); x
++)
662 for (y
=0; y
<gdImageSY (im
); y
++)
669 transparent
=gdImageGetPixel(photo_outline
, x
, y
);
674 mask
= photo_mask
? gdImageGetPixel (photo_mask
, x
, y
) : 0;
675 silk
= photo_silk
? gdImageGetPixel (photo_silk
, x
, y
) : 0;
677 if (gdImageGetPixel (photo_copper
[photo_groups
[1]], x
, y
))
678 rgb (&cop
, 40, 40, 40);
680 rgb (&cop
, 100, 100, 110);
682 if (photo_ngroups
== 2)
683 blend (&cop
, 0.3, &cop
, &fr4
);
685 cc
= gdImageGetPixel (photo_copper
[photo_groups
[0]], x
, y
);
691 rgb (&cop
, 220, 145, 230);
694 rgb (&cop
, 140, 150, 160);
696 r
= (random() % 5 - 2) * 2;
703 if (cc
== TOP_SHADOW
)
705 cop
.r
= 255 - (255 - cop
.r
) * 0.7;
706 cop
.g
= 255 - (255 - cop
.g
) * 0.7;
707 cop
.b
= 255 - (255 - cop
.b
) * 0.7;
709 if (cc
== BOTTOM_SHADOW
)
717 if (photo_drill
&& !gdImageGetPixel (photo_drill
, x
, y
))
724 if (silk
== TOP_SHADOW
)
725 rgb (&p
, 255, 255, 255);
726 else if (silk
== BOTTOM_SHADOW
)
727 rgb (&p
, 192, 192, 192);
729 rgb (&p
, 224, 224, 224);
736 if (mask
== TOP_SHADOW
)
737 blend (&p
, 0.7, &p
, &white
);
738 if (mask
== BOTTOM_SHADOW
)
739 blend (&p
, 0.7, &p
, &black
);
744 if (options
[HA_use_alpha
].int_value
) {
747 gdImageColorResolveAlpha(im
, 0, 0, 0, 127):\
748 gdImageColorResolveAlpha(im
, p
.r
, p
.g
, p
.b
, 0);
752 gdImageColorResolve(im
, 0, 0, 0):\
753 gdImageColorResolve(im
, p
.r
, p
.g
, p
.b
);
756 if (photo_flip
== PHOTO_FLIP_X
)
757 gdImageSetPixel (im
, gdImageSX (im
) - x
- 1, y
, cc
);
758 else if (photo_flip
== PHOTO_FLIP_Y
)
759 gdImageSetPixel (im
, x
, gdImageSY (im
) - y
- 1, cc
);
761 gdImageSetPixel (im
, x
, y
, cc
);
766 /* actually write out the image */
767 fmt
= filetypes
[options
[HA_filetype
].int_value
];
769 if (strcmp (fmt
, FMT_gif
) == 0)
770 #ifdef HAVE_GDIMAGEGIF
778 else if (strcmp (fmt
, FMT_jpg
) == 0)
779 #ifdef HAVE_GDIMAGEJPEG
780 gdImageJpeg (im
, f
, -1);
787 else if (strcmp (fmt
, FMT_png
) == 0)
788 #ifdef HAVE_GDIMAGEPNG
797 fprintf (stderr
, "Error: Invalid graphic file format."
798 " This is a bug. Please report it.\n");
805 extern void hid_parse_command_line (int *argc
, char ***argv
);
808 png_parse_arguments (int *argc
, char ***argv
)
810 hid_register_attributes (png_attribute_list
,
811 sizeof (png_attribute_list
) /
812 sizeof (png_attribute_list
[0]));
813 hid_parse_command_line (argc
, argv
);
821 png_set_layer (const char *name
, int group
, int empty
)
823 int idx
= (group
>= 0
825 max_layer
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
827 name
= PCB
->Data
->Layer
[idx
].Name
;
829 if (idx
>= 0 && idx
< max_layer
&& !print_layer
[idx
])
831 if (SL_TYPE (idx
) == SL_ASSY
|| SL_TYPE (idx
) == SL_FAB
)
834 if (strcmp (name
, "invisible") == 0)
837 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
838 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
840 if (SL_TYPE (idx
) == SL_PASTE
)
850 photo_im
= &photo_silk
;
852 case SL (SILK
, BOTTOM
):
855 photo_im
= &photo_silk
;
861 photo_im
= &photo_mask
;
863 case SL (MASK
, BOTTOM
):
866 photo_im
= &photo_mask
;
871 photo_im
= &photo_drill
;
878 if (strcasecmp (name
, "outline") == 0)
879 photo_im
= &photo_outline
;
881 photo_im
= photo_copper
+ group
;
888 static color_struct
*black
= NULL
, *white
= NULL
;
889 *photo_im
= gdImageCreate (gdImageSX (im
), gdImageSY (im
));
891 white
= (color_struct
*) malloc (sizeof (color_struct
));
892 white
->r
= white
->g
= white
->b
= 255;
894 white
->c
= gdImageColorAllocate (*photo_im
, white
->r
, white
->g
, white
->b
);
896 black
= (color_struct
*) malloc (sizeof (color_struct
));
897 black
->r
= black
->g
= black
->b
= black
->a
= 0;
898 black
->c
= gdImageColorAllocate (*photo_im
, black
->r
, black
->g
, black
->b
);
900 if (idx
== SL (PDRILL
, 0)
901 || idx
== SL (UDRILL
, 0))
902 gdImageFilledRectangle (*photo_im
, 0, 0, gdImageSX (im
), gdImageSY (im
), black
->c
);
913 case SL (SILK
, BOTTOM
):
915 return PCB
->ElementOn
;
919 case SL (MASK
, BOTTOM
):
920 return TEST_FLAG (SHOWMASKFLAG
, PCB
) && SL_MYSIDE (idx
);
932 case SL (SILK
, BOTTOM
):
944 hidGC rv
= (hidGC
) malloc (sizeof (hid_gc_struct
));
945 rv
->me_pointer
= &png_hid
;
948 rv
->color
= (color_struct
*) malloc (sizeof (color_struct
));
949 rv
->color
->r
= rv
->color
->g
= rv
->color
->b
= rv
->color
->a
= 0;
955 png_destroy_gc (hidGC gc
)
961 png_use_mask (int use_it
)
967 png_set_color (hidGC gc
, const char *name
)
977 if (strcmp (name
, "erase") == 0 || strcmp (name
, "drill") == 0)
979 /* FIXME -- should be background, not white */
986 if (in_mono
|| (strcmp (name
, "#000000") == 0))
992 if (hid_cache_color (0, name
, &cval
, &color_cache
))
994 gc
->color
= cval
.ptr
;
996 else if (name
[0] == '#')
998 gc
->color
= (color_struct
*) malloc (sizeof (color_struct
));
999 sscanf (name
+ 1, "%2x%2x%2x", &(gc
->color
->r
), &(gc
->color
->g
),
1002 gdImageColorAllocate (im
, gc
->color
->r
, gc
->color
->g
, gc
->color
->b
);
1003 cval
.ptr
= gc
->color
;
1004 hid_cache_color (1, name
, &cval
, &color_cache
);
1008 printf ("WE SHOULD NOT BE HERE!!!\n");
1015 png_set_line_cap (hidGC gc
, EndCapStyle style
)
1021 png_set_line_width (hidGC gc
, int width
)
1027 png_set_draw_xor (hidGC gc
, int xor)
1033 png_set_draw_faded (hidGC gc
, int faded
)
1039 png_set_line_cap_angle (hidGC gc
, int x1
, int y1
, int x2
, int y2
)
1049 if (gc
->me_pointer
!= &png_hid
)
1051 fprintf (stderr
, "Fatal: GC from another HID passed to png HID\n");
1055 if (linewidth
!= gc
->width
)
1057 /* Make sure the scaling doesn't erase lines completely */
1058 if (SCALE (gc
->width
) == 0 && gc
->width
> 0)
1059 gdImageSetThickness (im
, 1);
1061 gdImageSetThickness (im
, SCALE (gc
->width
));
1062 linewidth
= gc
->width
;
1066 if (lastbrush
!= gc
->brush
|| need_brush
)
1084 r
= SCALE (gc
->width
);
1085 if (r
== 0 && gc
->width
> 0)
1087 sprintf (name
, "#%.2x%.2x%.2x_%c_%d", gc
->color
->r
, gc
->color
->g
,
1088 gc
->color
->b
, type
, r
);
1090 if (hid_cache_color (0, name
, &bval
, &brush_cache
))
1092 gc
->brush
= bval
.ptr
;
1097 gc
->brush
= gdImageCreate (r
, r
);
1098 bg
= gdImageColorAllocate (gc
->brush
, 255, 255, 255);
1100 gdImageColorAllocateAlpha (gc
->brush
, gc
->color
->r
, gc
->color
->g
,
1102 gdImageColorTransparent (gc
->brush
, bg
);
1105 * if we shrunk to a radius/box width of zero, then just use
1106 * a single pixel to draw with.
1109 gdImageFilledRectangle (gc
->brush
, 0, 0, 0, 0, fg
);
1114 gdImageFilledEllipse (gc
->brush
, r
/2, r
/2, r
, r
, fg
);
1115 /* Make sure the ellipse is the right exact size. */
1116 gdImageSetPixel (gc
->brush
, 0, r
/2, fg
);
1117 gdImageSetPixel (gc
->brush
, r
-1, r
/2, fg
);
1118 gdImageSetPixel (gc
->brush
, r
/2, 0, fg
);
1119 gdImageSetPixel (gc
->brush
, r
/2, r
-1, fg
);
1122 gdImageFilledRectangle (gc
->brush
, 0, 0, r
-1, r
-1, fg
);
1124 bval
.ptr
= gc
->brush
;
1125 hid_cache_color (1, name
, &bval
, &brush_cache
);
1128 gdImageSetBrush (im
, gc
->brush
);
1129 lastbrush
= gc
->brush
;
1133 #define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
1134 if (lastcolor
!= CBLEND (gc
))
1136 if (is_drill
|| is_mask
)
1139 fprintf (f
, "%d gray\n", gc
->erase
? 0 : 1);
1151 r
= 0.8 * 255 + 0.2 * r
;
1152 g
= 0.8 * 255 + 0.2 * g
;
1153 b
= 0.8 * 255 + 0.2 * b
;
1156 if (gc
->r
== gc
->g
&& gc
->g
== gc
->b
)
1157 fprintf (f
, "%g gray\n", r
/ 255.0);
1159 fprintf (f
, "%g %g %g rgb\n", r
/ 255.0, g
/ 255.0, b
/ 255.0);
1161 lastcolor
= CBLEND (gc
);
1167 png_draw_rect (hidGC gc
, int x1
, int y1
, int x2
, int y2
)
1170 gdImageRectangle (im
,
1171 SCALE_X (x1
), SCALE_Y (y1
),
1172 SCALE_X (x2
), SCALE_Y (y2
), gc
->color
->c
);
1176 png_fill_rect (hidGC gc
, int x1
, int y1
, int x2
, int y2
)
1179 gdImageSetThickness (im
, 0);
1181 gdImageFilledRectangle (im
, SCALE_X (x1
), SCALE_Y (y1
),
1182 SCALE_X (x2
)-1, SCALE_Y (y2
)-1, gc
->color
->c
);
1186 png_draw_line (hidGC gc
, int x1
, int y1
, int x2
, int y2
)
1188 if (x1
== x2
&& y1
== y2
)
1190 int w
= gc
->width
/ 2;
1191 png_fill_rect (gc
, x1
- w
, y1
- w
, x1
+ w
, y1
+ w
);
1196 gdImageSetThickness (im
, 0);
1198 if(gc
->cap
!= Square_Cap
|| x1
== x2
|| y1
== y2
)
1200 gdImageLine (im
, SCALE_X (x1
), SCALE_Y (y1
),
1201 SCALE_X (x2
), SCALE_Y (y2
), gdBrushed
);
1206 * if we are drawing a line with a square end cap and it is
1207 * not purely horizontal or vertical, then we need to draw
1208 * it as a filled polygon.
1210 int fg
= gdImageColorResolve (im
, gc
->color
->r
, gc
->color
->g
,
1212 w
= gc
->width
, dx
= x2
- x1
, dy
= y2
- y1
, dwx
, dwy
;
1214 double l
= sqrt (dx
* dx
+ dy
* dy
) * 2 * scale
;
1215 dwx
= -w
/ l
* dy
; dwy
= w
/ l
* dx
;
1216 p
[0].x
= SCALE_X (x1
) + dwx
- dwy
; p
[0].y
= SCALE_Y(y1
) + dwy
+ dwx
;
1217 p
[1].x
= SCALE_X (x1
) - dwx
- dwy
; p
[1].y
= SCALE_Y(y1
) - dwy
+ dwx
;
1218 p
[2].x
= SCALE_X (x2
) - dwx
+ dwy
; p
[2].y
= SCALE_Y(y2
) - dwy
- dwx
;
1219 p
[3].x
= SCALE_X (x2
) + dwx
+ dwy
; p
[3].y
= SCALE_Y(y2
) + dwy
- dwx
;
1220 gdImageFilledPolygon (im
, p
, 4, fg
);
1225 png_draw_arc (hidGC gc
, int cx
, int cy
, int width
, int height
,
1226 int start_angle
, int delta_angle
)
1231 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
1232 * in pcb, 0 degrees is to the left and +90 degrees is down
1234 start_angle
= 180 - start_angle
;
1235 delta_angle
= -delta_angle
;
1236 if (delta_angle
> 0)
1239 ea
= start_angle
+ delta_angle
;
1243 sa
= start_angle
+ delta_angle
;
1248 * make sure we start between 0 and 360 otherwise gd does
1263 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
1264 cx
, cy
, width
, height
, start_angle
, delta_angle
, sa
, ea
);
1265 printf ("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
1266 im
, SCALE_X (cx
), SCALE_Y (cy
),
1267 SCALE (width
), SCALE (height
), sa
, ea
, gc
->color
->c
);
1270 gdImageSetThickness (im
, 0);
1272 gdImageArc (im
, SCALE_X (cx
), SCALE_Y (cy
),
1273 SCALE (2 * width
), SCALE (2 * height
), sa
, ea
, gdBrushed
);
1277 png_fill_circle (hidGC gc
, int cx
, int cy
, int radius
)
1281 gdImageSetThickness (im
, 0);
1283 gdImageFilledEllipse (im
, SCALE_X (cx
), SCALE_Y (cy
),
1284 SCALE (2 * radius
), SCALE (2 * radius
), gc
->color
->c
);
1289 png_fill_polygon (hidGC gc
, int n_coords
, int *x
, int *y
)
1294 points
= (gdPoint
*) malloc (n_coords
* sizeof (gdPoint
));
1297 fprintf (stderr
, "ERROR: png_fill_polygon(): malloc failed\n");
1302 for (i
= 0; i
< n_coords
; i
++)
1304 points
[i
].x
= SCALE_X (x
[i
]);
1305 points
[i
].y
= SCALE_Y (y
[i
]);
1307 gdImageSetThickness (im
, 0);
1309 gdImageFilledPolygon (im
, points
, n_coords
, gc
->color
->c
);
1314 png_calibrate (double xval
, double yval
)
1320 png_set_crosshair (int x
, int y
, int a
)
1327 "GIF/JPEG/PNG export.",
1331 1, /* poly before */
1334 png_get_export_options
,
1336 png_parse_arguments
,
1337 0 /* png_invalidate_wh */ ,
1338 0 /* png_invalidate_lr */ ,
1339 0 /* png_invalidate_all */ ,
1349 png_set_line_cap_angle
,
1355 common_fill_pcb_polygon
,
1356 0 /* png_thindraw_pcb_polygon */ ,
1359 0 /* png_shift_is_pressed */ ,
1360 0 /* png_control_is_pressed */ ,
1361 0 /* png_get_coords */ ,
1363 0 /* png_add_timer */ ,
1364 0 /* png_stop_timer */ ,
1365 0 /* png_watch_file */ ,
1366 0 /* png_unwatch_file */ ,
1367 0 /* png_add_block_hook */ ,
1368 0 /* png_stop_block_hook */ ,
1371 0 /* png_confirm_dialog */ ,
1372 0 /* png_close_confirm_dialog */ ,
1373 0 /* png_report_dialog */ ,
1374 0 /* png_prompt_for */ ,
1375 0 /* png_fileselect */ ,
1376 0 /* png_attribute_dialog */ ,
1377 0 /* png_show_item */ ,
1379 0 /* png_progress */
1382 #include "dolists.h"
1387 apply_default_hid (&png_hid
, 0);
1388 hid_register_hid (&png_hid
);
1390 #include "png_lists.h"