File Coverage

blib/lib/PDL/IO/Pic.pm
Criterion Covered Total %
statement 149 212 70.2
branch 59 114 51.7
condition 14 51 27.4
subroutine 25 29 86.2
pod 5 15 33.3
total 252 421 59.8


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             PDL::IO::Pic -- image I/O for PDL
4              
5             =head1 DESCRIPTION
6              
7             =head2 Image I/O for PDL 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 PDLs 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 PDL::IO::Pic;
33              
34              
35             @EXPORT_OK = qw( wmpeg rim wim rpic wpic rpiccan wpiccan imageformat);
36              
37             %EXPORT_TAGS = (Func => [@EXPORT_OK]);
38 48     48   902 use PDL::Core;
  48         107  
  48         349  
39 48     48   395 use PDL::Exporter;
  48         108  
  48         316  
40 48     48   304 use PDL::Types;
  48         148  
  48         6691  
41 48     48   22844 use PDL::ImageRGB;
  48         133  
  48         314  
42 48     48   25158 use PDL::IO::Pnm;
  48         145  
  48         409  
43 48     48   414 use PDL::Options;
  48         112  
  48         2646  
44 48     48   727 use PDL::Config;
  48         123  
  48         1193  
45 48     48   277 use File::Basename;
  48         88  
  48         5110  
46 48     48   428 use SelfLoader;
  48         108  
  48         2251  
47 48     48   329 use File::Spec;
  48         121  
  48         1054  
48              
49 48     48   328 use strict;
  48         136  
  48         1485  
50 48     48   302 use vars qw( $Dflags @ISA %converter );
  48         123  
  48         111114  
51              
52             @ISA = qw( PDL::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 PDL as that type of file. The
80             # methods must have the same syntax as wpic/rpic (e.g. wfits/rfits).
81             #
82              
83             $PDL::IO::Pic::debug = $PDL::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 48     48 0 98 $Dflags = '';
91 48         120 %converter = ();
92              
93             # Pbmplus systems have cjpeg/djpeg; netpbm systems have pnmtojpeg and
94             # jpegtopnm.
95              
96 48         105 my $jpeg_conv='';
97              
98             {
99 48         158 my @path = File::Spec->path();
  48         1401  
100 48 50       415 my $ext = $^O =~ /MSWin/i ? '.exe' : '';
101 48         117 local $_;
102 48         105 my $pbmplus;
103              
104 48         129 for (@path) {
105 432 50       5347 $jpeg_conv="cjpeg" if ( -x "$_/cjpeg" . $ext );
106 432 50       4408 $jpeg_conv="pnmtojpeg" if ( -x "$_/pnmtojpeg" . $ext );
107             }
108             }
109              
110 48         224 my @normal = qw/TIFF SGI RAST PCX PNG/;
111 48 50       215 push(@normal,"JPEG") if($jpeg_conv eq 'pnmtojpeg');
112              
113 48         148 for (@normal)
114 240         489 { my $conv = lc; $converter{$_} = {put => "pnmto$conv",
  240         980  
115             get => "$conv".'topnm'} }
116              
117 48         390 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 48 50       294 push(@special,['JPEG', 'cjpeg' ,'djpeg'])
124             if($jpeg_conv eq 'cjpeg');
125              
126 48         138 for(@special) {
127 192         842 $converter{$_->[0]} = {put => $_->[1],
128             get => $_->[2]}
129             }
130              
131 48         295 $converter{'FITS'}={ 'referral' => {'put' => \&PDL::wfits, 'get' => \&PDL::rfits} };
132              
133             # these converters do not understand pbmplus flags:
134 48         196 $converter{'JPEG'}->{FLAGS} = '';
135 48         131 $converter{'GIF'}->{Prefilt} = 'ppmquant 256 |';
136              
137              
138 48         156 my $key;
139 48         270 for $key (keys %converter) {
140              
141             $converter{$key}->{Rok} = inpath($converter{$key}->{'get'})
142 528 100       1720 if defined($converter{$key}->{'get'});
143              
144             $converter{$key}->{Wok} = inpath($converter{$key}->{'put'})
145 528 100       1677 if defined($converter{$key}->{'put'});
146              
147 528 100       1300 if (defined $converter{$key}->{Prefilt}) {
148 48 50       485 my $filt = $1 if $converter{$key}->{Prefilt} =~ /^\s*(\S+)\s+/;
149 48 50       265 $converter{$key}->{Wok} = inpath($filt) if $converter{$key}->{Wok};
150             }
151             }
152              
153 48         275 $PDL::IO::Pic::biggrays = &hasbiggrays();
154 48 0 33     175 print "using big grays\n" if $PDL::IO::Pic::debug &&
155             $PDL::IO::Pic::biggrays;
156              
157 48         224 for (keys %converter) {
158 528 0       2043 $converter{$_}->{ushortok} = $PDL::IO::Pic::biggrays ?
    100          
    50          
159             (m/GIF/ ? 0 : 1) : (m/GIF|RAST|IFF/ ? 0 : 1);
160             }
161             }
162              
163             sub inpath {
164 864     864 0 1603 my ($prog) = @_;
165 864 50       2962 my $pathsep = $^O =~ /win32/i ? ';' : ':';
166 864 50       1749 my $exe = $^O =~ /win32/i ? '.exe' : '';
167 864 100 66     8992 for(split $pathsep,$ENV{PATH}){return 1 if -x "$_/$prog$exe" || $prog =~ /^NONE$/}
  7008         79980  
168 768         3617 return 0;
169             }
170              
171              
172             sub hasbiggrays {
173 48     48 0 161 my ($checked,$form) = (0,'');
174 48         386 require IO::File;
175 48 50       175 for (&rpiccan()) { next if /^PNM$/; $form = $_; $checked=1; last }
  48         99749  
  0         0  
  0         0  
  0         0  
176 48 50       221 unless ($checked) {
177 48 50       185 warn "PDL::IO::Pic - couldn't find any pbm converter"
178             if $PDL::IO::Pic::debug;
179 48         134 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, ">&PDL::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 = PDL->rpic('PDL.jpg') if PDL->rpiccan('JPEG');
210             @wformats = PDL->wpiccan();
211              
212             finds out if PDL::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 48     48 1 376 sub rpiccan {return PDL->rpiccan(@_)}
221 0     0 1 0 sub wpiccan {return PDL->wpiccan(@_)}
222 54     54 0 544 sub PDL::rpiccan {splice @_,1,0,'R';
223 54         559 return PDL::IO::Pic::piccan(@_)}
224 1     1 0 17 sub PDL::wpiccan {splice @_,1,0,'W';
225 1         4 return PDL::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 = PDL->rpic 'PDL.jpg' if PDL->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)'),"PDL.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 33 sub rpic {PDL->rpic(@_)}
278              
279             sub PDL::rpic {
280 10 50   10 0 2917 barf 'Usage: $im = rpic($file[,hints]) or $im = PDL->rpic($file[,hints])'
281             if $#_<0;
282 10         34 my ($class,$file,$hints,$maybe) = @_;
283 10         21 my ($type, $pdl);
284              
285 10 50       34 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         78 $pdl = $class->initialize;
291             }
292              
293 10 100       51 $hints = { iparse $rpicopts, $hints } if ref $hints;
294 10 100       38 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     26 $converter{$type}->{'get'} !~ /NA/);
299             }
300             else {
301 7         39 $type = chkform($file);
302 7 50       1785 barf "can't figure out file type, specify explicitly"
303             if $type =~ /UNKNOWN/; }
304              
305 10         33 my($converter) = $PDL::IO::Pic::converter;
306 10 50       39 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         26 my $flags = $converter{$type}->{FLAGS};
315 10 50       38 $flags = "$Dflags" unless defined($flags);
316 10 50       30 $flags .= " $$hints{XTRAFLAGS}" if defined($$hints{XTRAFLAGS});
317 10         44 my $cmd = qq{$converter{$type}->{get} $flags "$file" |};
318 10 50       52 $cmd = $file if $converter{$type}->{'get'} =~ /^NONE/;
319              
320 10 100       110 print("conversion by '$cmd'\n") if $PDL::IO::Pic::debug > 10;
321              
322 10         53 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 = \&PDL::wpic;
459              
460             sub PDL::wpic {
461 8 50   8 0 2451 barf 'Usage: wpic($pdl,$filename[,$hints]) ' .
462             'or $pdl->wpic($filename,[,$hints])' if $#_<1;
463              
464 8         32 my ($pdl,$file,$hints) = @_;
465 8         18 my ($type, $cmd, $form,$iform,$iraw);
466              
467 8 100       84 $hints = {iparse($wpicopts, $hints)} if ref $hints;
468             # figure out the right converter
469 8         80 my ($conv, $flags, $format, $referral) = getconv($pdl,$file,$hints);
470              
471 8 50       6063 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       143 print "Using the command $conv with the flags $flags\n"
480             if $PDL::IO::Pic::debug>10;
481              
482 8 100       34 if (defined($$hints{IFORM})) {
483 5         10 $iform = $$hints{IFORM}; }
484             else { # check if converter requires a particular intermediate format
485 3 50       33 $iform = 'PPM' if $conv =~ /^\s*(ppm)|(cjpeg)/;
486 3 50       15 $iform = 'PGM' if $conv =~ /^\s*pgm/;
487 3 50       10 $iform = 'PBM' if $conv =~ /^\s*pbm/;
488 3 50       15 $iform = 'PNM' if $conv =~ /^\s*(pnm)|(NONE)/; }
489             # get final values for $iform and $pdl (check conversions, consistency,etc)
490 8         50 ($pdl,$iform) = chkpdl($pdl,$iform,$hints,$format);
491 8 100       248 print "using intermediate format $iform\n" if $PDL::IO::Pic::debug>10;
492              
493 8         45 $cmd = "|" . qq{$conv $flags >"$file"};
494 8 50       41 $cmd = ">" . $file if $conv =~ /^NONE/;
495 8 100       44 print "built the command $cmd to write image\n" if $PDL::IO::Pic::debug>10;
496              
497 8 100 66     68 $iraw = 1 if (defined($$hints{IFORM}) && $$hints{IFORM} =~ /RAW/);
498 8 50 66     44 $iraw = 0 if (defined($$hints{IFORM}) && $$hints{IFORM} =~ /ASCII/);
499              
500 8     0   270 local $SIG{PIPE}= sub {}; # Prevent crashing if converter dies
501              
502 8         58 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 PDL with the image data in it.
517             Any PNM handled format or FITS will work. In the second form, $x is an
518             existing PDL 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 48     48   627 use PDL::IO::Pic;
  48         122  
  48         43080  
563              
564             sub rim {
565 2     2 1 28 my(@args) = @_;
566              
567 2         6 my $out;
568              
569             ## Handle dest-PDL-first case
570 2 100 66     25 if(@args >= 2 and (UNIVERSAL::isa($args[0],'PDL'))) {
571 1         4 my $dest = shift @args;
572 1         8 my $rpa = PDL->null;
573 1         5 $out = rpic(@args);
574              
575 1 0 33     13 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         8 $dest .= $out;
582 1         9 return $out;
583             }
584              
585             # Handle no-first-PDL case
586 1         5 $out = rpic(@args);
587              
588 1 0 33     13 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         5 $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             PDL::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             pbmplus for details).
661              
662             =item LUT
663              
664             Use color-table information
665              
666             =back
667              
668             =cut
669              
670             *wim = \&PDL::wim;
671              
672             sub PDL::wim {
673 0     0 0 0 my(@args) = @_;
674              
675 0         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     0 ( ref $args[2] eq 'HASH' and $args[2]->{FORMAT} =~ m/fits/i )
      0        
      0        
684             )
685             );
686              
687 0         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 PDL3D 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 = \&PDL::wmpeg;
757              
758             sub PDL::wmpeg {
759 0 0   0 0 0 barf 'Usage: wmpeg($pdl,$filename) ' .
760             'or $pdl->wmpeg($filename)' if $#_ != 1;
761              
762 0         0 my ($pdl,$file) = @_;
763              
764             # return undef if no ffmpeg in path
765 0 0       0 if (! inpath('ffmpeg')) {
766 0         0 warn("wmpeg: ffmpeg not found in PATH");
767 0         0 return;
768             }
769              
770 0         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     0 barf "input must be byte (3,x,y,z)" if (@Dims != 4) || ($Dims[0] != 3)
      0        
774             || ($pdl->get_datatype != $PDL_B);
775 0         0 my $nims = $Dims[3];
776 0         0 my $tmp = gettmpdir();
777              
778             # get tmpdir for parameter file
779             # see PDL-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         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         0 my (@MDims) = (3,map(16*int(($_+15)/16),@Dims[1..2]));
788 0         0 my ($frame) = zeroes(byte,@MDims);
789 0         0 my ($inset) = $frame->slice(join(',',
790             map(int(($MDims[$_]-$Dims[$_])/2).':'.
791             int(($MDims[$_]+$Dims[$_])/2-1),0..2)));
792 0         0 my $range = sprintf "[%d-%d]",0,$nims-1;
793 0         0 local $SIG{PIPE} = 'IGNORE';
794 0 0       0 open MPEG, "| ffmpeg -f image2pipe -vcodec ppm -i - $file"
795             or barf "spawning ffmpeg failed: $?";
796 0         0 binmode MPEG;
797             # select ((select (MPEG), $| = 1)[0]); # may need for win32
798 0         0 my (@slices) = $pdl->dog;
799 0         0 for ($i=0; $i<$nims; $i++) {
800 0         0 local $PDL::debug = 1;
801 0         0 print STDERR "Writing frame $i, " . $frame->slice(':,:,-1:0')->clump(2)->info . "\n";
802 0         0 $inset .= $slices[$i];
803 0         0 print MPEG "P6\n$MDims[1] $MDims[2]\n255\n";
804 0         0 pnmout($frame->slice(':,:,-1:0')->clump(2), 1, 0, 'PDL::IO::Pic::MPEG');
805             }
806             # clean up
807 0         0 close MPEG;
808              
809             # rm tmpdir and files if needed
810 0         0 return 1;
811             }
812              
813             =head2 imageformat
814              
815             =for ref
816              
817             Figure out the format of an image file from its magic numbers, or else, from its extension.
818              
819             Currently recognized image formats are: PNM, GIF, TIFF, JPEG, SGI,
820             RAST, IFF, PCX, PS, FITS, PNG. If the format can not be determined,
821             the string 'UNKNOWN' is returned.
822              
823             =for example
824              
825             $format=imageformat($path); # find out image format of certain file
826             print "Unknown image format" if $format eq 'UNKNOWN';
827             $canread=rpiccan($format); # check if this format is readable in this system
828             if($canread){
829             $pdl=rpic($path) ; # attempt to read image ONLY if we can
830             } else {
831             print "Image can't be read\n"; # skip unreadable file
832             }
833              
834             =cut
835              
836 2     2 1 68 sub imageformat {PDL->imageformat(@_)}
837              
838             sub PDL::imageformat {
839 2     2 0 9 my($class, $file)=@_;
840 2         19 return chkform($file);
841             }
842              
843             1; # Return OK status
844              
845             __DATA__