File Coverage

blib/lib/PDLA/IO/Pic.pm
Criterion Covered Total %
statement 146 209 69.8
branch 59 114 51.7
condition 14 51 27.4
subroutine 23 27 85.1
pod 4 13 30.7
total 246 414 59.4


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             PDLA::IO::Pic -- image I/O for PDLA
4              
5             =head1 DESCRIPTION
6              
7             =head2 Image I/O for PDLA based on the netpbm package.
8              
9             This package implements I/O for a number of popular image formats
10             by exploiting the xxxtopnm and pnmtoxxx converters from the netpbm package
11             (which is based on the original pbmplus by Jef Poskanzer).
12              
13             Netpbm is available at
14             ftp://wuarchive.wustl.edu/graphics/graphics/packages/NetPBM/
15             Pbmplus (on which netpbm is based) might work as well, I haven't tried it.
16             If you want to read/write JPEG images you additionally need the two
17             converters cjpeg/djpeg which come with the libjpeg distribution (the
18             "official" archive site for this software is L).
19              
20             Image I/O for all formats is established by reading and writing only
21             the PNM format directly while the netpbm standalone apps take care of
22             the necessary conversions. In accordance with netpbm parlance PNM stands
23             here for 'portable any map' meaning any of the PBM/PGM/PPM formats.
24              
25             As it appeared to be a reasonable place this package also contains the
26             routine wmpeg to write mpeg movies from PDLAs representing image
27             stacks (the image stack is first written as a sequence of PPM images into some
28             temporary directory). For this to work you need the program ffmpeg also.
29              
30             =cut
31              
32             package PDLA::IO::Pic;
33              
34              
35             @EXPORT_OK = qw( wmpeg rim wim rpic wpic rpiccan wpiccan );
36              
37             %EXPORT_TAGS = (Func => [@EXPORT_OK]);
38 13     13   599 use PDLA::Core;
  13         31  
  13         86  
39 13     13   98 use PDLA::Exporter;
  13         27  
  13         87  
40 13     13   73 use PDLA::Types;
  13         40  
  13         1744  
41 13     13   6032 use PDLA::ImageRGB;
  13         35  
  13         84  
42 13     13   6244 use PDLA::IO::Pnm;
  13         37  
  13         113  
43 13     13   112 use PDLA::Options;
  13         35  
  13         679  
44 13     13   496 use PDLA::Config;
  13         35  
  13         301  
45 13     13   72 use File::Basename;
  13         27  
  13         1329  
46 13     13   94 use SelfLoader;
  13         40  
  13         642  
47 13     13   82 use File::Spec;
  13         36  
  13         308  
48              
49 13     13   69 use strict;
  13         28  
  13         393  
50 13     13   63 use vars qw( $Dflags @ISA %converter );
  13         41  
  13         30242  
51              
52             @ISA = qw( PDLA::Exporter );
53              
54              
55             =head2 Configuration
56              
57             The executables from the netpbm package are assumed to be in your path.
58             Problems in finding the executables may show up as PNM format
59             errors when calling wpic/rpic. If you run into this kind of problem run
60             your program with perl C<-w> so that perl prints a message if it can't find
61             the filter when trying to open the pipe. [']
62              
63             =cut
64              
65              
66             # list of converters by type
67             # might get more fields in the future to provide a generic representation
68             # of common flags like COMPRESSION, LUT, etc which would hold the correct
69             # flags for the particular converter or NA if not supported
70             # conventions:
71             # NONE we need no converter (directly supported format)
72             # NA feature not available
73             # 'whatevertopnm' name of the executable
74             # The 'FLAGS' key must be used if the converter needs other flags than
75             # the default flags ($Dflags)
76             #
77             #
78             # The "referral" field, if present, contains a within-perl referral
79             # to other methods for reading/writing the PDLA as that type of file. The
80             # methods must have the same syntax as wpic/rpic (e.g. wfits/rfits).
81             #
82              
83             $PDLA::IO::Pic::debug = $PDLA::IO::Pic::debug || 0;
84             &init_converter_table();
85              
86             # setup functions
87              
88             sub init_converter_table {
89             # default flag to be used with any converter unless overridden with FLAGS
90 13     13 0 30 $Dflags = '';
91 13         27 %converter = ();
92              
93             # Pbmplus systems have cjpeg/djpeg; netpbm systems have pnmtojpeg and
94             # jpegtopnm.
95              
96 13         27 my $jpeg_conv='';
97              
98             {
99 13         27 my @path = File::Spec->path();
  13         370  
100 13 50       97 my $ext = $^O =~ /MSWin/i ? '.exe' : '';
101 13         25 local $_;
102 13         29 my $pbmplus;
103              
104 13         30 for (@path) {
105 117 50       1359 $jpeg_conv="cjpeg" if ( -x "$_/cjpeg" . $ext );
106 117 50       1203 $jpeg_conv="pnmtojpeg" if ( -x "$_/pnmtojpeg" . $ext );
107             }
108             }
109              
110 13         63 my @normal = qw/TIFF SGI RAST PCX PNG/;
111 13 50       92 push(@normal,"JPEG") if($jpeg_conv eq 'pnmtojpeg');
112              
113 13         37 for (@normal)
114 65         133 { my $conv = lc; $converter{$_} = {put => "pnmto$conv",
  65         266  
115             get => "$conv".'topnm'} }
116              
117 13         80 my @special = (['PNM','NONE','NONE'],
118             ['PS','pnmtops -dpi=100',
119             'pstopnm -stdout -xborder=0 -yborder=0 -quiet -dpi=100'],
120             ['GIF','ppmtogif','giftopnm'],
121             ['IFF','ppmtoilbm','ilbmtoppm']
122             );
123 13 50       46 push(@special,['JPEG', 'cjpeg' ,'djpeg'])
124             if($jpeg_conv eq 'cjpeg');
125              
126 13         35 for(@special) {
127 52         198 $converter{$_->[0]} = {put => $_->[1],
128             get => $_->[2]}
129             }
130              
131 13         65 $converter{'FITS'}={ 'referral' => {'put' => \&PDLA::wfits, 'get' => \&PDLA::rfits} };
132              
133             # these converters do not understand pbmplus flags:
134 13         63 $converter{'JPEG'}->{FLAGS} = '';
135 13         41 $converter{'GIF'}->{Prefilt} = 'ppmquant 256 |';
136              
137              
138 13         34 my $key;
139 13         89 for $key (keys %converter) {
140              
141             $converter{$key}->{Rok} = inpath($converter{$key}->{'get'})
142 143 100       436 if defined($converter{$key}->{'get'});
143              
144             $converter{$key}->{Wok} = inpath($converter{$key}->{'put'})
145 143 100       416 if defined($converter{$key}->{'put'});
146              
147 143 100       354 if (defined $converter{$key}->{Prefilt}) {
148 13 50       118 my $filt = $1 if $converter{$key}->{Prefilt} =~ /^\s*(\S+)\s+/;
149 13 50       76 $converter{$key}->{Wok} = inpath($filt) if $converter{$key}->{Wok};
150             }
151             }
152              
153 13         75 $PDLA::IO::Pic::biggrays = &hasbiggrays();
154 13 0 33     42 print "using big grays\n" if $PDLA::IO::Pic::debug &&
155             $PDLA::IO::Pic::biggrays;
156              
157 13         47 for (keys %converter) {
158 143 0       534 $converter{$_}->{ushortok} = $PDLA::IO::Pic::biggrays ?
    100          
    50          
159             (m/GIF/ ? 0 : 1) : (m/GIF|RAST|IFF/ ? 0 : 1);
160             }
161             }
162              
163             sub inpath {
164 234     234 0 445 my ($prog) = @_;
165 234 50       804 my $pathsep = $^O =~ /win32/i ? ';' : ':';
166 234 50       490 my $exe = $^O =~ /win32/i ? '.exe' : '';
167 234 100 66     2465 for(split $pathsep,$ENV{PATH}){return 1 if -x "$_/$prog$exe" || $prog =~ /^NONE$/}
  1898         21304  
168 208         961 return 0;
169             }
170              
171              
172             sub hasbiggrays {
173 13     13 0 41 my ($checked,$form) = (0,'');
174 13         105 require IO::File;
175 13 50       48 for (&rpiccan()) { next if /^PNM$/; $form = $_; $checked=1; last }
  13         26781  
  0         0  
  0         0  
  0         0  
176 13 50       63 unless ($checked) {
177 13 50       46 warn "PDLA::IO::Pic - couldn't find any pbm converter"
178             if $PDLA::IO::Pic::debug;
179 13         35 return 0;
180             }
181 0         0 *SAVEERR = *SAVEERR; # stupid fix to shut up -w (AKA pain-in-the-...-flag)
182 0         0 open(SAVEERR, ">&STDERR");
183 0 0       0 my $tmp = new_tmpfile IO::File or barf "couldn't open tmpfile";
184 0         0 my $pos = $tmp->getpos;
185 0         0 my $txt;
186 0         0 { local *IN;
  0         0  
187 0         0 *IN = *$tmp; # doesn't seem to work otherwise
188 0 0       0 open(STDERR,">&IN") or barf "couldn't redirect stdder";
189              
190 0         0 system("$converter{$form}->{get} -version");
191 0         0 open(STDERR, ">&PDLA::IO::Pic::SAVEERR");
192 0         0 $tmp->setpos($pos); # rewind
193 0         0 $txt = join '',;
194 0         0 close IN; undef $tmp;
  0         0  
195             }
196 0         0 return ($txt =~ /PGM_BIGGRAYS/);
197             }
198              
199             =head1 FUNCTIONS
200              
201             =head2 rpiccan, wpiccan
202              
203             =for ref
204              
205             Test which image formats can be read/written
206              
207             =for example
208              
209             $im = PDLA->rpic('PDLA.jpg') if PDLA->rpiccan('JPEG');
210             @wformats = PDLA->wpiccan();
211              
212             finds out if PDLA::IO::Pic can read/write certain image formats.
213             When called without arguments returns a list of supported
214             formats. When called with an argument returns true if format
215             is supported on your computer (requires appropriate filters in
216             your path), false otherwise.
217              
218             =cut
219              
220 13     13 1 73 sub rpiccan {return PDLA->rpiccan(@_)}
221 0     0 1 0 sub wpiccan {return PDLA->wpiccan(@_)}
222 19     19 0 390 sub PDLA::rpiccan {splice @_,1,0,'R';
223 19         149 return PDLA::IO::Pic::piccan(@_)}
224 1     1 0 15 sub PDLA::wpiccan {splice @_,1,0,'W';
225 1         4 return PDLA::IO::Pic::piccan(@_)}
226              
227              
228             =head2 rpic
229              
230             =for ref
231              
232             Read images in many formats with automatic format detection.
233              
234             =for example
235              
236             $im = rpic $file;
237             $im = PDLA->rpic 'PDLA.jpg' if PDLA->rpiccan('JPEG');
238              
239             I
240              
241             =for opt
242              
243             FORMAT => 'JPEG' # explicitly read this format
244             XTRAFLAGS => '-nolut' # additional flags for converter
245              
246             Reads image files in most of the formats supported by netpbm. You can
247             explicitly specify a supported format by additionally passing a hash
248             containing the FORMAT key as in
249              
250             $im = rpic ($file, {FORMAT => 'GIF'});
251              
252             This is especially useful if the particular format isn't identified by
253             a magic number and doesn't have the 'typical' extension or you want to
254             avoid the check of the magic number if your data comes in from a pipe.
255             The function returns a pdl of the appropriate type upon completion.
256             Option parsing uses the L module and
257             therefore supports minimal options matching.
258              
259             You can also read directly into an existing pdl that has to have the
260             right size(!). This can come in handy when you want to read a sequence
261             of images into a datacube, e.g.
262              
263             $stack = zeroes(byte,3,500,300,4);
264             rpic $stack->slice(':,:,:,(0)'),"PDLA.jpg";
265              
266             reads an rgb image (that had better be of size (500,300)) into the
267             first plane of a 3D RGB datacube (=4D pdl datacube). You can also do
268             transpose/inversion upon read that way.
269              
270             =cut
271              
272             my $rpicopts = {
273             FORMAT => undef,
274             XTRAFLAGS => undef,
275             };
276              
277 4     4 1 28 sub rpic {PDLA->rpic(@_)}
278              
279             sub PDLA::rpic {
280 10 50   10 0 180 barf 'Usage: $im = rpic($file[,hints]) or $im = PDLA->rpic($file[,hints])'
281             if $#_<0;
282 10         36 my ($class,$file,$hints,$maybe) = @_;
283 10         19 my ($type, $pdl);
284              
285 10 50       30 if (ref($file)) { # $file is really a pdl in this case
286 0         0 $pdl = $file;
287 0         0 $file = $hints;
288 0         0 $hints = $maybe;
289             } else {
290 10         65 $pdl = $class->initialize;
291             }
292              
293 10 100       41 $hints = { iparse $rpicopts, $hints } if ref $hints;
294 10 100       34 if (defined($$hints{'FORMAT'})) {
295 3         7 $type = $$hints{'FORMAT'};
296             barf "unsupported (input) image format"
297             unless (exists($converter{$type}) &&
298 3 50 33     21 $converter{$type}->{'get'} !~ /NA/);
299             }
300             else {
301 7         35 $type = chkform($file);
302 7 50       2265 barf "can't figure out file type, specify explicitly"
303             if $type =~ /UNKNOWN/; }
304              
305 10         26 my($converter) = $PDLA::IO::Pic::converter;
306 10 50       35 if (defined($converter{$type}->{referral})) {
307 0 0       0 if(ref ($converter{$type}->{referral}->{'get'}) eq 'CODE') {
308 0         0 return &{$converter{$type}->{referral}->{'get'}}(@_);
  0         0  
309             } else {
310 0         0 barf "rpic: internal error with referral (format is $type)\n";
311             }
312             }
313              
314 10         51 my $flags = $converter{$type}->{FLAGS};
315 10 50       32 $flags = "$Dflags" unless defined($flags);
316 10 50       29 $flags .= " $$hints{XTRAFLAGS}" if defined($$hints{XTRAFLAGS});
317 10         40 my $cmd = qq{$converter{$type}->{get} $flags "$file" |};
318 10 50       47 $cmd = $file if $converter{$type}->{'get'} =~ /^NONE/;
319              
320 10 100       97 print("conversion by '$cmd'\n") if $PDLA::IO::Pic::debug > 10;
321              
322 10         43 return rpnm($pdl,$cmd);
323             }
324              
325             =head2 wpic
326              
327             =for ref
328              
329             Write images in many formats with automatic format selection.
330              
331             =for usage
332              
333             Usage: wpic($pdl,$filename[,{ options... }])
334              
335             =for example
336              
337             wpic $pdl, $file;
338             $im->wpic('web.gif',{LUT => $lut});
339             for (@images) {
340             $_->wpic($name[0],{CONVERTER => 'ppmtogif'})
341             }
342              
343              
344             Write out an image file. Function will try to guess correct image
345             format from the filename extension, e.g.
346              
347             $pdl->wpic("image.gif")
348              
349             will write a gif file. The data written out will be scaled to byte if
350             input is of type float/double. Input data that is of a signed integer
351             type and contains negative numbers will be rejected (assuming the user
352             should have the desired conversion to an unsigned type already). A number
353             of options can be specified (as a hash reference) to get more direct control of
354             the image format that is being written. Valid options are (key
355             => example_value):
356              
357             =for options
358              
359             CONVERTER => 'ppmtogif', # explicitly specify pbm converter
360             FLAGS => '-interlaced -transparent 0', # flags for converter
361             IFORM => 'PGM', # explicitly specify intermediate format
362             XTRAFLAGS => '-imagename iris', # additional flags to defaultflags
363             FORMAT => 'PCX', # explicitly specify output image format
364             COLOR => 'bw', # specify color conversion
365             LUT => $lut, # use color table information
366              
367             Option parsing uses the L module and
368             therefore supports minimal options matching. A detailed explanation of
369             supported options follows.
370              
371             =over 7
372              
373             =item CONVERTER
374              
375             directly specify the converter,
376             you had better know what you are doing, e.g.
377              
378             CONVERTER => 'ppmtogif',
379              
380             =item FLAGS
381              
382             flags to use with the converter;
383             ignored if !defined($$hints{CONVERTER}), e.g. with the gif format
384              
385             FLAGS => '-interlaced -transparent 0',
386              
387             =item IFORM
388              
389             intermediate PNM/PPM/PGM/PBM format to use;
390             you can append the strings 'RAW' or 'ASCII'
391             to enforce those modes, eg IFORMAT=>'PGMRAW' or
392              
393             IFORM => 'PGM',
394              
395             =item XTRAFLAGS
396              
397             additional flags to use with an automatically chosen
398             converter, this example works when you write SGI
399             files (but will give an error otherwise)
400              
401             XTRAFLAGS => '-imagename iris',
402              
403             =item FORMAT
404              
405             explicitly select the format you want to use. Required if wpic cannot
406             figure out the desired format from the file name extension. Supported
407             types are currently TIFF,GIF,SGI,PNM,JPEG,PS,RAST(Sun Raster),IFF,PCX,
408             e.g.
409              
410             FORMAT => 'PCX',
411              
412             =item COLOR
413              
414             you want black and white (value B), other possible value is
415             B which will write a dithered black&white
416             image from the input data, data conversion will be done appropriately,
417             e.g.
418              
419             COLOR => 'bw',
420              
421             =item LUT
422              
423             This is a palette image and the value of this key should be a
424             pdl containing an RGB lookup table (3,x), e.g.
425              
426             LUT => $lut,
427              
428             =back
429              
430             Using the CONVERTER hint you can also build a pipe and perform
431             several netpbm operations to get the special result you like. Using it
432             this way the first converter/filecommand in the pipe should be
433             specified with the CONVERTER hint and subsequent converters + flags in
434             the FLAGS hint. This is because wpic tries to figure out the required
435             format to be written by wpnm based on the first converter. Be careful when
436             using the PBMBIN var as it will only be prepended to the converter. If more
437             converters are in the FLAGS part specify the full path unless they are in
438             your PATH anyway.
439              
440             Example:
441              
442             $im->wpic('test.ps',{CONVERTER => 'pgmtopbm',
443             FLAGS => "-dither8 | pnmtops" })
444              
445             Some of the options may appear silly at the moment and probably
446             are. The situation will hopefully improve as people use the code and
447             the need for different/modified options becomes clear. The general
448             idea is to make the function perl compliant: easy things should be
449             easy, complicated tasks possible.
450              
451             =cut
452              
453             my %wpicopts = map {($_ => undef)}
454             qw/IFORM CONVERTER FLAGS FORMAT
455             XTRAFLAGS COLOR LUT/;
456             my $wpicopts = \%wpicopts;
457              
458             *wpic = \&PDLA::wpic;
459              
460             sub PDLA::wpic {
461 8 50   8 0 1865 barf 'Usage: wpic($pdl,$filename[,$hints]) ' .
462             'or $pdl->wpic($filename,[,$hints])' if $#_<1;
463              
464 8         31 my ($pdl,$file,$hints) = @_;
465 8         16 my ($type, $cmd, $form,$iform,$iraw);
466              
467 8 100       63 $hints = {iparse($wpicopts, $hints)} if ref $hints;
468             # figure out the right converter
469 8         69 my ($conv, $flags, $format, $referral) = getconv($pdl,$file,$hints);
470              
471 8 50       5409 if(defined($referral)) {
472 0 0       0 if(ref ($referral->{'put'}) eq 'CODE') {
473 0         0 return &{$referral->{'put'}}(@_);
  0         0  
474             } else {
475 0         0 barf "wpic: internal error with referral (format is $format)\n";
476             }
477             }
478              
479 8 100       121 print "Using the command $conv with the flags $flags\n"
480             if $PDLA::IO::Pic::debug>10;
481              
482 8 100       33 if (defined($$hints{IFORM})) {
483 5         23 $iform = $$hints{IFORM}; }
484             else { # check if converter requires a particular intermediate format
485 3 50       24 $iform = 'PPM' if $conv =~ /^\s*(ppm)|(cjpeg)/;
486 3 50       18 $iform = 'PGM' if $conv =~ /^\s*pgm/;
487 3 50       12 $iform = 'PBM' if $conv =~ /^\s*pbm/;
488 3 50       17 $iform = 'PNM' if $conv =~ /^\s*(pnm)|(NONE)/; }
489             # get final values for $iform and $pdl (check conversions, consistency,etc)
490 8         47 ($pdl,$iform) = chkpdl($pdl,$iform,$hints,$format);
491 8 100       234 print "using intermediate format $iform\n" if $PDLA::IO::Pic::debug>10;
492              
493 8         43 $cmd = "|" . qq{$conv $flags >"$file"};
494 8 50       38 $cmd = ">" . $file if $conv =~ /^NONE/;
495 8 100       49 print "built the command $cmd to write image\n" if $PDLA::IO::Pic::debug>10;
496              
497 8 100 66     52 $iraw = 1 if (defined($$hints{IFORM}) && $$hints{IFORM} =~ /RAW/);
498 8 50 66     49 $iraw = 0 if (defined($$hints{IFORM}) && $$hints{IFORM} =~ /ASCII/);
499              
500 8     0   224 local $SIG{PIPE}= sub {}; # Prevent crashing if converter dies
501              
502 8         54 wpnm($pdl, $cmd, $iform , $iraw);
503             }
504              
505             =head2 rim
506              
507             =for usage
508              
509             Usage: $x = rim($file);
510             or rim($x,$file);
511              
512             =for ref
513              
514             Read images in most formats, with improved RGB handling.
515              
516             You specify a filename and get back a PDLA with the image data in it.
517             Any PNM handled format or FITS will work. In the second form, $x is an
518             existing PDLA that gets loaded with the image data.
519              
520             If the image is in one of the standard RGB formats, then you get back
521             data in (,,) format -- that is to say, the third dim
522             contains the color information. That allows you to do simple indexing
523             into the image without knowing whether it is color or not -- if present,
524             the RGB information is silently threaded over. (Contrast L, which
525             munges the information by putting the RGB index in the 0th dim, screwing
526             up subsequent threading operations).
527              
528             If the image is in FITS format, then you get the data back in exactly
529             the same order as in the file itself.
530              
531             Images with a ".Z" or ".gz" extension are assumed to be compressed with
532             UNIX L<"compress"|compress> or L<"gzip"|gzip>, respecetively, and are
533             automatically uncompressed before reading.
534              
535             OPTIONS
536              
537             The same as L, which is used as an engine:
538              
539             =over 3
540              
541             =item FORMAT
542              
543             If you don't specify this then formats are autodetected. If you do specify
544             it then only the specified interpreter is tried. For example,
545              
546             $x = rim("foo.gif",{FORMAT=>"JPEG"})
547              
548             forces JPEG interpretation.
549              
550             =item XTRAFLAGS
551              
552             Contains extra command line flags for the pnm interpreter. For example,
553              
554             $x = rim("foo.jpg",{XTRAFLAGS=>"-nolut"})
555              
556             prevents use of a lookup table in JPEG images.
557              
558             =back
559              
560             =cut
561              
562 13     13   150 use PDLA::IO::Pic;
  13         35  
  13         10866  
563              
564             sub rim {
565 2     2 1 22 my(@args) = @_;
566              
567 2         4 my $out;
568              
569             ## Handle dest-PDLA-first case
570 2 100 66     21 if(@args >= 2 and (UNIVERSAL::isa($args[0],'PDLA'))) {
571 1         2 my $dest = shift @args;
572 1         5 my $rpa = PDLA->null;
573 1         4 $out = rpic(@args);
574              
575 1 0 33     11 if($out->ndims == 3 && $out->dim(0) == 3 &&
      0        
      33        
576             !( defined($out->gethdr) && $out->gethdr->{SIMPLE} )
577             ) {
578 0         0 $out = $out->reorder(1,2,0);
579             }
580            
581 1         6 $dest .= $out;
582 1         7 return $out;
583             }
584              
585             # Handle no-first-PDLA case
586 1         4 $out = rpic(@args);
587              
588 1 0 33     11 if($out->ndims == 3 && $out->dim(0) == 3 &&
      0        
      33        
589             !( defined($out->gethdr) && $out->gethdr->{SIMPLE} )
590             ) {
591 0         0 return $out->reorder(1,2,0);
592             }
593              
594 1         6 $out;
595             }
596              
597              
598              
599             =head2 wim
600              
601             =for ref
602              
603             Write a pdl to an image file with selected type (or using filename extensions)
604              
605             =for usage
606              
607             wim $pdl,$file;
608             $pdl->wim("foo.gif",{LUT=>$lut});
609              
610             Write out an image file. You can specify the format explicitly as an
611             option, or the function will try to guess the correct image
612             format from the filename extension, e.g.
613              
614             $pdl->wim("image.gif");
615             $pdl->wim("image.fits");
616              
617             will write a gif and a FITS file. The data written out will be scaled
618             to byte if the input if of type float/double. Input data that is of a
619             signed integer type and contains negative numbers will be rejected.
620              
621             If you append C<.gz> or C<.Z> to the end of the file name, the final
622             file will be automatically compresed with L<"gzip"|gzip> |
623             L<"compress"|compress>, respectively.
624              
625             OPTIONS
626              
627             You can pass in a hash ref whose keys are options. The code uses the
628             PDLA::Options module so unique abbreviations are accepted. Accepted
629             keys are the same as for L, which is used as an engine:
630              
631             =over 3
632              
633             =item CONVERTER
634              
635             Names the converter program to be used by pbmplus (e.g. "ppmtogif" to
636             output a gif file)
637              
638             =item FLAGS
639              
640             Flags that should be passed to the converter (replacing any default flag list)
641             e.g. "-interlaced" to make an interlaced GIF
642              
643             =item IFORM
644              
645             Explicitly specifies the intermediate format (e.g. PGM, PPM, or PNM).
646              
647             =item XTRAFLAGS
648              
649             Flags that should be passed to the converter (in addition to any default
650             flag list).
651              
652             =item FORMAT
653              
654             Explicitly specifies the output image format (allowing pbmplus to pick an
655             output converter)
656              
657             =item COLOR
658              
659             Specifies color conversion (e.g. 'bw' converts to black-and-white; see
660             L for details).
661              
662             =item LUT
663              
664             Use color-table information
665              
666             =back
667              
668             =cut
669              
670             *wim = \&PDLA::wim;
671              
672             sub PDLA::wim {
673 0     0 0   my(@args) = @_;
674              
675 0           my($im) = $args[0];
676              
677             $args[0] = $im->reorder(2,0,1)
678             if( $im->ndims == 3
679             and $im->dim(2)==3
680             and !(
681             ( $args[1] =~ m/\.fits$/i )
682             or
683 0 0 0       ( ref $args[2] eq 'HASH' and $args[2]->{FORMAT} =~ m/fits/i )
      0        
      0        
684             )
685             );
686              
687 0           wpic(@args);
688             }
689              
690             =head2 wmpeg
691              
692             =for ref
693              
694             Write an image sequence (a (3,x,y,n) byte pdl) as an animation.
695              
696             =for usage
697              
698             $piddle->wmpeg('movie.mpg'); # $piddle is (3,x,y,nframes) byte
699              
700             Writes a stack of RGB images as a movie. While the
701             format generated is nominally MPEG, the file extension
702             is used to determine the video encoder type.
703              
704             E.g.:
705             .mpg for MPEG-1 encoding
706             .mp4 for MPEG-4 encoding
707            
708             And even:
709             .gif for GIF animation (uncompressed)
710              
711             C requires a 4-D pdl of type B as
712             input. The first dim B to be of size 3 since
713             it will be interpreted as RGB pixel data.
714             C returns 1 on success and undef on failure.
715              
716             =for example
717              
718             $anim->wmpeg("GreatAnimation.mpg")
719             or die "can't create mpeg1 output";
720              
721             $anim->wmpeg("GreatAnimation.mp4")
722             or die "can't create mpeg4 output";
723              
724             Some of the input data restrictions will have to
725             be relaxed in the future but routine serves as
726             a proof of principle at the moment. It uses the
727             program ffmpeg to encode the frames into video.
728             The arguments and parameters used for ffmpeg have
729             not been tuned. This is a first implementation
730             replacing mpeg_encode by ffmpeg. Currently, wmpeg
731             doesn't allow modification of the parameters
732             written through its calling interface. This will
733             change in the future as needed.
734              
735             In the future it might be much nicer to implement
736             a movie perl object that supplies methods for
737             manipulating the image stack (insert, cut, append
738             commands) and a final movie->make() call would
739             invoke ffmpeg on the picture stack (which will
740             only be held on disk). This should get around the
741             problem of having to hold a huge amount of data
742             in memory to be passed into wmpeg (when you are,
743             e.g. writing a large animation from PDLA3D rendered
744             fly-throughs).
745              
746             Having said that, the actual storage requirements
747             might not be so big in the future any more if
748             you could pass 'virtual' transform pdls into
749             wmpeg that will only be actually calculated when
750             accessed by the wpic routines, you know what I
751             mean...
752              
753              
754             =cut
755              
756             *wmpeg = \&PDLA::wmpeg;
757              
758             sub PDLA::wmpeg {
759 0 0   0 0   barf 'Usage: wmpeg($pdl,$filename) ' .
760             'or $pdl->wmpeg($filename)' if $#_ != 1;
761              
762 0           my ($pdl,$file) = @_;
763              
764             # return undef if no ffmpeg in path
765 0 0         if (! inpath('ffmpeg')) {
766 0           warn("wmpeg: ffmpeg not found in PATH");
767 0           return;
768             }
769              
770 0           my @Dims = $pdl->dims;
771             # too strict in general but alright for the moment
772             # especially restriction to byte will have to be relaxed
773 0 0 0       barf "input must be byte (3,x,y,z)" if (@Dims != 4) || ($Dims[0] != 3)
      0        
774             || ($pdl->get_datatype != $PDLA_B);
775 0           my $nims = $Dims[3];
776 0           my $tmp = gettmpdir();
777              
778             # get tmpdir for parameter file
779             # see PDLA-2.4.6 version for original code
780              
781             # check the pdl for correct dimensionality
782              
783             # write all the images as ppms and write the appropriate parameter file
784 0           my ($i,$fname);
785             # add blank cells to each image to fit with 16N x 16N mpeg standard
786             # $frame is full frame, insert each image in as $inset
787 0           my (@MDims) = (3,map(16*int(($_+15)/16),@Dims[1..2]));
788 0           my ($frame) = zeroes(byte,@MDims);
789 0           my ($inset) = $frame->slice(join(',',
790             map(int(($MDims[$_]-$Dims[$_])/2).':'.
791             int(($MDims[$_]+$Dims[$_])/2-1),0..2)));
792 0           my $range = sprintf "[%d-%d]",0,$nims-1;
793 0           local $SIG{PIPE} = 'IGNORE';
794 0 0         open MPEG, "| ffmpeg -f image2pipe -vcodec ppm -i - $file"
795             or barf "spawning ffmpeg failed: $?";
796 0           binmode MPEG;
797             # select ((select (MPEG), $| = 1)[0]); # may need for win32
798 0           my (@slices) = $pdl->dog;
799 0           for ($i=0; $i<$nims; $i++) {
800 0           local $PDLA::debug = 1;
801 0           print STDERR "Writing frame $i, " . $frame->slice(':,:,-1:0')->clump(2)->info . "\n";
802 0           $inset .= $slices[$i];
803 0           print MPEG "P6\n$MDims[1] $MDims[2]\n255\n";
804 0           pnmout($frame->slice(':,:,-1:0')->clump(2), 1, 0, 'PDLA::IO::Pic::MPEG');
805             }
806             # clean up
807 0           close MPEG;
808              
809             # rm tmpdir and files if needed
810 0           return 1;
811             }
812              
813              
814              
815             1; # Return OK status
816              
817             __DATA__