source: gsdl/trunk/perllib/plugins/ImageConverter.pm@ 15866

Last change on this file since 15866 was 15866, checked in by kjdon, 16 years ago

plugin overhaul: Image conversion stuff moved to this helper plugin, so many plugins can share it.

  • Property svn:executable set to *
File size: 12.8 KB
Line 
1package ImageConverter;
2
3use PrintInfo;
4
5use strict;
6
7BEGIN {
8 @ImageConverter::ISA = ('PrintInfo');
9}
10
11my $arguments = [
12 { 'name' => "create_thumbnail",
13 'desc' => "{ImageConverter.generatethumbnail}",
14 'type' => "bool",
15 'deft' => "true",
16 'reqd' => "no" },
17 { 'name' => "noscaleup",
18 'desc' => "{ImageConverter.noscaleup}",
19 'type' => "flag",
20 'reqd' => "no" },
21 { 'name' => "thumbnailsize",
22 'desc' => "{ImageConverter.thumbnailsize}",
23 'type' => "int",
24 'deft' => "100",
25 'range' => "1,",
26 'reqd' => "no" },
27 { 'name' => "thumbnailtype",
28 'desc' => "{ImageConverter.thumbnailtype}",
29 'type' => "string",
30 'deft' => "gif",
31 'reqd' => "no" },
32 { 'name' => "create_screenview",
33 'desc' => "{ImageConverter.generatescreenview}",
34 'type' => "bool",
35 'deft' => "true",
36 'reqd' => "no" },
37 { 'name' => "screenviewsize",
38 'desc' => "{ImageConverter.screenviewsize}",
39 'type' => "int",
40 'deft' => "500",
41 'range' => "1,",
42 'reqd' => "no" },
43 { 'name' => "screenviewtype",
44 'desc' => "{ImageConverter.screenviewtype}",
45 'type' => "string",
46 'deft' => "jpg",
47 'reqd' => "no" },
48 { 'name' => "converttotype",
49 'desc' => "{ImageConverter.converttotype}",
50 'type' => "string",
51 'deft' => "",
52 'reqd' => "no" },
53 { 'name' => "noscaleup",
54 'desc' => "{ImageConverter.noscaleup}",
55 'type' => "flag",
56 'reqd' => "no" },
57 { 'name' => "minimumsize",
58 'desc' => "{ImageConverter.minimumsize}",
59 'type' => "int",
60 'deft' => "100",
61 'range' => "1,",
62 'reqd' => "no" },
63 { 'name' => "cache_generated_images",
64 'desc' => "{ImageConverter.cache_generated_image}",
65 'type' => "flag",
66 'reqd' => "no" }
67 ];
68
69my $options = { 'name' => "ImageConverter",
70 'desc' => "{ImageConverter.desc}",
71 'abstract' => "yes",
72 'inherits' => "yes",
73 'args' => $arguments };
74
75sub new {
76 my ($class) = shift (@_);
77 my ($pluginlist,$inputargs,$hashArgOptLists) = @_;
78 push(@$pluginlist, $class);
79
80 push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
81 push(@{$hashArgOptLists->{"OptList"}},$options);
82
83 my $self = new PrintInfo($pluginlist, $inputargs, $hashArgOptLists);
84
85 # Check that ImageMagick is installed and available on the path (except for Windows 95/98)
86 if (!($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT())) {
87 my $result = `identify 2>&1`;
88 if ($? == -1 || $? == 256) { # Linux and Windows return different values for "program not found"
89 $self->{'imagemagick_not_installed'} = 1;
90 }
91 }
92 return bless $self, $class;
93
94}
95
96sub init {
97 my $self = shift(@_);
98
99 $self->{'tmp_file_paths'} = ();
100}
101
102sub check_imagemagick {
103
104 my $self = shift (@_);
105 my ($gli) = @_;
106
107 my $outhandle = $self->{'outhandle'};
108
109 my $image_magick_ok = 1;
110 # None of this works very well on Windows 95/98...
111 if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) {
112 if ($gli) {
113 #print STDERR "<ProcessingError n='$file' r='Windows 95/98 not supported'>\n";
114 # have no file here. other kind of error? just want a warning really
115 }
116 print $outhandle "ImageConverter: Windows 95/98 not supported, no image processing available\n";
117 $image_magick_ok = 0;
118
119 } else {
120 # Check that ImageMagick is installed and available on the path
121 my $result = `identify 2>&1`;
122 if ($? == -1 || $? == 256) { # Linux and Windows return different values for "program not found"
123 if ($gli) {
124 #print STDERR "<ProcessingError n='$file' r='ImageMagick not installed'>\n";
125 }
126 print $outhandle "ImageConverter: ImageMagick not installed, no image processing available\n";
127 $image_magick_ok = 0;
128 }
129 }
130 return $image_magick_ok;
131
132}
133
134# convert image to new type if converttotype is set
135# generate thumbnails if required
136# generate screenview if required
137# discover image metadata
138sub generate_images {
139 my $self = shift(@_);
140
141 my ($filename_full_path, $filename_no_path, $doc_obj, $section) = @_;
142
143 # check the filenames
144 return 0 if ($filename_no_path eq "" || !-f $filename_full_path);
145
146 my $verbosity = $self->{'verbosity'};
147 my $outhandle = $self->{'outhandle'};
148
149 # check the size of the image against minimum size if specified
150 my $minimumsize = $self->{'minimumsize'};
151 if (defined $minimumsize && (-s $filename_full_path < $minimumsize)) {
152 print $outhandle "ImageConverter: \"$filename_full_path\" too small, skipping\n"
153 if ($verbosity > 1);
154 return 0; # or is there a better return value??
155 }
156
157 my $filehead = $filename_no_path;
158 $filehead =~ s/\.([^\.]*)$//; # filename with no extension
159 my $assocfilemeta = "[assocfilepath]";
160 if ($section ne $doc_obj->get_top_section()) {
161 $assocfilemeta = "[parent(Top):assocfilepath]";
162 }
163
164 # Convert the image to a new type (if required).
165 my $converttotype = $self->{'converttotype'};
166 my $type = "unknown";
167
168 if ($converttotype ne "" && $filename_full_path !~ m/$converttotype$/) {
169
170 my $result = $self->convert($filename_full_path, $converttotype, "", "");
171 ($filename_full_path) = ($result =~ /=>(.*\.$converttotype)/);
172
173 $type = $converttotype;
174 $filename_no_path = "$filehead.$type";
175 }
176
177 # add Image metadata
178 $doc_obj->add_metadata($section, "Image", $filename_no_path);
179
180 # Source and SourceUTF8 - should this be converted filename or original?
181 # here we overwrite the originals with converted ones
182 $self->set_Source_metadata($doc_obj, $filename_no_path);
183
184 # use identify to get info about the (possibly converted) image
185 my ($image_type, $image_width, $image_height, $image_size)
186 = &identify($filename_full_path, $outhandle, $verbosity);
187
188 if ($image_type ne " ") {
189 $type = $image_type;
190 }
191
192 #overwrite the ones added in BasePlugin
193 $doc_obj->set_metadata_element ($section, "FileFormat", $type);
194 $doc_obj->set_metadata_element ($section, "FileSize", $image_size);
195
196 $doc_obj->add_metadata ($section, "ImageType", $image_type);
197 $doc_obj->add_metadata ($section, "ImageWidth", $image_width);
198 $doc_obj->add_metadata ($section, "ImageHeight", $image_height);
199 $doc_obj->add_metadata ($section, "ImageSize", $image_size);
200
201 $doc_obj->add_metadata ($section, "srclink", "<a href=\"_httpprefix_/collect/[collection]/index/assoc/$assocfilemeta/[Image]\">");
202 $doc_obj->add_metadata ($section, "/srclink", "</a>");
203 $doc_obj->add_metadata ($section, "srcicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/$assocfilemeta/[Image]\" width=\"100\">");
204
205 # Add the image as an associated file
206 $doc_obj->associate_file($filename_full_path, $filename_no_path, "image/$type", $section);
207
208 if ($self->{'create_thumbnail'} eq "true") {
209 $self->create_thumbnail($filename_full_path, $filehead, $doc_obj, $section, $assocfilemeta);
210 }
211 if ($self->{'create_screenview'} eq "true") {
212 $self->create_screenview($filename_full_path, $filehead, $doc_obj, $section, $assocfilemeta);
213 }
214}
215
216sub create_thumbnail {
217 my $self = shift(@_);
218 my ($original_file, $filehead, $doc_obj, $section, $assocfilemeta) = @_;
219
220 my $thumbnailsize = $self->{'thumbnailsize'};
221 my $thumbnailtype = $self->{'thumbnailtype'};
222
223 # Generate the thumbnail with convert
224 my $result = $self->convert($original_file, $thumbnailtype, "-geometry $thumbnailsize" . "x$thumbnailsize", "THUMB");
225 my ($thumbnailfile) = ($result =~ /=>(.*\.$thumbnailtype)/);
226
227 # Add the thumbnail as an associated file ...
228 if (-e "$thumbnailfile") {
229 $doc_obj->associate_file("$thumbnailfile", $filehead."_thumb.$thumbnailtype",
230 "image/$thumbnailtype",$section);
231 $doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype);
232 $doc_obj->add_metadata ($section, "Thumb", $filehead."_thumb.$thumbnailtype");
233
234 $doc_obj->add_metadata ($section, "thumbicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/$assocfilemeta/[Thumb]\" width=[ThumbWidth] height=[ThumbHeight]>");
235
236
237 # Extract Thumbnail metadata from convert output
238 if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
239 $doc_obj->add_metadata ($section, "ThumbWidth", $1);
240 $doc_obj->add_metadata ($section, "ThumbHeight", $2);
241 }
242 } else {
243 my $outhandle = $self->{'outhandle'};
244 print $outhandle "Couldn't find thumbnail $thumbnailfile\n";
245
246 }
247}
248
249sub create_screenview {
250
251 my $self = shift(@_);
252 my ($original_file, $filehead, $doc_obj, $section, $assocfilemeta) = @_;
253
254 # To do: if the actual image smaller than the screenview size,
255 # we should use the original !
256
257 my $screenviewsize = $self->{'screenviewsize'};
258 my $screenviewtype = $self->{'screenviewtype'};
259
260 # make the screenview image
261 my $result = $self->convert($original_file, $screenviewtype, "-geometry $screenviewsize" . "x$screenviewsize", "SCREEN");
262 my ($screenviewfilename) = ($result =~ /=>(.*\.$screenviewtype)/);
263
264
265 #add the screenview as an associated file ...
266 if (-e "$screenviewfilename") {
267 $doc_obj->associate_file("$screenviewfilename", $filehead."_screen.$screenviewtype", "image/$screenviewtype",$section);
268 $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype);
269 $doc_obj->add_metadata ($section, "Screen", $filehead."_screen.$screenviewtype");
270
271 $doc_obj->add_metadata ($section, "screenicon", "<img src=\"_httpprefix_/collect/[collection]/index/assoc/$assocfilemeta/[Screen]\" width=[ScreenWidth] height=[ScreenHeight]>");
272
273 # get screenview dimensions, size and type
274 if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) {
275 $doc_obj->add_metadata ($section, "ScreenWidth", $1);
276 $doc_obj->add_metadata ($section, "ScreenHeight", $2);
277 } elsif ($result =~ m/([0-9]+)x([0-9]+)/) {
278 #if the image hasn't changed size, the previous regex doesn't match
279 $doc_obj->add_metadata ($section, "ScreenWidth", $1);
280 $doc_obj->add_metadata ($section, "ScreenHeight", $2);
281 }
282 } else {
283 my $outhandle = $self->{'outhandle'};
284 print $outhandle "Couldn't find screenview file $screenviewfilename\n";
285
286 }
287
288}
289
290
291
292sub convert {
293 my $self = shift(@_);
294 my $source_file_path = shift(@_);
295 my $target_file_type = shift(@_);
296 my $convert_options = shift(@_) || "";
297 my $convert_type = shift(@_) || "";
298
299 my $outhandle = $self->{'outhandle'};
300 my $verbosity = $self->{'verbosity'};
301
302 # Determine the full name and path of the output file
303 my $filehead = &util::get_tmp_filename();
304 my $target_file_path = $filehead . "." . $target_file_type;
305 push(@{$self->{'tmp_file_paths'}}, $target_file_path);
306
307 # Generate and run the convert command
308 my $convert_command = "convert -interlace plane -verbose $convert_options \"$source_file_path\" \"$target_file_path\"";
309 print $outhandle "$convert_type $convert_command\n" if ($verbosity > 2);
310 my $result = `$convert_command 2>&1`;
311 print $outhandle "$convert_type RESULT = $result\n" if ($verbosity > 2);
312
313 return $result;
314}
315
316
317# Discover the characteristics of an image file with the ImageMagick
318# "identify" command.
319
320sub identify {
321 my ($image, $outhandle, $verbosity) = @_;
322
323 # Use the ImageMagick "identify" command to get the file specs
324 my $command = "identify \"$image\" 2>&1";
325 print $outhandle "$command\n" if ($verbosity > 2);
326 my $result = '';
327 $result = `$command`;
328 print $outhandle "$result\n" if ($verbosity > 3);
329
330 # Read the type, width, and height
331 my $type = 'unknown';
332 my $width = 'unknown';
333 my $height = 'unknown';
334
335 my $image_safe = quotemeta $image;
336 if ($result =~ /^$image_safe (\w+) (\d+)x(\d+)/) {
337 $type = $1;
338 $width = $2;
339 $height = $3;
340 }
341
342 # Read the size
343 my $size = "unknown";
344 if ($result =~ m/^.* ([0-9]+)b/) {
345 $size = $1;
346 }
347 elsif ($result =~ m/^.* ([0-9]+)(\.([0-9]+))?kb?/) {
348 $size = 1024 * $1;
349 if (defined($2)) {
350 $size = $size + (1024 * $2);
351 # Truncate size (it isn't going to be very accurate anyway)
352 $size = int($size);
353 }
354 }
355 elsif ($result =~ m/^.* (([0-9]+)(\.([0-9]+))?e\+([0-9]+))(kb|b)?/) {
356 # Deals with file sizes on Linux of type "3.4e+02kb" where e+02 is 1*10^2.
357 # 3.4e+02 therefore evaluates to 3.4 x 1 x 10^2 = 340kb.
358 # Programming languages including Perl know how that 3.4e+02 is a number,
359 # so we don't need to do any calculations.
360 $size = $1*1; # turn the string into a number by multiplying it by 1
361 #if we did $size = $1; $size would be merely the string "3.4e+02"
362 $size = int($size); # truncate size
363 }
364 print $outhandle "file: $image:\t $type, $width, $height, $size\n"
365 if ($verbosity > 2);
366
367 # Return the specs
368 return ($type, $width, $height, $size);
369}
370
371sub clean_up_temporary_files {
372 my $self = shift(@_);
373
374 foreach my $tmp_file_path (@{$self->{'tmp_file_paths'}}) {
375 if (-e $tmp_file_path) {
376 &util::rm($tmp_file_path);
377 }
378 }
379
380}
381
3821;
Note: See TracBrowser for help on using the repository browser.