File Coverage

blib/lib/Image/MetaData/JPEG.pm
Criterion Covered Total %
statement 172 172 100.0
branch 93 106 87.7
condition 31 37 83.7
subroutine 26 26 100.0
pod 7 17 41.1
total 329 358 91.9


line stmt bran cond sub pod time code
1             ###########################################################
2             # A Perl package for showing/modifying JPEG (meta)data. #
3             # Copyright (C) 2004,2005,2006 Stefano Bettelli #
4             # See the COPYING and LICENSE files for license terms. #
5             ###########################################################
6             #use 5.008;
7             package Image::MetaData::JPEG;
8 14     14   124961 use Image::MetaData::JPEG::data::Tables qw(:JPEGgrammar);
  14         32  
  14         2698  
9 14     14   5483 use Image::MetaData::JPEG::Backtrace;
  14         21  
  14         371  
10 14     14   5974 use Image::MetaData::JPEG::Segment;
  14         36  
  14         422  
11 14     14   65 no integer;
  14         13  
  14         44  
12 14     14   214 use strict;
  14         18  
  14         276  
13 14     14   44 use warnings;
  14         16  
  14         25698  
14              
15             our $VERSION = '0.159';
16              
17             ###########################################################
18             # These simple methods should be used instead of standard #
19             # "warn" and "die" in this package; they print a much #
20             # more elaborated error message (including a stack trace).#
21             # Warnings can be turned off altogether simply by setting #
22             # Image::MetaData::JPEG::show_warnings to false. #
23             ###########################################################
24 5     5 0 7 sub warn { my ($this, $message) = @_;
25 5 100       20 warn Image::MetaData::JPEG::Backtrace::backtrace
26             ($message, "Warning" . $this->info(), $this)
27             if $Image::MetaData::JPEG::show_warnings; }
28 17     17 0 22 sub die { my ($this, $message) = @_;
29 17         41 die Image::MetaData::JPEG::Backtrace::backtrace
30             ($message, "Fatal error" . $this->info(), $this); }
31 21     21 0 23 sub info { my ($this) = @_;
32 21   100     50 my $filename = $this->{filename} || '';
33 21         105 return " [file $filename]"; }
34              
35             ###########################################################
36             # Constructor for a JPEG file structure object, accepting #
37             # a "JPEG stream". It parses the file stream and stores #
38             # its sections internally. An optional parameter can ex- #
39             # clude parsing and even storing for some segments. The #
40             # stream can be specified in two ways: #
41             # - [a scalar] interpreted as a file name to be opened; #
42             # - [a scalar reference] interpreted as a pointer to an #
43             # in-memory buffer containing a JPEG stream; #
44             # ------------------------------------------------------- #
45             # There is now a second argument, $regex. This string is #
46             # matched against segment names, and only those segments #
47             # with a positive match are parsed. This allows for some #
48             # speed-up if you just need partial information. For #
49             # instance, if you just want to manipulate the comments, #
50             # you could use $regex equal to 'COM'. If $regex is unde- #
51             # fined, all segments are matched. #
52             # ------------------------------------------------------- #
53             # There is now a third optional argument, $options. If it #
54             # matches the string 'FASTREADONLY', only those segments #
55             # matching $regex are actually stored; also, everything #
56             # which is found after a Start Of Scan is completely #
57             # neglected. This allows for very large speed-ups, but, #
58             # obviously, you cannot rebuild the file afterwards, so #
59             # this is only for getting information fast (e.g., when #
60             # doing a directory scan). #
61             # ------------------------------------------------------- #
62             # If an unrecoverable error occurs during the execution #
63             # of the constructor, the undefined value is returned #
64             # instead of the object reference, and a meaningful error #
65             # message is set up (read it with Error()). #
66             ###########################################################
67             sub new {
68 71     71 1 117493 my ($pkg, $file_input, $regex, $options) = @_;
69 71         477 my $this = bless {
70             filename => undef, # private
71             handle => undef, # private
72             read_only => undef, # private
73             segments => [],
74             }, $pkg;
75             # remember to unset the ctor error message
76 71         237 $pkg->SetError(undef);
77             # set the read-only flag if $options matches FASTREADONLY
78 71 100       215 $this->{read_only} = $options =~ m/FASTREADONLY/ if $options;
79             # execute the following subroutines in an eval block so that
80             # errors can be treated without shutting down the caller.
81 71         120 my $status = eval { $this->open_input($file_input);
  71         235  
82 69         309 $this->parse_segments($regex) ; };
83             # close the file handle, if open
84 71         372 $this->close_input();
85             # If an error was found (and it triggered a die call)
86             # we must set the appropriate error variable here
87 71 50       621 $pkg->SetError($@) unless $status;
88             # return the object reference (undef if an error occurred)
89 71 100       219 return $this->Error() ? undef : $this;
90             }
91              
92             ###########################################################
93             # This block declares a private variable containing a #
94             # meaningful error message for problems during the class #
95             # constructor. The two following methods allow reading #
96             # and setting the value of this variable. #
97             ###########################################################
98             { my $ctor_error_message = undef;
99 75   100 75 1 72789 sub Error { return $ctor_error_message || undef; }
100 142     142 0 299 sub SetError { $ctor_error_message = $_[1]; }
101             }
102              
103             ###########################################################
104             # This method writes the data area of each segment in the #
105             # current object to a disk file or a variable in memory. #
106             # A disk file is written if $filename is a scalar with a #
107             # valid file name; memory is instead used if $filename is #
108             # a scalar reference. If $filename is undef, it defaults #
109             # to the file originally used to create the current JPEG #
110             # structure object. This method returns "true" (1) if it #
111             # works, "false" (undef) otherwise. This call fails if #
112             # the "read_only" member is set. #
113             # ------------------------------------------------------- #
114             # Remember that if you make changes to any segment, you #
115             # should call update() for that particular segment before #
116             # calling this method, otherwise the changes remain confi-#
117             # ned to the internal structures of the segment (update() #
118             # dumps them into the data area). Note that "high level" #
119             # methods, like those in the JPEG_.pl files,#
120             # are supposed to call update() on their own. #
121             ###########################################################
122             sub save {
123 26     26 1 7112 my ($this, $filename) = @_;
124             # fail immediately if "read_only" is set
125 26 100       129 return undef if $this->{read_only};
126             # if $filename is undefined, it defaults to the original name
127 25 50       73 $filename = $this->{filename} unless defined $filename;
128             # Open an IO handler for output on a file named $filename
129             # or on an in-memory variable pointed to by $filename.
130             # Use an indirect handler, which is closed authomatically
131             # when it goes out of scope (so, no need to call close()).
132             # If open fails, it returns false and sets the special
133             # variable $! to reflect the system error.
134 9 50   9   83 open(my $out, '>', $filename) || return undef;
  9         13  
  9         59  
  25         1782  
135             # Legacy systems might need an explicit binary open.
136 25         9148 binmode($out);
137             # For each segment in the segment list, write the content of
138             # the data area (including the preamble when needed) to the
139             # IO handler. Save the results of each output for later testing.
140 25         44 my @results = map { $_->output_segment_data($out) } @{$this->{segments}};
  276         576  
  25         133  
141             # return undef if any print failed, true otherwise
142 25 50       66 return (scalar grep { ! $_ } @results) ? undef : 1;
  276         1043  
143             }
144              
145             ###########################################################
146             # This method takes care to open a file handle pointing #
147             # to the JPEG object specified by $file_input. If the #
148             # "file name" is a scalar reference instead, it is saved #
149             # in the "handle" member (and it must be treated accor- #
150             # dingly in the following). Nothing is actually read now; #
151             # if opening fails, the routine dies with a message. #
152             ###########################################################
153             sub open_input {
154 71     71 0 119 my ($this, $file_input) = @_;
155             # protect against undefined values
156 71 100       239 $this->die('Undefined input') unless defined $file_input;
157             # scalar references: save the reference in $this->{handle}
158             # and save a self-explicatory string as file name
159 70 100       234 if (ref $file_input eq 'SCALAR') {
160 26         57 $this->{handle} = $file_input;
161 26         61 $this->{filename} = '[in-memory JPEG stream]'; }
162             # real file: we need to open the file and complain if this is
163             # not possible (legacy systems might need an explicity binary
164             # open); then, the file name of the original file is saved.
165             else {
166 44 100       2324 open($this->{handle}, '<', $file_input) ||
167             $this->die("Open error on $file_input: $!");
168 43         153 binmode($this->{handle});
169 43         187 $this->{filename} = $file_input; }
170             }
171              
172             ###########################################################
173             # This method is the counterpart of "open". Actually, it #
174             # does something only for real files (because we do not #
175             # want to close in-memory scalars ....). #
176             ###########################################################
177             sub close_input {
178 71     71 0 121 my ($this) = @_;
179             # $this->{handle} should really be a reference to something
180 71 100       247 return unless ref $this->{handle};
181             # a ref to a scalar: we do not want to close in-memory scalars
182 70 100       252 return if ref $this->{handle} eq 'SCALAR';
183             # the default action corresponds to closing the filehandle
184 44         2507 close $this->{handle};
185             }
186              
187             ###########################################################
188             # This method returns a portion of the input file (speci- #
189             # fied by $offset and $length). It is necessary to mask #
190             # how data reading is actually implemented. As usual, it #
191             # dies on errors (but this is trapped in the constructor).#
192             # This method returns a scalar reference; if $offset is #
193             # just "LENGTH", the input length is returned instead. #
194             # A length <= 0 is ignored (ref to empty string). #
195             ###########################################################
196             sub get_data {
197 4229     4229 0 3763 my ($this, $offset, $length) = @_;
198             # a shorter name for the file handle
199 4229         3814 my $handle = $this->{handle};
200             # understand if this is a file or a scalar reference
201 4229         4205 my $is_file = ref $handle eq 'GLOB';
202             # if the first argument is just the string 'LENGTH',
203             # return the input length instead
204 4229 100       11345 return ($is_file ? -s $handle : length $$handle) if $offset eq 'LENGTH';
    100          
205             # this is the buffer to be returned at the end
206 3401         3046 my $data = '';
207             # if length is <= zero return a reference to an empty string
208 3401 100       5242 return \ $data if $length <= 0;
209             # if we are dealing with a real file, we need to seek to the
210             # requested position, then read the appropriate amount of data
211             # (and throw an error if reading failed).
212 3281 100       3425 if ($is_file) {
213 2184 50       5420 seek($handle, $offset, 0) ||
214             $this->die("Error while seeking in $this->{filename}");
215 2184         10090 my $read = read $handle, $data, $length;
216 2184 50 33     7449 $this->die("Read error in $this->{filename}")
217             if ! defined $read || $read < $length; }
218             # otherwise, we are dealing with a scalar reference, and
219             # everything is much simpler (this can't fail, right?)
220 1097         1978 else { $data = substr $$handle, $offset, $length; }
221             # return a reference to read data
222 3281         8200 return \ $data;
223             }
224              
225             ###########################################################
226             # This method searches for segments in the input JPEG. #
227             # When a segment is found, the corresponding data area is #
228             # read and used to create a segment object (the ctor of #
229             # this object takes care to decode the relevant data). #
230             # The object is then inserted into the "segments" hash, #
231             # with a code-related key. Raw (compressed) image data #
232             # are stored in "fake" segments, just for simplicity. #
233             # ------------------------------------------------------- #
234             # There is now an argument, set equal to the second argu- #
235             # ment of the constructor. If it is defined, only match- #
236             # ing segments are parsed. Also, if read_only is set, #
237             # only "interesting" segments are saved and everything #
238             # after the Start Of Scan is neglected. #
239             #=========================================================#
240             # Structure of a generic segment: #
241             # 2 bytes segment marker (the first byte is always 0xff) #
242             # 2 bytes segment_length (it doesn't include the marker) #
243             # .... data (segment_length - 2 bytes) #
244             #=========================================================#
245             # The segment length (2 bytes) has a "Motorola" (big end- #
246             # ian) endianness (byte alignement), that is it starts #
247             # with the most significant digit. Note that the segment #
248             # length marker counts its own length (i.e., after it #
249             # there are only segment_length-2 bytes). #
250             #=========================================================#
251             # Some segments do not have data after them (not even the #
252             # length field, they are pure markers): SOI, EOI and the #
253             # RST? restart segments. Scans (started by a SOS segment) #
254             # are followed by compressed data, with possibly inter- #
255             # leaved RST segments: raw data must be searched with a #
256             # dedicated routine because they are not envelopped. #
257             #=========================================================#
258             # Ref: "Digital compression and coding of continuous-tone #
259             # still images: requirements and guidelines", #
260             # CCITT, 09/1992, sec. B.1.1.4, pag. 33. #
261             ###########################################################
262             sub parse_segments {
263 69     69 0 122 my ($this, $regex) = @_;
264             # prepare another hash to reverse the JPEG markers lookup
265 69         12324 my %JPEG_MARKER_BY_CODE = reverse %JPEG_MARKER;
266             # an offset in the input object, and a variable with its size
267 69         613 my $offset = 0;
268 69         230 my $isize = $this->get_data('LENGTH');
269             # don't claim empty files are valid JPEG pictures
270 69 100       184 $this->die('Empty file') unless $isize;
271             # loop on input data and find all of its segment
272 68         237 while ($offset < $isize) {
273             # search for the next JPEG marker, giving the segment type
274 696         1429 (my $marker, $offset) = $this->get_next_marker($offset);
275             # Die on unknown markers
276 693 50       1560 $this->die(sprintf 'Unknown marker found: 0x%02x (offset $offset)',
277             $marker) unless exists $JPEG_MARKER_BY_CODE{$marker};
278             # save the current offset (beginning of data)
279 693         682 my $start = $offset;
280             # calculate the name of the marker
281 693         841 my $name = $JPEG_MARKER_BY_CODE{$marker};
282             # determine the parse flag
283 693 100 100     2465 my $flag = ($regex && $name !~ /$regex/) ? 'NOPARSE' : undef;
284             # SOI, EOI and ReSTart are dataless segments
285 693 100       592 my $length = 0; goto DECODE_LENGTH_END if $name =~ /^RST|EOI|SOI/;
  693         2798  
286 568 50       1051 DECODE_LENGTH_START:
287             # we need at least two bytes here
288             $this->die('Segment size not found') unless $isize > $offset + 2;
289             # decode the length of this application block (2 bytes).
290             # This is always in big endian ("Motorola") style, that
291             # is the first byte is the most significant one.
292 568         507 $length = unpack 'n', ${$this->get_data($offset, 2)};
  568         818  
293             # the segment length includes the two aforementioned
294             # bytes, so the length must be at least two
295 568 50       1113 $this->die('JPEG segment too small') if $length < 2;
296 693 100       1228 DECODE_LENGTH_END:
297             # we need at least $length bytes here
298             $this->die('Segment data not found') unless $isize >= $offset+$length;
299             # pass the data to a segment object and store it, unless
300             # the "read_only" member is set and $flag is "NOPARSE".
301             # (don't pass $flag to dataless segments, it is just silly).
302 692 100 100     1685 push @{$this->{segments}}, new Image::MetaData::JPEG::Segment
  633 100       1598  
303             ($name, $this->get_data($start + 2, $length - 2),
304             $length ? $flag : undef) unless $this->{read_only} && $flag;
305             # update offset
306 692         920 $offset += $length;
307             # When you find a SOS marker or a RST marker there is a special
308             # treatement; if "read_only" is set, we neglect the rest of the
309             # input. Otherwise, we need a special routine
310 692 100       2283 if ($name =~ /SOS|^RST/) {
311 69 100       661 $offset = $isize, next if $this->{read_only};
312 63         189 $offset = $this->parse_ecs($offset); }
313             DECODE_PAST_EOI_GARBAGE:
314             # Try to intercept underground data stored after the EOI segment;
315             # I have found images which store multiple reduced versions of
316             # itself after the EOI segment, as well as undocumented binary
317             # and ascii data. Save them in a pseudo-segment, so that they
318             # can be restored (take "read_only" into account).
319 686 100 100     4135 if ($name eq 'EOI' && $offset < $isize) {
320 38         69 my $len = $isize - $offset;
321 38 50       110 push @{$this->{segments}}, new Image::MetaData::JPEG::Segment
  38         112  
322             ('Post-EOI', $this->get_data($offset, $len), 'NOPARSE')
323             unless $this->{read_only};
324 38         3055 $offset += $len;
325             }
326             }
327             }
328              
329             ###########################################################
330             # This method searches for the next JPEG marker in the #
331             # stream being parsed. A marker is always assigned a two #
332             # byte code: an 0xff byte followed by a byte which is not #
333             # 0x00 nor 0xff. Any marker may optionally be preceeded #
334             # by any number of fill bytes (padding of the previous #
335             # segment, I suppose), set to 0xff. Most markers start #
336             # marker segments containing a related group of parame- #
337             # ters; some markers stand alone. The return value is a #
338             # list containing the numeric value of the second marker #
339             # byte and an offset pointing just after it. #
340             # ------------------------------------------------------- #
341             # An old version of "Arles Image Web Page Creator" had a #
342             # bug which caused the application to generate JPEG's #
343             # with illegal comment segments, reportedly due to a bug #
344             # in the Intel JPEG library the developers used at that #
345             # time (these segments had to 0x00 bytes appended). It is #
346             # true that a JPEG file with garbage between segments is #
347             # to be considered invalid, but some libraries like IJG's #
348             # try to forgive, so we try to forgive too, if the amount #
349             # of garbage is not too large ... #
350             #=========================================================#
351             # Ref: "Digital compression and coding of continuous-tone #
352             # still images: requirements and guidelines", #
353             # CCITT, 09/1992, sec. B.1.1.2, pag. 31. #
354             #=========================================================#
355             sub get_next_marker {
356 696     696 0 748 my ($this, $offset) = @_;
357 696         981 my $punctuation = chr $JPEG_PUNCTUATION; my $garbage = 0;
  696         646  
358             # this is the upper limit to $offset
359 696         1139 my $length = $this->get_data('LENGTH');
360             # $offset should point at the beginning of a new segment,
361             # so the next byte should be 0xff. However, sometimes garbage
362             # slips in ... Forgive this bug if garbage is not too much
363             $offset < $length && ${$this->get_data($offset, 1)} eq $punctuation
364 696 100 100     1934 ? last : (++$garbage, ++$offset) for (0..10);
365 696 100       1573 $this->die('Next marker not found') unless $length - $offset > 1;
366             # it is assumed that we are now at the beginning of
367             # a new segment, so the next byte must be 0xff.
368 694         588 my $marker_byte = ${$this->get_data($offset++, 1)};
  694         1190  
369 694 100       1284 $this->die(sprintf 'Unknown punctuation (0x%02x) at offset 0x%x',
370             ord($marker_byte), $offset) if $marker_byte ne $punctuation;
371             # report about garbage, unless we died
372 693 100       1065 $this->warn("Skipping $garbage garbage bytes") if $garbage;
373             # next byte can be either the marker type or a padding
374             # byte equal to 0xff (skip it if it's a padding byte)
375 693         1184 $marker_byte = ${$this->get_data($offset++, 1)}
  693         1061  
376             while $marker_byte eq $punctuation;
377             # return the marker we have found (no check on its validity),
378             # as well as the offset to the next byte in the JPEG stream
379 693         1163 return (ord($marker_byte), $offset);
380             }
381              
382             ###########################################################
383             # This method reads in a compressed (entropy coded) data #
384             # segment (ECS) and saves it as a "pseudo" segment. The #
385             # argument is the current offset in the in-memory JPEG #
386             # stream, the result is the updated offset. These pseudo #
387             # segments can be found after a Start-Of-Scan segment, #
388             # and, if restart is enabled, they can be interleaved #
389             # with restart segments (RST). Indeed, an ECS is not a #
390             # real segment, because it does not start with a marker #
391             # and its length is not known a priori. However, it is #
392             # easy to detect its end since a regular marker cannot #
393             # appear inside it. In practice, data in an ECS are coded #
394             # in such a way that a 0xff byte can only be followed by #
395             # 0x00 (invalid marker) or 0xff (padding). #
396             #=========================================================#
397             # WARNING: when restart is enabled, usually the file con- #
398             # tains a lot of ECS and RST. In order not to be too slow #
399             # we keep the restart marker embedded in row data here. #
400             #=========================================================#
401             # Ref: "Digital compression and coding of continuous-tone #
402             # still images: requirements and guidelines", #
403             # CCITT, 09/1992, sec. B.1.1.5, pag. 33. #
404             ###########################################################
405             sub parse_ecs {
406 63     63 0 95 my ($this, $offset) = @_;
407             # A title for a raw data block ('ECS' must be there)
408 63         94 my $ecs_name = 'ECS (Raw data)';
409             # transform the JPEG punctuation value into a string
410 63         112 my $punctuation = chr $JPEG_PUNCTUATION;
411             # create a string containing the character which can follow a
412             # punctuations mark without causing the ECS to be considered
413             # terminated. This string must contain at least the null byte and
414             # the punctuation mark itself. But, for efficiency reasons, we are
415             # going to include also the restart markers here.
416 63         105 my $skipstring = $punctuation . chr 0x00;
417 63         369 $skipstring .= chr $_ for ($JPEG_MARKER{RST0} .. $JPEG_MARKER{RST7});
418             # read in everything till the end of the input
419 63         153 my $length = $this->get_data('LENGTH');
420 63         164 my $buffer = $this->get_data($offset, $length - $offset);
421             # find the next 0xff byte not followed by a character of $skipstring
422             # from $offset on. It is better to use pos() instead of taking a
423             # substring of $$buffer, because this copy takes a lot of space. In
424             # order to honour the position set by pos(), it is necessary to use
425             # "g" in scalar context. My benchmarks say this is almost as fast as C.
426 63         297 pos($$buffer) = 0; scalar $$buffer =~ /$punctuation[^$skipstring]/g;
  63         1762  
427             # trim the $buffer at the byte before the punctuation mark; the
428             # position of the last match can be accessed through pos(); if no
429             # match is found, complain but do not fail (similar behaviour to that
430             # of the 'xv' program); the file is however corrupt and unusable.
431 63 50       1011 pos($$buffer) ? substr($$buffer, pos($$buffer) - 2) = ''
432             : $this->warn('Premature end of JPEG stream');
433             # push a pseudo segment among the regular ones (do not parse it)
434 63         94 push @{$this->{segments}}, new Image::MetaData::JPEG::Segment
  63         290  
435             ($ecs_name, $buffer, 'NOPARSE');
436             # return the updated offset
437 63         172 return $offset + length $$buffer;
438             }
439              
440             ###########################################################
441             # This method creates a list containing the references #
442             # (or their indexes in the segment references list, if #
443             # the second argument is 'INDEXES') of those segments #
444             # whose name matches a given regular expression. #
445             # The output can be invalid after adding/removing any #
446             # segment. If $regex is undefined or evaluates to the #
447             # empty string, this method returns all indexes. #
448             ###########################################################
449             sub get_segments {
450 678     678 1 15512 my ($this, $regex, $do_indexes) = @_;
451             # fix the regular expression to '.' if undefined or set to the
452             # empty string. I do this because I want to avoid the stupid
453             # behaviour of m//; from `man perlop`: if the pattern evaluates
454             # to the empty string, the last successfully matched regular
455             # expression is used instead; if no match has previously succeeded,
456             # this will (silently) act instead as a genuine empty pattern
457 678 100 100     2741 $regex = '.' unless defined $regex && length $regex > 0;
458             # get the list of segment references in this file
459 678         993 my $segments = $this->{segments};
460             # return the list of matched segments
461 1539         3125 return (defined $do_indexes && $do_indexes eq 'INDEXES') ?
462 6580         14590 grep { $$segments[$_]->{name} =~ /$regex/ } 0..$#$segments :
463 678 100 66     2370 grep { $_->{name} =~ /$regex/ } @$segments;
464             }
465              
466             ###########################################################
467             # This method erases from the internal segment list all #
468             # segments matching the $regex regular expression. If #
469             # $regex is undefined or evaluates to the empty string, #
470             # this method throws an exception, because I don't want #
471             # the user to erase the whole file just because he/she #
472             # did not understand what he was doing. The apocalyptic #
473             # behaviour can be forced by setting $regex = '.'. One #
474             # must remember that it is not wise to drop non-metadata #
475             # segments, because this in general invalidates the file. #
476             # As a special case, if $regex == 'METADATA', all APP* #
477             # and COM segments are erased. #
478             ###########################################################
479             sub drop_segments {
480 30     30 1 3427 my ($this, $regex) = @_;
481             # refuse to work with empty or undefined regular expressions
482 30 100 100     179 $this->die('regular expression not specified')
483             unless defined $regex && length $regex > 0;
484             # if $regex is 'METADATA', convert it
485 26 100       79 $regex = '^(APP\d{1,2}|COM)$' if $regex eq 'METADATA';
486             # rewrite the segment list keeping only segments not matching
487             # $regex (see get_segments for further considerations).
488 26         706 @{$this->{segments}} =
  354         764  
489 26         43 grep { $_->{name} !~ /$regex/ } @{$this->{segments}};
  26         103  
490             }
491              
492             ###########################################################
493             # This method inserts the segments referenced by $segref #
494             # into the current list of segments at position $pos. If #
495             # $segref is undefined, the method fails silently. If #
496             # $pos is undefined, the position is chosen automatically #
497             # (using find_new_app_segment_position); if $pos is out #
498             # of bound, an exception is thrown; this happens also if #
499             # $pos points to the first segment, and it is SOI. #
500             # $segref may be a reference to a single segment or a #
501             # reference to a list of segment references; everything #
502             # else throws an exception. If overwrite is defined, it #
503             # must be the number of segs to overwrite during splice. #
504             ###########################################################
505             sub insert_segments {
506 56     56 1 5076 my ($this, $segref, $pos, $overwrite) = @_;
507             # do nothing if $segref is undefined or is not a reference
508 56 100       141 return unless ref $segref;
509             # segref may be a reference to a segment or a reference
510             # to a list; we must turn it into a reference to a list
511 55 100       179 $segref = [ $segref ] unless ref $segref eq 'ARRAY';
512             # check that all elements in the list are segment references
513             ref $_ eq 'Image::MetaData::JPEG::Segment' ||
514 55   33     188 $this->die('$segref is not a reference') for @$segref;
515             # calculate a convenient position if the user neglects to;
516             # remember to pass the new segment name as an argument
517 55 50       166 $pos = $this->find_new_app_segment_position
    100          
518             (exists $$segref[0] ? $$segref[0]->{name} : undef) unless defined $pos;
519 55         100 my $max_pos = -1 + $this->get_segments();
520             # fail if $pos is negative or out-of-bound;
521 55 100 66     296 $this->die("out-of-bound position $pos [0, $max_pos]")
522             if $pos < 0 || $pos > $max_pos;
523             # fail if $pos points to the first segment and it is SOI
524 54 100 100     162 $this->die('inserting on start-of-image is forbidden')
525             if $pos == 0 && $this->{segments}->[0]->{name} eq 'SOI';
526             # do the actual insertion (one or multiple segments);
527             # if overwrite is defined, it must be the number of
528             # segments to overwrite during the splice.
529 53 100       105 $overwrite = 0 unless defined $overwrite;
530 53         63 splice @{$this->{segments}}, $pos, $overwrite, @$segref;
  53         234  
531             }
532              
533             ###########################################################
534             # This method finds a position for a new application or #
535             # comment segment to be placed in the file. The algorithm #
536             # is the following: the position is chosen immediately #
537             # before the first (or after the last) element of some #
538             # list, provided that the list is not empty, otherwise #
539             # the next list is taken into account: #
540             # -) [for COM segments only] try after 'COM' segments; #
541             # otherwise try after all APP segments; #
542             # -) [for APPx segments only] try after the last element #
543             # of the list of APPy's (with y = x..0, in sequence); #
544             # otherwise try before the first element of the list #
545             # of APPy's (with y = x+1..15, in sequence); #
546             # -) try before the first DHP segment #
547             # -) try before the first SOF segment #
548             # If all these approaches fail, this method returns the #
549             # position immediately after the SOI segment (i.e., 1). #
550             # ------------------------------------------------------- #
551             # The argument must be the name of the segment to be #
552             # inserted (it defaults to 'COM', producing a warning). #
553             ###########################################################
554             sub find_new_app_segment_position {
555 32     32 1 2263 my ($this, $name) = @_;
556             # if name is not specified, issue a warning and set 'COM'
557 32 100       79 $this->warn('Segment name not specified: using COM'), $name = 'COM'
558             unless $name;
559             # setting $name to something else than 'COM' or 'APPx' is an error
560 32 50       176 $this->die("Unknown segment name ($name)")
561             unless $name =~ /^(COM|APP([0-9]|1[0-5]))$/;
562             # just in order to avoid a warning for half-read files
563             # with an incomplete set of segments, let us make sure
564             # that no position is past the segment array end
565 32         72 my $last_segment = -1 + $this->get_segments();
566 32 100   32   124 my $safe = sub { ($last_segment < $_[0]) ? $last_segment : $_[0] };
  32         249  
567             # this private function returns a list containing the
568             # indexes of the segments whose name matches the argument
569 32     105   109 my $list = sub { $this->get_segments('^'.$_[0].'$', 'INDEXES') };
  105         214  
570             # if there are already some 'COM' segments, let us put the new COM
571             # segment immediately after them; otherwise try after all APP segments
572 32 100       108 if ($name =~ /^COM/) {
573 12         21 return &$safe(1+$_) for reverse &$list('COM');
574 7         18 return &$safe(1+$_) for reverse &$list('APP.*'); }
575             # if $name is APPx, try after the last element of the list of APPy's
576             # (with y = x .. 0, in sequence); if all these fail, try before the
577             # first element of the list of APPy's (with y = x+1..15, in sequence)
578 22 100       143 if ($name =~ /^APP(.*)$/) {
579 20         133 for (reverse 0..$1) {return &$safe(1+$_) for reverse &$list("APP$_");};
  76         158  
580 2         9 for (1+$1..15) { return &$safe($_) for &$list("APP$_"); }; }
  4         9  
581             # if all specific tests failed, try with the
582             # first DHP segment or the first SOF segment
583 3         14 return &$safe($_) for &$list('DHP');
584 3         8 return &$safe($_) for &$list('SOF');
585             # if even this fails, try after start-of-image (just in order
586             # to avoid a warning for half-read files with not even two
587             # segments (they cannot be saved), return 0 if necessary)
588 3         9 return &$safe(1);
589             }
590              
591             ###########################################################
592             # Load other parts for this package. In order to avoid #
593             # that this file becomes too large, only general interest #
594             # methods are written here. #
595             ###########################################################
596             require 'Image/MetaData/JPEG/access/various.pl';
597             require 'Image/MetaData/JPEG/access/comments.pl';
598             require 'Image/MetaData/JPEG/access/app1_exif.pl';
599             require 'Image/MetaData/JPEG/access/app13.pl';
600              
601             # successful package load
602             1;