File Coverage

blib/lib/CAD/Drawing/IO/Image.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package CAD::Drawing::IO::Image;
2             our $VERSION = '0.02';
3              
4 1     1   33736 use CAD::Drawing;
  0            
  0            
5             use CAD::Drawing::Defined;
6              
7             use warnings;
8             use strict;
9              
10             use Carp;
11             use UNIVERSAL qw(isa);
12              
13             use Image::Magick;
14              
15             ########################################################################
16             =pod
17              
18             =head1 NAME
19              
20             CAD::Drawing::IO::Image - Output methods for images
21              
22             =head1 AUTHOR
23              
24             Eric L. Wilhelm
25              
26             http://scratchcomputing.com
27              
28             =head1 COPYRIGHT
29              
30             This module is copyright (C) 2004-2006 by Eric L. Wilhelm. Portions
31             copyright (C) 2003 by Eric L. Wilhelm and A. Zahner Co.
32              
33             =head1 LICENSE
34              
35             This module is distributed under the same terms as Perl. See the Perl
36             source package for details.
37              
38             You may use this software under one of the following licenses:
39              
40             (1) GNU General Public License
41             (found at http://www.gnu.org/copyleft/gpl.html)
42             (2) Artistic License
43             (found at http://www.perl.com/pub/language/misc/Artistic.html)
44              
45             =head1 NO WARRANTY
46              
47             This software is distributed with ABSOLUTELY NO WARRANTY. The author,
48             his former employer, and any other contributors will in no way be held
49             liable for any loss or damages resulting from its use.
50              
51             =head1 Modifications
52              
53             The source code of this module is made freely available and
54             distributable under the GPL or Artistic License. Modifications to and
55             use of this software must adhere to one of these licenses. Changes to
56             the code should be noted as such and this notification (as well as the
57             above copyright information) must remain intact on all copies of the
58             code.
59              
60             Additionally, while the author is actively developing this code,
61             notification of any intended changes or extensions would be most helpful
62             in avoiding repeated work for all parties involved. Please contact the
63             author with any such development plans.
64              
65             =head1 SEE ALSO
66              
67             CAD::Drawing
68             Image::Magick
69              
70             =cut
71              
72             ########################################################################
73              
74             =head1 Requisite Plug-in Functions
75              
76             See CAD::Drawing::IO for a description of the plug-in architecture.
77              
78             =cut
79             ########################################################################
80             # the following are required to be a disc I/O plugin:
81             our $can_save_type = "img";
82              
83             =head2 check_type
84              
85             Returns true if $type is "img" or $filename matches one of the
86             ImageMagick type extensions.
87              
88             $fact = check_type($filename, $type);
89              
90             =cut
91             sub check_type {
92             my ($filename, $type) = @_;
93             if(defined($type)) {
94             # FIXME: need a better method for spec'ing arbitrary type
95             ($type eq "img") and return("img");
96             return();
97             }
98             elsif($filename =~ m/.*\.(\w+)$/) {
99             my $ext = $1;
100             ($ext =~ m/tif|gif|jpg|png|bmp|fax|fig|pict|psd|xcf/) &&
101             return("img");
102             }
103             return();
104             } # end subroutine check_type definition
105             ########################################################################
106              
107             =head1 Methods
108              
109             =cut
110             ########################################################################
111              
112             =head2 load
113              
114             Requires vectorization...
115              
116             load();
117              
118             =cut
119             sub load {
120             croak("load image not written");
121             } # end subroutine load definition
122             ########################################################################
123              
124             =head2 save
125              
126             save();
127              
128             =cut
129             sub save {
130             my $self = shift;
131             my ($filename, $opt) = @_;
132             our %img_out_functions;
133             my %opts;
134             my $accuracy = 1; # digits of accuracy with which to bother
135             if(isa($opt, 'HASH')) {
136             %opts = %$opt;
137             }
138             else {
139             $opt and croak("not a hash");
140             }
141             my $imwidth = $opts{width};
142             my $imheight = $opts{height};
143             (defined($imwidth) and defined($imheight)) or
144             carp("can't save image without width and height\n");
145             my $outobj = Image::Magick->new(size=>"${imwidth}x${imheight}");
146             my $bgcolor = "white";
147             my $defaultcolor = "black";
148             if($opts{defaultcolor}) {
149             $defaultcolor = $opts{defaultcolor};
150             }
151             # $CAD::Drawing::default_color{$self} = $defaultcolor; # XXX ?
152             if($opts{bgcolor}) {
153             $bgcolor = $opts{bgcolor};
154             }
155             $outobj->ReadImage("xc:$bgcolor");
156             if($opts{transparent}) {
157             $outobj->Transparent(color=>"$bgcolor");
158             }
159             unless($opts{prescaled}) {
160             carp("must prescale drawing object for now\n");
161             # FIXME: this should now go into the fit-to-bound deal
162             }
163             # $outobj->Set(antialias=>"False");
164             my $matte = "white";
165             $outobj->Set(mattecolor=>$matte);
166             $opts{imtype} and $outobj->Set(type => $opts{imtype});
167             $opts{imcomp} and $outobj->Set(compression => $opts{imcomp});
168             my %img_data = (
169             imobj => $outobj,
170             height => $imheight,
171             width => $imwidth,
172             accuracy => $accuracy,
173             bgcolor => $bgcolor,
174             defcolor => $defaultcolor,
175             # FIXME: need some way to make this selective?
176             filled => $opts{'filled'} || 'none',
177             lw => defined($opts{'linewidth'}) ? $opts{'linewidth'} : 3.0,
178             font => $opts{font} ? $opts{font} : 'arial',
179             );
180             my $count = $self->outloop(\%img_out_functions, \%img_data);
181             my $err = $outobj->Write($filename);
182             $err and die;
183             return($count);
184             } # end subroutine save definition
185             ########################################################################
186              
187             our %img_out_functions = (
188             lines => sub {
189             my ($obj, $data) = @_;
190             my $img = $data->{imobj};
191             my $acc = $data->{accuracy};
192             my @pts = map({
193             [map({sprintf("%0.${acc}f", $_)} (@$_)[0,1])]
194             } @{$obj->{pts}});
195             ## warn "points: @{$pts[0]} and @{$pts[1]}\n";
196             # XXX is this needed?
197             if(($pts[0][0] == $pts[1][0]) and ($pts[0][1] == $pts[1][1])) {
198             ## warn "bad line\n";
199             return();
200             }
201             $pts[$_][1] = $data->{height} - $pts[$_][1] for 0..1;
202             my $pt_string = join(" ", map({join(",", @$_)} @pts));
203             my $color = image_color($obj->{color}, $data);
204             $img->Draw(
205             primitive => 'line',
206             strokewidth => $obj->{lw} || $data->{lw},
207             stroke => $color,
208             fill => $data->{filled},
209             points => $pt_string,
210             );
211             },
212             plines => sub {
213             my ($obj, $data) = @_;
214             my $img = $data->{imobj};
215             my $acc = $data->{accuracy};
216             my @pts = map({
217             [map({sprintf("%0.${acc}f", $_)} (@$_)[0,1])]
218             } @{$obj->{pts}});
219             $pts[$_][1] = $data->{height} - $pts[$_][1] for 0..$#pts;
220             my $pt_string = join(" ", map({join(",", @$_)} @pts));
221             my $color = image_color($obj->{color}, $data);
222             $img->Draw(
223             primitive => $obj->{closed} ? 'polygon' : 'polyline',
224             strokewidth => $obj->{lw} || $data->{lw},
225             stroke => $color,
226             fill => $data->{filled},
227             points => $pt_string,
228             );
229             },
230             circles => sub {
231             my ($obj, $data) = @_;
232             my $img = $data->{imobj};
233             my $acc = $data->{accuracy};
234             my @pt = (@{$obj->{pt}})[0,1];
235             $pt[1] = $data->{height} - $pt[1];
236             my $r = $obj->{rad};
237             my @rec = ( # some consistency would be nice!
238             #[map({sprintf("%0.${acc}f", $_ - $r)} @pt)],
239             [map({sprintf("%0.${acc}f", $_)} @pt)],
240             [map({sprintf("%0.${acc}f", $_)} $pt[0] - $r, $pt[1])],
241             );
242             my $pt_string = join(" ", map({join(",", @$_)} @rec));
243             my $color = image_color($obj->{color}, $data);
244             $img->Draw(
245             primitive => 'circle',
246             strokewidth => $data->{lw},
247             stroke => $color,
248             fill => $data->{filled},
249             antialias => 'true',
250             points => $pt_string,
251             );
252              
253             },
254             texts => sub {
255             my ($obj, $data) = @_;
256             my $img = $data->{imobj};
257             my $acc = $data->{accuracy};
258             my @pt = map({sprintf("%0.${acc}f", $_)} (@{$obj->{pt}})[0,1]);
259             $pt[1] = $data->{height} - $pt[1];
260             my $height = sprintf("%0.0f", $obj->{height});
261             ## warn "handling text : $obj->{string} (h=$height)\n";
262             ## warn "point: $pt[0], $pt[1]\n";
263             my $color = image_color($obj->{color}, $data);
264             my $res = $img->Annotate(
265             x => $pt[0],
266             y => $pt[1],
267             text => $obj->{string},
268             font => $data->{font},
269             stroke => $color,
270             fill => $color,
271             antialias => 'true',
272             pointsize => $height,
273             rotate => $obj->{angle} ? (-$obj->{angle} * 180 / $pi) : 0,
274             );
275             warn $res if $res;
276             },
277             arcs => sub {
278             my ($obj, $data) = @_;
279             my $img = $data->{imobj};
280             my $acc = $data->{accuracy};
281             my @pt = @{$obj->{pt}}[0,1];
282             $pt[1] = $data->{height} - $pt[1];
283             my $r = $obj->{rad};
284             my @rec = (
285             [map({sprintf("%0.${acc}f", $_ - $r)} @pt)],
286             [map({sprintf("%0.${acc}f", $_ + $r)} @pt)],
287             );
288             my @angs = reverse(map({-$_ * 180/$pi} @{$obj->{angs}})); # whee!
289             my $pt_string = join(" ", map({join(",", @$_)} @rec, \@angs));
290             ## warn "pts: $pt_string\n";
291             my $color = image_color($obj->{color}, $data);
292             ## warn "color: $color";
293             $img->Draw(
294             primitive => 'arc',
295             strokewidth => $data->{lw},
296             stroke => $color,
297             fill => $data->{filled},
298             antialias => 'true',
299             # XXX super-unstable interface completely broken in 5.5.7.9-1.1?
300             points => $pt_string,
301             # points => '40,40 80,80 0,90',
302             );
303              
304             },
305             ); # end img_out_functions
306             $img_out_functions{points} = 0 ?
307             sub {
308             my ($obj, $data) = @_;
309             my $img = $data->{imobj};
310             my $acc = $data->{accuracy};
311             my @pt = map({sprintf("%0.${acc}f", $_)} (@{$obj->{pt}})[0,1]);
312             $pt[1] = $data->{height} - $pt[1];
313             my $pt_string = join(",", @pt);
314             my $color = image_color($obj->{color}, $data);
315             $img->Draw(
316             primitive => 'point',
317             stroke => $color,
318             points => $pt_string,
319             );
320             }
321             :
322             sub {
323             my ($obj, $data) = @_;
324             $img_out_functions{circles}->(
325             {%$obj, rad => 0.1},
326             {%$data, lw => 1, filled => 1}
327             );
328             };
329              
330             =head2 image_color
331              
332             image_color($color, $data);
333              
334             =cut
335             sub image_color {
336             my ($color, $data) = @_;
337             # XXX fixme: %no should be based on defcolor
338             my %no = map( { $_ => 1} 0, 7, 256);
339             $no{$color} && return($data->{defcolor});
340             return($aci2hex[$color]);
341             } # end subroutine image_color definition
342             ########################################################################
343             1;