File Coverage

blib/lib/Scanner/Format.pm
Criterion Covered Total %
statement 33 90 36.6
branch 7 46 15.2
condition n/a
subroutine 9 25 36.0
pod 9 12 75.0
total 58 173 33.5


line stmt bran cond sub pod time code
1             #================================ Format.pm ==================================
2             # Filename: Format.pm
3             # Description: Page Scan Format Class.
4             # Original Author: Dale M. Amon
5             # Revised by: $Author: amon $
6             # Date: $Date: 2008-09-24 19:18:03 $
7             # Version: $Revision: 1.2 $
8             # License: LGPL 2.1, Perl Artistic or BSD
9             #
10             #=============================================================================
11 1     1   754 use strict;
  1         2  
  1         53  
12              
13             package Scanner::Format;
14 1     1   6 use vars qw{@ISA};
  1         2  
  1         1795  
15             @ISA = qw( UNIVERSAL );
16              
17             #=============================================================================
18             # CLASS METHODS
19             #=============================================================================
20             $Scanner::Format::DEFAULT_UNITS = undef;
21              
22             sub defaultUnitsAre ($$) {
23 1     1 1 1 my ($class, $units) = @_;
24 1 50       5 defined $units || return 0;
25 1 50       2 if (Scanner::Format->_validateUnits ($units)) {
26 1         1 $Scanner::Format::DEFAULT_UNITS = lc $units;
27 1         2 return 1;
28             }
29 0         0 return 0;
30             }
31              
32             #-----------------------------------------------------------------------------
33             $Scanner::Format::DEFAULT_FORMAT = undef;
34              
35             sub defaultFormatIs ($$) {
36 1     1 0 1 my ($class, $format) = @_;
37 1 50       3 defined $format || return 0;
38            
39 1         2 my ($t,$w,$h) = Scanner::Format->_validateFormat ($format);
40 1 50       2 $t || return 0;
41              
42 1         2 $Scanner::Format::DEFAULT_FORMAT = $format;
43 1         1 return 1;
44             }
45              
46             #-----------------------------------------------------------------------------
47             $Scanner::Format::DEFAULT_CALIBRATOR = 0;
48              
49 0     0 1 0 sub setDefaultCalibratorFlag {$Scanner::Format::DEFAULT_CALIBRATOR = 1;}
50 1     1 1 1 sub clrDefaultCalibratorFlag {$Scanner::Format::DEFAULT_CALIBRATOR = 0;}
51              
52             #-----------------------------------------------------------------------------
53              
54             sub new {
55 0     0 1 0 my $class = shift;
56 0         0 my %params = @_;
57 0         0 my $self = bless {}, $class;
58              
59 0 0       0 $self->_setPaperSpecs (\%params) || return undef;
60 0 0       0 $self->_setCalibrator (\%params) || return undef;
61              
62 0         0 return $self;
63             }
64              
65             #=============================================================================
66             # INSTANCE METHODS
67             #=============================================================================
68              
69             sub info ($$) {
70 0     0 1 0 my ($self,$str) = @_;
71 0         0 my $u = $self->{'units'};
72 0         0 my ($pw,$pl) = $self->UserDimensions;
73 0         0 my ($sw,$sl) = ($self->_unconvertLength ($u,$self->{'width'}),
74             $self->_unconvertLength ($u,$self->_actualHeight));
75              
76 0 0       0 printf "[$str Format]\n" .
    0          
77             "Format string: %s\n" .
78             "Scan orientation: %s\n" .
79             "Paper type: %s\n" .
80             "Scan width: %6.2f %s\n" .
81             "Scan length: %6.2f %s\n" .
82             "Calibrator margin: %s\n" .
83             "Total scan width: %6.2f %s\n" .
84             "Total scan length: %6.2f %s\n",
85             $self->{'format'},
86             ($self->{'orientation'} eq "P") ? "Scanner top is page top." :
87             "Scanner left is page top.",
88             ucfirst $self->{'papertype'},
89             $pw, $self->_unitsPrintString ($pw),
90             $pl, $self->_unitsPrintString ($pl),
91             ($self->{'calibrator'}) ? "On" : "Off",
92             $sw, $self->_unitsPrintString ($sw),
93             $sl, $self->_unitsPrintString ($sl);
94              
95 0         0 return $self;
96             }
97              
98             #-----------------------------------------------------------------------------
99              
100             sub ScanDimensions ($) {
101 0     0 0 0 my $self = shift;
102 0         0 return ($self->{'width'}, $self->_actualHeight);
103             }
104              
105             sub UserDimensions ($) {
106 0     0 0 0 my $self = shift;
107 0         0 my $u = $self->{'units'};
108 0         0 my $w = $self->_unconvertLength ($u,$self->{'width'});
109 0         0 my $h = $self->_unconvertLength ($u,$self->{'height'});
110 0         0 return ($w,$h);
111             }
112              
113 0     0 1 0 sub landscape ($) {shift->{'orientation'} eq "L";}
114 0     0 1 0 sub portrait ($) {shift->{'orientation'} eq "P";}
115 0     0 1 0 sub orientation ($) {shift->{'orientation'};}
116 0     0 1 0 sub format ($) {shift->{'format'};}
117              
118             #=============================================================================
119             # INTERNAL CLASS METHODS
120             #=============================================================================
121             # Orientation Description
122             #------------------------------------------------------
123             $Scanner::Format::Orientation = { "L" => "Landscape",
124             "P" => "Portrait"
125             };
126             sub _validateOrientation ($$) {
127 1     1   2 shift; my $o = uc shift;
  1         1  
128 1         3 return exists $Scanner::Format::Orientation->{$o};
129             }
130              
131             #-----------------------------------------------------------------------------
132             # Unit Units per mm
133             #------------------------------------------------------
134             $Scanner::Format::PaperUnits = { "mm" => 1.0,
135             "mm's" => 1.0,
136             "mms" => 1.0,
137             "inch" => 25.4,
138             "inches" => 25.4
139             };
140             sub _validateUnits ($$) {
141 1     1   2 shift; my $u = lc shift;
  1         2  
142 1         4 return exists $Scanner::Format::PaperUnits->{$u};
143             }
144              
145              
146             #-----------------------------------------------------------------------------
147             # It returns a list (type,width,height), which may all be undef.
148             #
149             # Type width(mm) height(mm)
150             #-----------------------------------------------------------------
151             $Scanner::Format::PaperSpecs = { "a4" => [8.5*25.4, 12.0*25.4],
152             "letter" => [8.5*25.4, 11.0*25.4],
153             "legal" => [8.5*25.4, 13.0*25.4]
154             };
155              
156             sub _validatePaperSpecs ($$) {
157 1     1   1 shift; my $p = lc shift;
  1         7  
158 1         3 return exists $Scanner::Format::PaperSpecs->{$p};
159             }
160              
161             sub _paperSpecs ($$) {
162 0     0   0 shift; my $p = lc shift;
  0         0  
163 0         0 return ($p, @{ $Scanner::Format::PaperSpecs->{$p} });
  0         0  
164             }
165              
166             #-----------------------------------------------------------------------------
167              
168             sub _validateFormat ($$) {
169 1     1   1 my ($self, $format) = @_;
170              
171 1         5 my ($o,$w,$l) = split /[:x]/, $format, 3;
172              
173 1 50       3 $self->_validateOrientation(uc $o) || (return (undef,undef,undef));
174            
175 1 50       6 if ($w =~ /^[[:digit:].]*$/) {
176 0 0       0 return (undef,undef,undef) if ($w <= 0.0);
177 0 0       0 return (undef,undef,undef) if ($l <= 0.0);
178 0 0       0 return (undef,undef,undef) if ($l !~ /^[[:digit:].]*$/);
179             }
180             else {
181 1 50       2 return (undef,undef,undef) if (!$self->_validatePaperSpecs ($w));
182             }
183 1         3 return ($o,$w,$l);
184             }
185              
186             #-----------------------------------------------------------------------------
187             # Convert a length from the current unit into the internally used mm. The unit
188             # type is used to look up a conversion factor in the unit's hash.
189              
190             sub _convertLength ($$$) {
191 0     0     my ($s,$u,$l) = @_;
192 0           return $Scanner::Format::PaperUnits->{$u} * $l;
193             }
194              
195             #-----------------------------------------------------------------------------
196              
197             sub _unconvertLength ($$$) {
198 0     0     my ($s,$u,$l) = @_;
199 0           return $l / $Scanner::Format::PaperUnits->{$u};
200             }
201              
202             #-----------------------------------------------------------------------------
203              
204             my $UnitSingular = { "mm" => "mm",
205             "mm's" => "mm",
206             "mms" => "mm",
207             "inch" => "inch",
208             "inches" => "inch"
209             };
210            
211             my $UnitPlural = { "mm" => "mm's",
212             "mm's" => "mm's",
213             "mms" => "mm's",
214             "inch" => "inches",
215             "inches" => "inches"
216             };
217              
218             sub _unitsPrintString ($$) {
219 0     0     my ($s,$l) = @_;
220 0           my $u = $s->{'units'};
221 0 0         return ($l eq 1) ? $UnitSingular->{$u} : $UnitPlural->{$u};
222             }
223              
224             #=============================================================================
225             # INTERNAL OBJECT METHODS
226             #=============================================================================
227             # Convert a length into the current unit. The unit type is used to look up
228             # a conversion factor in the unit's hash. It returns the height to be scanned
229             # which includes extra inch if calibrator is true.
230              
231             sub _actualHeight ($) {
232 0     0     my $self = shift;
233 0 0         return $self->{'height'} + (($self->{'calibrator'}) ? 25.4 : 0.0);
234             }
235              
236             #-----------------------------------------------------------------------------
237              
238             sub _setPaperSpecs ($$) {
239 0     0     my ($self, $params) = @_;
240 0           my ($u,$p,$o,$w,$l);
241              
242 0 0         $u = (defined $params->{'units'}) ?
243             lc $params->{'units'} : $Scanner::Format::DEFAULT_UNITS;
244 0 0         return 0 if (!$self->_validateUnits($u));
245              
246 0 0         my $format = (defined $params->{'format'}) ?
247             $self->{'format'} = $params->{'format'} :
248             $Scanner::Format::DEFAULT_FORMAT;
249              
250 0           ($o,$w,$l) = $self->_validateFormat($format);
251 0 0         return 0 if (!defined $o);
252              
253             # Convert external units to internally used mm.
254 0 0         if ($w =~ /^[[:digit:].]*$/) {
255 0           ($p,$w,$l) = ("undefined",
256             $self->_convertLength ($u, $w),
257             $self->_convertLength ($u, $l));
258             }
259             # Internal units are already in mm.
260             else {
261 0           ($p,$w,$l) = $self->_paperSpecs ($w);
262             }
263              
264 0           @$self{'format','units','orientation','papertype','width','height'} =
265             ($format, lc $u, uc $o,$p,$w,$l);
266 0           return 1;
267             }
268              
269             #-----------------------------------------------------------------------------
270              
271             sub _setCalibrator ($$) {
272 0     0     my ($self, $params) = @_;
273              
274 0 0         my $calibrator = (defined $params->{'calibrator'}) ?
275             $params->{'calibrator'} : $Scanner::Format::DEFAULT_CALIBRATOR;
276 0 0         $self->{'calibrator'} = ($calibrator) ? 1 : 0;
277 0           return 1;
278             }
279              
280             #=============================================================================
281             # Set Class Runtime Defaults
282             #=============================================================================
283              
284             Scanner::Format->defaultUnitsAre ("mm");
285             Scanner::Format->clrDefaultCalibratorFlag;
286             Scanner::Format->defaultFormatIs ("P:A4");
287            
288             #=============================================================================
289             # POD DOCUMENTATION
290             #=============================================================================
291             # You may extract and format the documention section with the 'perldoc' cmd.
292              
293             =head1 NAME
294              
295             Scanner::Format - Page Scan format class.
296              
297             =head1 SYNOPSIS
298              
299             use Scanner::Format;
300              
301             $obj = Scanner::Format->new ( list of named arguments );
302             Scanner::Format->setDefaultCalibratorFlag;
303             Scanner::Format->clrDefaultCalibratorFlag;
304             $bool = Scanner::Format->defaultUnitsAre ( $myunits );
305             $bool = Scanner::Format->defaultFormatIs ( $myformat );
306              
307             ($width, $height) = $obj->ScanDimensions;
308             ($width, $height) = $obj->UserDimensions;
309             $flg = $obj->landscape;
310             $flg = $obj->portrait;
311             $str = $obj->orientation;
312             $str = $obj->format;
313             $obj = $obj->info ($str);
314              
315             =head1 Inheritance
316              
317             UNIVERSAL
318              
319             =head1 Description
320              
321             This class is a representation of a format of a page.
322              
323             =head1 Examples
324              
325             use Scanner::Format;
326              
327             my $flg = Scanner::Format->defaultUnitsAre ( "Inches" );
328             $flg = Scanner::Format->defaultFormatIs ( "P:Letter" );
329             Scanner::Format->setDefaultCalibratorFlag;
330              
331             my $obj = Scanner::Format->new ('format' => "P:8.5x13.0");
332             my ($x,$y) = $obj->ScanDimensions;
333              
334             if ($obj->landscape) {print "It is a landscape format.\n";}
335             if ($obj->portrait ) {print "It is a portrait format.\n";}
336              
337             =head1 Class Variables
338              
339             DEFAULT_UNITS Assume arguments to every new are in
340             this unit. Default is mm.
341             DEFAULT_FORMAT If a new method does not specify a format
342             assume this format. Default is a Portrait
343             A4 page, ie 215.9 x 304.8 mm.
344             DEFAULT_CALIBRATOR Flag whether an extra inch or 25.4 mm
345             should be added to the bottom to allow for
346             calibration tools below the page. Default is
347             off.
348              
349             =head1 Instance Variables
350              
351             format page format string
352             calibrator Flag indicating whether extra space is left at the bottom.
353             orientation L for landscape and P for Portrait.
354             height Height of the page in default units, usually mm.
355             width Width of the page in default units, usually mm.
356             papertype a4, letter, etc. May be undefined.
357              
358             =head1 Class Methods
359              
360             =over 4
361              
362             =item B<$obj = Scanner::Format-Enew ( named argument list )>
363              
364             This is the Class method for creating new Scanner::Format objects. It may have
365             many different arguments. They are in short:
366              
367             format -> string {OPT: default is "P:A4"]
368             calibrator -> boolean [OPT: default is 1]
369             units -> mm|inches [OPT: default is "mm"]
370              
371             'calibrator' =>
372              
373             If set, add an extra inch below the page. The default value is false.
374              
375             'units' =>
376              
377             Sets the unit of measure to be used when interpreting the width and height
378             parameters. Current choices are "mm" and "inches". The default value is "mm"
379             since that is what the 'scanimage' program uses.
380              
381             'format' =>
382              
383             A format string has two or 3 fields:
384              
385             := : |
386             :x
387              
388             where:
389              
390             : is the page placement on the scanner, either L for landscape or
391             P for portrait.
392              
393             : allowed values at present are a4, letter and legal (case is ignored).
394              
395             : scan width of the page in the current units of measure and must be
396             greater than zero.
397              
398             : scan height of the page in the current units of measure and must be
399             greater than zero.
400              
401             All fields are case insensitive.
402              
403             The default value is a portrait oritentation of an a4 paper type. The size is
404             8.5 inch * 25.4 mm/inch across the width of the scanner and 12.5 inch * 25.4 mm/inch down
405             the length of the scanner.
406              
407             'date' =>
408              
409             A date to be included as the first part of the page name, where a single date
410             is represented as:
411              
412             yyyymmdd
413             yyyymmddhhmmss
414              
415             and mm and dd may be 00 to represent 'the whole month' or the 'whole year' as
416             in a monthly magazine or a yearly report, or to represent uncertainty, 'it
417             was from sometime in that year'. there may optionally be two dates, so as to
418             represent a period of time associated with the page:
419              
420             date1-date2
421              
422             =item BsetDefaultCalibratorFlag>
423              
424             Setting this will make every object created add an extra inch below each page
425             unless specifically overridden by 'calibrator' => 0 when a new object is
426             created.
427              
428             The intent of this option is to leave space for placement of a
429             size/color/aspect-ratio calibration devices in the scan field of view. Common
430             image calibration devices are small color wheels, rulers, little square
431             things like you see in photos by field Geologists, or perhaps a round coin to
432             show aspect ratios. Such calibrators act are a permanent means of mapping an
433             image to its real world original.
434              
435             The feature is turned off by default. It may either be set on by default with
436             this Class method, or turned on explicitly for particular page objects.
437              
438             =item BclrDefaultCalibratorFlag>
439              
440             The converse of the above. Since this is the default condition of the Class,
441             you will only need to run this if you have executed a setDefaultCalibratorFlag
442             somewhere in your code.
443              
444             =item B<$bool = Scanner::Format-EdefaultUnitsAre ( $units )>
445              
446             Set the default units for height and width input values. Legal inputs are "mm"
447             and "inches". Case is ignored. Any other value causes a false return.
448              
449             If you do nothing, the class default is "mm" because the scanimage program
450             assumes metric.
451              
452             Returns true on success; false if no arg or it wasn't one of the two valid
453             options.
454              
455             =item B<$bool = Scanner::Format-EdefaultPaperTypeIs ( $papertype )>
456              
457             Set the default paper type. Legal values are "a4", "letter" or "legal". Case
458             is ignored. Any other value causes a false return.
459              
460             If you do nothing, the class default is "a4". Why? Because we used metric for
461             the units default. Consistency is next to godliness I always say.
462              
463             =back 4
464              
465             =head1 Instance Methods
466              
467             =over 4
468              
469             =item B<$str = $obj-Eformat>
470              
471             Return the current page scan format string.
472              
473             =item B<$flg = $obj-Einfo ($str)>
474              
475             Print a block of informational text to stdout:
476              
477             [$str Format]
478             Format: P:8.5x12
479             Scan Orientation: P
480             Paper type: undefined
481             Scan width: 8.5 Inches
482             Scan length: 12 Inches
483             Image Calibrator Margin: 0 Iinches
484              
485             =item B<$flg = $obj-Elandscape>
486              
487             Return true if it uses a landscape page format.
488              
489             =item B<$flg = $obj-Eorientation>
490              
491             Return the orientation string, "L" or "P".
492              
493             =item B<$flg = $obj-Eportrait>
494              
495             Return true if it uses a portrait page format.
496              
497             =item B<($width, $height) = $obj-E>gt>ScanDimensions>
498              
499             Retrieve the page dimensions to be used for scanning. The height may include
500             extra space for calibration devices as earlier discussed in the
501             Scanner::Format->setDefaultCalibratorFlag section:
502              
503             (width, height+calibratorheight)
504              
505             The scanner might of course have something to say about the height or width we
506             have selected! That, however, is not the Format's problem. It is what it is
507             and it might be too large for the scanner you have.
508              
509             =item B<($width, $height) = $obj-E>gt>UserDimensions>
510              
511             Retrieve the page dimensions as originally supplied by the user.
512              
513             =back 4
514              
515             =head1 Private Class Methods
516              
517             None.
518              
519             =head1 Private Instance Methods
520              
521             None.
522              
523             =head1 Errors and Warnings
524              
525             None.
526              
527             =head1 KNOWN BUGS
528              
529             See TODO.
530              
531             =head1 SEE ALSO
532              
533             None.
534              
535             =head1 AUTHOR
536              
537             Dale Amon
538              
539             =cut
540            
541             #=============================================================================
542             # CVS HISTORY
543             #=============================================================================
544             # $Log: Format.pm,v $
545             # Revision 1.2 2008-09-24 19:18:03 amon
546             # Fix bug in info method printout; improve formating of info output.
547             #
548             # Revision 1.1 2008-08-28 23:31:43 amon
549             # Major rewrite. Shuffled code between classes and add lots of features.
550             #
551             # Revision 1.2 2008-08-07 19:52:48 amon
552             # Upgrade source format to current standard.
553             #
554             # Revision 1.1.1.1 2006-06-15 22:06:59 amon
555             # Classes for scanner use abstractions.
556             #
557             # 20060615 Dale Amon
558             # Added check for an attempt to set a zero height or width.
559             # 20040818 Dale Amon
560             # Created.
561             1;