blib/lib/Text/Amuse/Output/Image.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 100 | 103 | 97.0 |
branch | 45 | 48 | 93.7 |
condition | 20 | 25 | 80.0 |
subroutine | 15 | 15 | 100.0 |
pod | 12 | 12 | 100.0 |
total | 192 | 203 | 94.5 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package Text::Amuse::Output::Image; | ||||||
2 | 45 | 45 | 69770 | use strict; | |||
45 | 100 | ||||||
45 | 3034 | ||||||
3 | 45 | 45 | 566 | use warnings; | |||
45 | 114 | ||||||
45 | 1107 | ||||||
4 | 45 | 45 | 259 | use utf8; | |||
45 | 85 | ||||||
45 | 274 | ||||||
5 | |||||||
6 | =head1 NAME | ||||||
7 | |||||||
8 | Text::Amuse::Output::Image -- class to manage images | ||||||
9 | |||||||
10 | =head1 SYNOPSIS | ||||||
11 | |||||||
12 | The module is used internally by L |
||||||
13 | pretty much internal only (and underdocumented). | ||||||
14 | |||||||
15 | =head1 CONSTRUCTORS | ||||||
16 | |||||||
17 | =over 4 | ||||||
18 | |||||||
19 | =item new(filename => "hello.png", width => 50, wrap => 'l') | ||||||
20 | |||||||
21 | Constructor. Accepts three options: C |
||||||
22 | integer in percent, and C |
||||||
23 | C |
||||||
24 | |||||||
25 | These arguments are saved in the objects and can be accessed with: | ||||||
26 | =cut | ||||||
27 | |||||||
28 | =back | ||||||
29 | |||||||
30 | =head1 METHODS | ||||||
31 | |||||||
32 | =over 4 | ||||||
33 | |||||||
34 | =item filename | ||||||
35 | |||||||
36 | =item rotate | ||||||
37 | |||||||
38 | Allowed values are 90 180 270. Rotation happens around the image | ||||||
39 | figure and before the scaling. | ||||||
40 | |||||||
41 | =item width | ||||||
42 | |||||||
43 | =item wrap | ||||||
44 | |||||||
45 | If 'l', the float will wrap on the left, if 'r' will wrap on the | ||||||
46 | right, if 'f' it's not floating, but it's intended as fullpage (will | ||||||
47 | insert a clearpage after the image). This is handy if there is some | ||||||
48 | long series of images without text. | ||||||
49 | |||||||
50 | =item fmt | ||||||
51 | |||||||
52 | =item desc | ||||||
53 | |||||||
54 | Please note that we concatenate the caption as is. It's up to the | ||||||
55 | caller to pass an escaped string. | ||||||
56 | |||||||
57 | =cut | ||||||
58 | |||||||
59 | sub new { | ||||||
60 | 442 | 442 | 1 | 2649 | my $class = shift; | ||
61 | 442 | 1369 | my $self = { | ||||
62 | width => 1, | ||||||
63 | wrap => 0, | ||||||
64 | }; | ||||||
65 | 442 | 1980 | my %opts = @_; | ||||
66 | |||||||
67 | 442 | 50 | 1164 | if (my $f = $opts{filename}) { | |||
68 | 442 | 895 | $self->{filename} = $f; | ||||
69 | # just to be sure | ||||||
70 | 442 | 100 | 2097 | unless ($f =~ m{^[0-9A-Za-z][0-9A-Za-z/-]+\.(png|jpe?g)}s) { | |||
71 | 2 | 23 | die "Illegal filename $f!"; | ||||
72 | } | ||||||
73 | } | ||||||
74 | else { | ||||||
75 | 0 | 0 | die "Missing filename argument!"; | ||||
76 | } | ||||||
77 | |||||||
78 | 440 | 100 | 1305 | if (my $wrap = $opts{wrap}) { | |||
79 | 309 | 50 | 100 | 1893 | if ($wrap eq 'l' or $wrap eq 'r' or $wrap eq 'f') { | ||
66 | |||||||
80 | 309 | 690 | $self->{wrap} = $wrap; | ||||
81 | } | ||||||
82 | else { | ||||||
83 | 0 | 0 | die "Wrong wrapping option"; | ||||
84 | } | ||||||
85 | 309 | 100 | 100 | 1229 | if ($wrap eq 'l' or $wrap eq 'r') { | ||
86 | 70 | 100 | 234 | $opts{width} ||= 50; | |||
87 | } | ||||||
88 | } | ||||||
89 | |||||||
90 | 440 | 100 | 1012 | if (my $w = $opts{width}) { | |||
91 | 87 | 100 | 351 | if ($w =~ m/^[0-9]+$/s) { | |||
92 | 86 | 1021 | $self->{width} = sprintf('%.2f', $w / 100); | ||||
93 | } | ||||||
94 | else { | ||||||
95 | 1 | 10 | die "Wrong width $w passed!"; | ||||
96 | } | ||||||
97 | } | ||||||
98 | 439 | 100 | 1059 | if (my $r = $opts{rotate}) { | |||
99 | 37 | 119 | my %angles = (90 => 90, 180 => 180, 270 => 270); | ||||
100 | 37 | 50 | 155 | $self->{rotate} = $angles{$r} || 0; | |||
101 | } | ||||||
102 | 439 | 929 | foreach my $k (qw/desc fmt/) { | ||||
103 | 878 | 100 | 66 | 2783 | if (exists $opts{$k} and defined $opts{$k}) { | ||
104 | 432 | 1109 | $self->{$k} = $opts{$k}; | ||||
105 | } | ||||||
106 | } | ||||||
107 | |||||||
108 | 439 | 3267 | bless $self, $class; | ||||
109 | } | ||||||
110 | |||||||
111 | sub rotate { | ||||||
112 | 458 | 458 | 1 | 1134 | return shift->{rotate}; | ||
113 | } | ||||||
114 | |||||||
115 | sub width { | ||||||
116 | 556 | 556 | 1 | 1470 | return shift->{width}; | ||
117 | } | ||||||
118 | |||||||
119 | sub wrap { | ||||||
120 | 447 | 447 | 1 | 968 | return shift->{wrap}; | ||
121 | } | ||||||
122 | |||||||
123 | sub filename { | ||||||
124 | 859 | 859 | 1 | 2239 | return shift->{filename}; | ||
125 | } | ||||||
126 | |||||||
127 | sub fmt { | ||||||
128 | 629 | 629 | 1 | 1647 | return shift->{fmt}; | ||
129 | } | ||||||
130 | |||||||
131 | sub desc { | ||||||
132 | 539 | 539 | 1 | 1061 | my ($self, @args) = @_; | ||
133 | 539 | 100 | 1287 | if (@args) { | |||
134 | 100 | 261 | $self->{desc} = shift(@args); | ||||
135 | } | ||||||
136 | 539 | 1255 | return shift->{desc}; | ||||
137 | } | ||||||
138 | |||||||
139 | =back | ||||||
140 | |||||||
141 | =head2 Formatters | ||||||
142 | |||||||
143 | =over 4 | ||||||
144 | |||||||
145 | =item width_html | ||||||
146 | |||||||
147 | Width in percent | ||||||
148 | |||||||
149 | =item width_latex | ||||||
150 | |||||||
151 | Width as '0.25\textwidth' | ||||||
152 | |||||||
153 | =cut | ||||||
154 | |||||||
155 | sub width_html { | ||||||
156 | 51 | 51 | 1 | 97 | my $self = shift; | ||
157 | 51 | 106 | my $width = $self->width; | ||||
158 | 51 | 242 | my $width_in_pc = sprintf('%d', $width * 100); | ||||
159 | 51 | 197 | return $width_in_pc . '%'; | ||||
160 | } | ||||||
161 | |||||||
162 | sub width_latex { | ||||||
163 | 229 | 229 | 1 | 337 | my $self = shift; | ||
164 | 229 | 480 | my $width = $self->width; | ||||
165 | 229 | 100 | 578 | if ($width == 1) { | |||
166 | 179 | 401 | return "\\textwidth"; | ||||
167 | } | ||||||
168 | else { | ||||||
169 | 50 | 107 | return $self->width . "\\textwidth"; # a float | ||||
170 | } | ||||||
171 | } | ||||||
172 | |||||||
173 | =item as_latex | ||||||
174 | |||||||
175 | The LaTeX code for the image. Right and left floats uses the | ||||||
176 | wrapfigure packages. To full page floats a \clearpage is appended. | ||||||
177 | |||||||
178 | =item as_html | ||||||
179 | |||||||
180 | The HTML code for the image. Classes used: | ||||||
181 | |||||||
182 | img.embedimg { | ||||||
183 | margin: 1em; | ||||||
184 | } | ||||||
185 | |||||||
186 | div.image, div.float_image_f { | ||||||
187 | margin: 1em; | ||||||
188 | text-align: center; | ||||||
189 | padding: 3px; | ||||||
190 | background-color: white; | ||||||
191 | } | ||||||
192 | |||||||
193 | div.float_image_r { | ||||||
194 | float: right; | ||||||
195 | } | ||||||
196 | |||||||
197 | div.float_image_l { | ||||||
198 | float: left; | ||||||
199 | } | ||||||
200 | |||||||
201 | div.float_image_f { | ||||||
202 | clear: both; | ||||||
203 | margin-left: auto; | ||||||
204 | margin-right: auto; | ||||||
205 | } | ||||||
206 | |||||||
207 | |||||||
208 | =item output | ||||||
209 | |||||||
210 | Given that we know the format, just return the right one, using | ||||||
211 | C |
||||||
212 | |||||||
213 | =back | ||||||
214 | |||||||
215 | |||||||
216 | =cut | ||||||
217 | |||||||
218 | |||||||
219 | |||||||
220 | sub as_latex { | ||||||
221 | 221 | 221 | 1 | 358 | my $self = shift; | ||
222 | 221 | 472 | my $wrap = $self->wrap; | ||||
223 | 221 | 490 | my $width = $self->width_latex; | ||||
224 | 221 | 420 | my $desc = ""; | ||||
225 | 221 | 498 | my $realdesc = $self->desc; | ||||
226 | 221 | 100 | 66 | 762 | if (defined($realdesc) && length($realdesc)) { | ||
227 | # the \noindent here is harmless if you still want the label, | ||||||
228 | # commenting out the \renewcommand* | ||||||
229 | 52 | 189 | $desc = "\n\\caption[]{\\noindent $realdesc}"; | ||||
230 | } | ||||||
231 | 221 | 474 | my $src = $self->filename; | ||||
232 | 221 | 428 | my $open; | ||||
233 | my $close; | ||||||
234 | 221 | 100 | 100 | 1005 | if ($wrap eq 'r' or $wrap eq 'l') { | ||
100 | |||||||
235 | 36 | 118 | $open = "\\begin{wrapfigure}{$wrap}{$width}"; | ||||
236 | 36 | 84 | $close = "\\end{wrapfigure}"; | ||||
237 | } | ||||||
238 | elsif ($wrap eq 'f') { | ||||||
239 | 119 | 225 | $open = "\\begin{figure}[p]"; | ||||
240 | 119 | 206 | $close = "\\end{figure}\n\\clearpage"; | ||||
241 | } | ||||||
242 | else { | ||||||
243 | 66 | 194 | $open = "\\begin{figure}[htbp!]"; | ||||
244 | 66 | 121 | $close = "\\end{figure}"; | ||||
245 | } | ||||||
246 | 221 | 100 | 473 | my $rotation = $self->rotate ? "origin=c,angle=" . $self->rotate . ',' : ''; | |||
247 | 221 | 100 | 487 | my $heightratio = $desc ? '0.85' : ""; | |||
248 | 221 | 1215 | my $out = <<"EOF"; | ||||
249 | |||||||
250 | $open | ||||||
251 | \\centering | ||||||
252 | \\includegraphics[${rotation}keepaspectratio=true,height=$heightratio\\textheight,width=$width]{$src}$desc | ||||||
253 | $close | ||||||
254 | EOF | ||||||
255 | 221 | 1236 | return $out; | ||||
256 | } | ||||||
257 | |||||||
258 | sub as_html { | ||||||
259 | 218 | 218 | 1 | 334 | my $self = shift; | ||
260 | 218 | 466 | my $wrap = $self->wrap; | ||||
261 | 218 | 378 | my $width = ""; | ||||
262 | 218 | 307 | my $desc; | ||||
263 | 218 | 375 | my $class = "image"; | ||||
264 | 218 | 360 | my $out; | ||||
265 | 218 | 100 | 521 | if ($wrap) { | |||
266 | 154 | 335 | $class = "float_image_$wrap"; | ||||
267 | } | ||||||
268 | |||||||
269 | 218 | 392 | my $src = $self->filename; | ||||
270 | 218 | 470 | my $realdesc = $self->desc; | ||||
271 | 218 | 100 | 66 | 773 | if (defined($realdesc) && length($realdesc)) { | ||
272 | 51 | 198 | $desc = <<"EOF"; | ||||
273 | $realdesc |
||||||
274 | EOF | ||||||
275 | } | ||||||
276 | |||||||
277 | 218 | 332 | my @styles; | ||||
278 | 218 | 100 | 528 | if ($self->width != 1) { | |||
279 | 43 | 115 | push @styles, "width:" . $self->width_html . ";"; | ||||
280 | } | ||||||
281 | 218 | 100 | 465 | if (my $rotate = $self->rotate) { | |||
282 | 19 | 56 | push @styles, "transform:rotate(${rotate}deg);"; | ||||
283 | 19 | 34 | push @styles, "background: transparent;"; | ||||
284 | } | ||||||
285 | 218 | 358 | my $style_html = ""; | ||||
286 | 218 | 100 | 469 | if (@styles) { | |||
287 | 55 | 214 | $style_html = q{ style="} . join(' ', @styles) . q{"}; | ||||
288 | } | ||||||
289 | 218 | 980 | $out = qq{\n \n} . |
||||
290 | qq{ |
||||||
291 | 218 | 100 | 579 | if (defined $desc) { | |||
292 | 51 | 138 | $out .= $desc; | ||||
293 | } | ||||||
294 | 218 | 388 | $out .= "\n"; | ||||
295 | 218 | 1154 | return $out; | ||||
296 | } | ||||||
297 | |||||||
298 | sub output { | ||||||
299 | 420 | 420 | 1 | 803 | my $self = shift; | ||
300 | 420 | 100 | 804 | if ($self->fmt eq 'ltx') { | |||
50 | |||||||
301 | 211 | 488 | return $self->as_latex; | ||||
302 | } | ||||||
303 | elsif ($self->fmt eq 'html') { | ||||||
304 | 209 | 490 | return $self->as_html; | ||||
305 | } | ||||||
306 | else { | ||||||
307 | 0 | die "Bad format ". $self->fmt; | |||||
308 | } | ||||||
309 | } | ||||||
310 | |||||||
311 | 1; | ||||||
312 |