line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Copyright 2010, 2011, 2012 Kevin Ryde |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# This file is part of Image-Base-PNGwriter. |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
# Image-Base-PNGwriter is free software; you can redistribute it and/or |
6
|
|
|
|
|
|
|
# modify it under the terms of the GNU General Public License as published |
7
|
|
|
|
|
|
|
# by the Free Software Foundation; either version 3, or (at your option) any |
8
|
|
|
|
|
|
|
# later version. |
9
|
|
|
|
|
|
|
# |
10
|
|
|
|
|
|
|
# Image-Base-PNGwriter is distributed in the hope that it will be useful, |
11
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
12
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
13
|
|
|
|
|
|
|
# Public License for more details. |
14
|
|
|
|
|
|
|
# |
15
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License along |
16
|
|
|
|
|
|
|
# with Image-Base-PNGwriter. If not, see . |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# Crib notes: |
20
|
|
|
|
|
|
|
# ->plot() and in turn everything using that clips to the image size |
21
|
|
|
|
|
|
|
# automatically |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
package Image::Base::PNGwriter; |
24
|
|
|
|
|
|
|
# Image::Base is good for 5.004 or some such far back, though |
25
|
|
|
|
|
|
|
# Image::PNGwriter 0.01 requires 5.8.5, so that's the actual minimum. It |
26
|
|
|
|
|
|
|
# looks like Image::PNGwriter could probably go earlier, unless maybe it |
27
|
|
|
|
|
|
|
# needs a new enough xsubpp for C++. |
28
|
3
|
|
|
3
|
|
55552
|
use 5.006; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
417
|
|
29
|
3
|
|
|
3
|
|
18
|
use strict; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
105
|
|
30
|
3
|
|
|
3
|
|
15
|
use warnings; |
|
3
|
|
|
|
|
9
|
|
|
3
|
|
|
|
|
116
|
|
31
|
3
|
|
|
3
|
|
15
|
use Carp; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
258
|
|
32
|
3
|
|
|
3
|
|
5774
|
use Image::PNGwriter; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
our $VERSION = 8; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# version 1.12 for ellipse() $fill |
37
|
|
|
|
|
|
|
# version 1.16 for diamond() |
38
|
|
|
|
|
|
|
use Image::Base 1.12; |
39
|
|
|
|
|
|
|
our @ISA = ('Image::Base'); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# uncomment this to run the ### lines |
42
|
|
|
|
|
|
|
#use Devel::Comments; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
# Cribs: |
45
|
|
|
|
|
|
|
# |
46
|
|
|
|
|
|
|
# /usr/include/pngwriter.h |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
use constant _DEFAULT_PALETTE => { 'black' => [ 0,0,0 ], |
49
|
|
|
|
|
|
|
'white' => [ 1,1,1 ] }; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub new { |
52
|
|
|
|
|
|
|
my ($class, %params) = @_; |
53
|
|
|
|
|
|
|
### Image-Base-PNGwriter new(): %params |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
# $obj->new(...) means make a copy, with some extra settings |
56
|
|
|
|
|
|
|
if (ref $class) { |
57
|
|
|
|
|
|
|
# needs the pngwriter copy-constructor ... |
58
|
|
|
|
|
|
|
die "Image cloning not yet implemented"; |
59
|
|
|
|
|
|
|
# my $self = $class; |
60
|
|
|
|
|
|
|
# $class = ref $class; |
61
|
|
|
|
|
|
|
# if (! defined $params{'-pngwriter'}) { |
62
|
|
|
|
|
|
|
# $params{'-pngwriter'} = $self->get('-pngwriter')->clone; |
63
|
|
|
|
|
|
|
# } |
64
|
|
|
|
|
|
|
# # inherit everything else |
65
|
|
|
|
|
|
|
# %params = (%$self, %params); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# -palette not yet documented, maybe call it -cindex anyway |
69
|
|
|
|
|
|
|
# FIXME: make a per-instance anon hash |
70
|
|
|
|
|
|
|
my $self = bless { -palette => _DEFAULT_PALETTE, |
71
|
|
|
|
|
|
|
-zlib_compression => -1, |
72
|
|
|
|
|
|
|
}, $class; |
73
|
|
|
|
|
|
|
if (! defined $params{'-pngwriter'}) { |
74
|
|
|
|
|
|
|
my $width = delete $params{'-width'}; |
75
|
|
|
|
|
|
|
if (! defined $width) { $width = 1; } |
76
|
|
|
|
|
|
|
my $height = delete $params{'-height'}; |
77
|
|
|
|
|
|
|
if (! defined $height) { $height = 1; } |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# can't pass undef to Image::PNGwriter->new |
80
|
|
|
|
|
|
|
my $filename = $params{'-file'}; |
81
|
|
|
|
|
|
|
if (! defined $filename) { $filename = ''; } |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# the filename to new() supplied is not read, just recorded in the $pw |
84
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'} |
85
|
|
|
|
|
|
|
= Image::PNGwriter->new ($width, $height, |
86
|
|
|
|
|
|
|
0, # background |
87
|
|
|
|
|
|
|
$filename); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
my $filename = delete $params{'-file'}; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
$self->set (%params); |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
if (defined $filename) { |
94
|
|
|
|
|
|
|
$self->load ($filename); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
### $self |
97
|
|
|
|
|
|
|
return $self; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
my %attr_to_get_method = (-width => 'getwidth', |
101
|
|
|
|
|
|
|
-height => 'getheight', |
102
|
|
|
|
|
|
|
# these not documented yet ... |
103
|
|
|
|
|
|
|
-bitdepth => 'getbitdepth', |
104
|
|
|
|
|
|
|
-gamma => 'getgamma', |
105
|
|
|
|
|
|
|
-colortype => 'getcolortype'); |
106
|
|
|
|
|
|
|
sub _get { |
107
|
|
|
|
|
|
|
my ($self, $key) = @_; |
108
|
|
|
|
|
|
|
### Image-Base-PNGwriter _get(): $key |
109
|
|
|
|
|
|
|
if (my $method = $attr_to_get_method{$key}) { |
110
|
|
|
|
|
|
|
return $self->{'-pngwriter'}->$method; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
### field: $self->{$key} |
113
|
|
|
|
|
|
|
return $self->SUPER::_get ($key); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub set { |
117
|
|
|
|
|
|
|
my ($self, %params) = @_; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
if (exists $params{'-pngwriter'}) { |
120
|
|
|
|
|
|
|
$self->{'-pngwriter'} = delete $params{'-pngwriter'}; |
121
|
|
|
|
|
|
|
delete $self->{'-file'}; |
122
|
|
|
|
|
|
|
delete $self->{'-zlib_compression'}; |
123
|
|
|
|
|
|
|
delete $self->{'-title'}; |
124
|
|
|
|
|
|
|
delete $self->{'-author'}; |
125
|
|
|
|
|
|
|
delete $self->{'-description'}; |
126
|
|
|
|
|
|
|
delete $self->{'-software'}; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
if (exists $params{'-width'} || exists $params{'-height'}) { |
130
|
|
|
|
|
|
|
my $width = (exists $params{'-width'} |
131
|
|
|
|
|
|
|
? delete $params{'-width'} |
132
|
|
|
|
|
|
|
: $self->{'-pngwriter'}->getwidth); |
133
|
|
|
|
|
|
|
my $height = (exists $params{'-height'} |
134
|
|
|
|
|
|
|
? delete $params{'-height'} |
135
|
|
|
|
|
|
|
: $self->{'-pngwriter'}->getheight); |
136
|
|
|
|
|
|
|
$self->{'-pngwriter'}->resize ($width, $height); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# not documented, yet ... |
140
|
|
|
|
|
|
|
if (exists $params{'-gamma'}) { |
141
|
|
|
|
|
|
|
$self->{'-pngwriter'}->setgamma (delete $params{'-gamma'}); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
%$self = (%$self, %params); |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
if (exists $params{'-file'}) { |
147
|
|
|
|
|
|
|
$self->{'-pngwriter'}->pngwriter_rename ($params{'-file'}); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
if (exists $params{'-zlib_compression'}) { |
150
|
|
|
|
|
|
|
$self->{'-pngwriter'}->setcompressionlevel ($params{'-zlib_compression'}); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# not documented yet ... |
154
|
|
|
|
|
|
|
if (exists $params{'-title'} || exists $params{'-author'} || exists $params{'-description'} || exists $params{'-software'}) { |
155
|
|
|
|
|
|
|
$self->{'-pngwriter'}->settext |
156
|
|
|
|
|
|
|
(map {defined $params{$_} ? $params{$_} : ''} '-title', '-author', '-description', '-software'); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
161
|
|
|
|
|
|
|
# load/save |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub load { |
164
|
|
|
|
|
|
|
my ($self, $filename) = @_; |
165
|
|
|
|
|
|
|
if (@_ == 1) { |
166
|
|
|
|
|
|
|
$filename = $self->get('-file'); |
167
|
|
|
|
|
|
|
} else { |
168
|
|
|
|
|
|
|
$self->set('-file', $filename); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
$self->{'-pngwriter'}->readfromfile ($filename); |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
sub save { |
173
|
|
|
|
|
|
|
my ($self, $filename) = @_; |
174
|
|
|
|
|
|
|
if (@_ == 2) { |
175
|
|
|
|
|
|
|
$self->set('-file', $filename); |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
$self->{'-pngwriter'}->write_png; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
#------------------------------------------------------------------------------- |
182
|
|
|
|
|
|
|
# drawing |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub xy { |
185
|
|
|
|
|
|
|
my ($self, $x, $y, $colour) = @_; |
186
|
|
|
|
|
|
|
### xy: $x, $y, $colour |
187
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'}; |
188
|
|
|
|
|
|
|
$x = int($x); |
189
|
|
|
|
|
|
|
$y = int($y); |
190
|
|
|
|
|
|
|
$x++; |
191
|
|
|
|
|
|
|
$y = $pw->getheight - $y; |
192
|
|
|
|
|
|
|
if (@_ == 4) { |
193
|
|
|
|
|
|
|
### plot: $x, $y, $self->colour_to_drgb($colour) |
194
|
|
|
|
|
|
|
$pw->plot ($x, $y, $self->colour_to_drgb($colour)); |
195
|
|
|
|
|
|
|
} else { |
196
|
|
|
|
|
|
|
### dread: $x, $y, $pw->dread($x,$y,1), $pw->dread($x,$y,2), $pw->dread($x,$y,3) |
197
|
|
|
|
|
|
|
return sprintf ('#%02X%02X%02X', |
198
|
|
|
|
|
|
|
map {int (255 * $pw->dread($x,$y,$_) + 0.5)} 1,2,3); |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
sub line { |
202
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour) = @_; |
203
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'}; |
204
|
|
|
|
|
|
|
my $height = $pw->getheight; |
205
|
|
|
|
|
|
|
$pw->line ($x1+1, $height-$y1, |
206
|
|
|
|
|
|
|
$x2+1, $height-$y2, |
207
|
|
|
|
|
|
|
$self->colour_to_drgb($colour)); |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
sub rectangle { |
210
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
211
|
|
|
|
|
|
|
### Image-Base-PNGwriter rectangle(): $x1, $y1, $x2, $y2, $colour, $fill |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'}; |
214
|
|
|
|
|
|
|
my $height = $pw->getheight; |
215
|
|
|
|
|
|
|
my $method = ($fill ? 'filledsquare' : 'square'); |
216
|
|
|
|
|
|
|
$pw->$method ($x1+1, $height-$y1, |
217
|
|
|
|
|
|
|
$x2+1, $height-$y2, |
218
|
|
|
|
|
|
|
$self->colour_to_drgb($colour)); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Only $pw->circle available, apparently. For radius 2 it draws something |
222
|
|
|
|
|
|
|
# like |
223
|
|
|
|
|
|
|
# |
224
|
|
|
|
|
|
|
# O |
225
|
|
|
|
|
|
|
# O O |
226
|
|
|
|
|
|
|
# O . O |
227
|
|
|
|
|
|
|
# O O |
228
|
|
|
|
|
|
|
# O |
229
|
|
|
|
|
|
|
# |
230
|
|
|
|
|
|
|
# which is x2==x1+4 and y2==y1+4. The parameters to circle() are integers, |
231
|
|
|
|
|
|
|
# so only odd number of pixels across like this can be done ($x2-$x1 an even |
232
|
|
|
|
|
|
|
# number), others go to Image::Base. |
233
|
|
|
|
|
|
|
# |
234
|
|
|
|
|
|
|
sub ellipse { |
235
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
236
|
|
|
|
|
|
|
### ellipse(): $x1, $y1, $x2, $y2, $colour, $fill |
237
|
|
|
|
|
|
|
my $xr = $x2 - $x1; |
238
|
|
|
|
|
|
|
if (! ($xr & 1) && $xr == ($y2 - $y1)) { |
239
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'}; |
240
|
|
|
|
|
|
|
$xr /= 2; |
241
|
|
|
|
|
|
|
### $xr |
242
|
|
|
|
|
|
|
### x centre: $x1+$xr |
243
|
|
|
|
|
|
|
### y centre: $pw->getheight() - ($y1+$xr) |
244
|
|
|
|
|
|
|
my $method = ($fill ? 'filledcircle' : 'circle'); |
245
|
|
|
|
|
|
|
$pw->$method ($x1+$xr+1, $pw->getheight() - ($y1+$xr), $xr, |
246
|
|
|
|
|
|
|
$self->colour_to_drgb($colour)); |
247
|
|
|
|
|
|
|
} else { |
248
|
|
|
|
|
|
|
### plain Image-Base |
249
|
|
|
|
|
|
|
shift->SUPER::ellipse(@_); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
sub diamond { |
254
|
|
|
|
|
|
|
my ($self, $x1, $y1, $x2, $y2, $colour, $fill) = @_; |
255
|
|
|
|
|
|
|
### diamond(): "$x1,$y1, $x2,$y2, $colour, fill=".($fill||0) |
256
|
|
|
|
|
|
|
my $w = $x2 - $x1; |
257
|
|
|
|
|
|
|
my $h = $y2 - $y1; |
258
|
|
|
|
|
|
|
my $pw = $self->{'-pngwriter'}; |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
if ($w && $h) { |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
### x centre: $x1+int(($w+1)/2)+1 |
263
|
|
|
|
|
|
|
### y centre: $pw->getheight() - ($y1+int($h/2)+1) |
264
|
|
|
|
|
|
|
### $w |
265
|
|
|
|
|
|
|
### $h |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
my $method = ($fill ? 'filleddiamond' : 'diamond'); |
268
|
|
|
|
|
|
|
$pw->$method ($x1+int(($w+1)/2)+1, |
269
|
|
|
|
|
|
|
$pw->getheight() - ($y1+int($h/2)), |
270
|
|
|
|
|
|
|
$w, $h, |
271
|
|
|
|
|
|
|
$self->colour_to_drgb($colour)); |
272
|
|
|
|
|
|
|
} else { |
273
|
|
|
|
|
|
|
# 1xN or Nx1 dubious in PNGwriter 0.5.3, use rectangle instead |
274
|
|
|
|
|
|
|
shift->rectangle (@_); |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#------------------------------------------------------------------------------ |
279
|
|
|
|
|
|
|
# colours |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# not documented, yet ... |
282
|
|
|
|
|
|
|
sub colour_to_drgb { |
283
|
|
|
|
|
|
|
my ($self, $colour) = @_; |
284
|
|
|
|
|
|
|
if (exists $self->{'-palette'}->{$colour}) { |
285
|
|
|
|
|
|
|
$colour = $self->{'-palette'}->{$colour}; |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
if (ref $colour) { |
288
|
|
|
|
|
|
|
return @$colour; |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# 1 to 4 digit hex, equally spaced from 00 -> 0.0 through FF -> 1.0, or |
292
|
|
|
|
|
|
|
# FFFF -> 1.0 etc. |
293
|
|
|
|
|
|
|
# Crib: [:xdigit:] matches some wide chars, but hex() as of perl 5.12.4 |
294
|
|
|
|
|
|
|
# doesn't accept them, so only 0-9A-F |
295
|
|
|
|
|
|
|
if ($colour =~ /^#(([0-9A-F]{3}){1,4})$/i) { |
296
|
|
|
|
|
|
|
my $len = length($1)/3; # of each group, so 1,2,3 or 4 |
297
|
|
|
|
|
|
|
my $divisor = hex('F' x $len); |
298
|
|
|
|
|
|
|
return (map {hex($_)/$divisor} |
299
|
|
|
|
|
|
|
substr ($colour, 1, $len), # full size groups |
300
|
|
|
|
|
|
|
substr ($colour, 1+$len, $len), |
301
|
|
|
|
|
|
|
substr ($colour, -$len)); |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
croak "Unknown colour: $colour"; |
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
1; |
308
|
|
|
|
|
|
|
__END__ |