| 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 |