package ImageConverter; use PrintInfo; use strict; BEGIN { @ImageConverter::ISA = ('PrintInfo'); } my $arguments = [ { 'name' => "create_thumbnail", 'desc' => "{ImageConverter.generatethumbnail}", 'type' => "bool", 'deft' => "true", 'reqd' => "no" }, { 'name' => "noscaleup", 'desc' => "{ImageConverter.noscaleup}", 'type' => "flag", 'reqd' => "no" }, { 'name' => "thumbnailsize", 'desc' => "{ImageConverter.thumbnailsize}", 'type' => "int", 'deft' => "100", 'range' => "1,", 'reqd' => "no" }, { 'name' => "thumbnailtype", 'desc' => "{ImageConverter.thumbnailtype}", 'type' => "string", 'deft' => "gif", 'reqd' => "no" }, { 'name' => "create_screenview", 'desc' => "{ImageConverter.generatescreenview}", 'type' => "bool", 'deft' => "true", 'reqd' => "no" }, { 'name' => "screenviewsize", 'desc' => "{ImageConverter.screenviewsize}", 'type' => "int", 'deft' => "500", 'range' => "1,", 'reqd' => "no" }, { 'name' => "screenviewtype", 'desc' => "{ImageConverter.screenviewtype}", 'type' => "string", 'deft' => "jpg", 'reqd' => "no" }, { 'name' => "converttotype", 'desc' => "{ImageConverter.converttotype}", 'type' => "string", 'deft' => "", 'reqd' => "no" }, { 'name' => "noscaleup", 'desc' => "{ImageConverter.noscaleup}", 'type' => "flag", 'reqd' => "no" }, { 'name' => "minimumsize", 'desc' => "{ImageConverter.minimumsize}", 'type' => "int", 'deft' => "100", 'range' => "1,", 'reqd' => "no" }, { 'name' => "cache_generated_images", 'desc' => "{ImageConverter.cache_generated_image}", 'type' => "flag", 'reqd' => "no" } ]; my $options = { 'name' => "ImageConverter", 'desc' => "{ImageConverter.desc}", 'abstract' => "yes", 'inherits' => "yes", 'args' => $arguments }; sub new { my ($class) = shift (@_); my ($pluginlist,$inputargs,$hashArgOptLists) = @_; push(@$pluginlist, $class); push(@{$hashArgOptLists->{"ArgList"}},@{$arguments}); push(@{$hashArgOptLists->{"OptList"}},$options); my $self = new PrintInfo($pluginlist, $inputargs, $hashArgOptLists); # Check that ImageMagick is installed and available on the path (except for Windows 95/98) if (!($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT())) { my $result = `identify 2>&1`; if ($? == -1 || $? == 256) { # Linux and Windows return different values for "program not found" $self->{'imagemagick_not_installed'} = 1; } } return bless $self, $class; } sub init { my $self = shift(@_); $self->{'tmp_file_paths'} = (); } sub check_imagemagick { my $self = shift (@_); my ($gli) = @_; my $outhandle = $self->{'outhandle'}; my $image_magick_ok = 1; # None of this works very well on Windows 95/98... if ($ENV{'GSDLOS'} eq "windows" && !Win32::IsWinNT()) { if ($gli) { #print STDERR "\n"; # have no file here. other kind of error? just want a warning really } print $outhandle "ImageConverter: Windows 95/98 not supported, no image processing available\n"; $image_magick_ok = 0; } else { # Check that ImageMagick is installed and available on the path my $result = `identify 2>&1`; if ($? == -1 || $? == 256) { # Linux and Windows return different values for "program not found" if ($gli) { #print STDERR "\n"; } print $outhandle "ImageConverter: ImageMagick not installed, no image processing available\n"; $image_magick_ok = 0; } } return $image_magick_ok; } # convert image to new type if converttotype is set # generate thumbnails if required # generate screenview if required # discover image metadata sub generate_images { my $self = shift(@_); my ($filename_full_path, $filename_no_path, $doc_obj, $section) = @_; # check the filenames return 0 if ($filename_no_path eq "" || !-f $filename_full_path); my $verbosity = $self->{'verbosity'}; my $outhandle = $self->{'outhandle'}; # check the size of the image against minimum size if specified my $minimumsize = $self->{'minimumsize'}; if (defined $minimumsize && (-s $filename_full_path < $minimumsize)) { print $outhandle "ImageConverter: \"$filename_full_path\" too small, skipping\n" if ($verbosity > 1); return 0; # or is there a better return value?? } my $filehead = $filename_no_path; $filehead =~ s/\.([^\.]*)$//; # filename with no extension my $assocfilemeta = "[assocfilepath]"; if ($section ne $doc_obj->get_top_section()) { $assocfilemeta = "[parent(Top):assocfilepath]"; } # Convert the image to a new type (if required). my $converttotype = $self->{'converttotype'}; my $type = "unknown"; if ($converttotype ne "" && $filename_full_path !~ m/$converttotype$/) { my $result = $self->convert($filename_full_path, $converttotype, "", ""); ($filename_full_path) = ($result =~ /=>(.*\.$converttotype)/); $type = $converttotype; $filename_no_path = "$filehead.$type"; } # add Image metadata $doc_obj->add_metadata($section, "Image", $filename_no_path); # Source and SourceUTF8 - should this be converted filename or original? # here we overwrite the originals with converted ones $self->set_Source_metadata($doc_obj, $filename_no_path); # use identify to get info about the (possibly converted) image my ($image_type, $image_width, $image_height, $image_size) = &identify($filename_full_path, $outhandle, $verbosity); if ($image_type ne " ") { $type = $image_type; } #overwrite the ones added in BasePlugin $doc_obj->set_metadata_element ($section, "FileFormat", $type); $doc_obj->set_metadata_element ($section, "FileSize", $image_size); $doc_obj->add_metadata ($section, "ImageType", $image_type); $doc_obj->add_metadata ($section, "ImageWidth", $image_width); $doc_obj->add_metadata ($section, "ImageHeight", $image_height); $doc_obj->add_metadata ($section, "ImageSize", $image_size); $doc_obj->add_metadata ($section, "srclink", ""); $doc_obj->add_metadata ($section, "/srclink", ""); $doc_obj->add_metadata ($section, "srcicon", ""); # Add the image as an associated file $doc_obj->associate_file($filename_full_path, $filename_no_path, "image/$type", $section); if ($self->{'create_thumbnail'} eq "true") { $self->create_thumbnail($filename_full_path, $filehead, $doc_obj, $section, $assocfilemeta); } if ($self->{'create_screenview'} eq "true") { $self->create_screenview($filename_full_path, $filehead, $doc_obj, $section, $assocfilemeta); } } sub create_thumbnail { my $self = shift(@_); my ($original_file, $filehead, $doc_obj, $section, $assocfilemeta) = @_; my $thumbnailsize = $self->{'thumbnailsize'}; my $thumbnailtype = $self->{'thumbnailtype'}; # Generate the thumbnail with convert my $result = $self->convert($original_file, $thumbnailtype, "-geometry $thumbnailsize" . "x$thumbnailsize", "THUMB"); my ($thumbnailfile) = ($result =~ /=>(.*\.$thumbnailtype)/); # Add the thumbnail as an associated file ... if (-e "$thumbnailfile") { $doc_obj->associate_file("$thumbnailfile", $filehead."_thumb.$thumbnailtype", "image/$thumbnailtype",$section); $doc_obj->add_metadata ($section, "ThumbType", $thumbnailtype); $doc_obj->add_metadata ($section, "Thumb", $filehead."_thumb.$thumbnailtype"); $doc_obj->add_metadata ($section, "thumbicon", ""); # Extract Thumbnail metadata from convert output if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) { $doc_obj->add_metadata ($section, "ThumbWidth", $1); $doc_obj->add_metadata ($section, "ThumbHeight", $2); } } else { my $outhandle = $self->{'outhandle'}; print $outhandle "Couldn't find thumbnail $thumbnailfile\n"; } } sub create_screenview { my $self = shift(@_); my ($original_file, $filehead, $doc_obj, $section, $assocfilemeta) = @_; # To do: if the actual image smaller than the screenview size, # we should use the original ! my $screenviewsize = $self->{'screenviewsize'}; my $screenviewtype = $self->{'screenviewtype'}; # make the screenview image my $result = $self->convert($original_file, $screenviewtype, "-geometry $screenviewsize" . "x$screenviewsize", "SCREEN"); my ($screenviewfilename) = ($result =~ /=>(.*\.$screenviewtype)/); #add the screenview as an associated file ... if (-e "$screenviewfilename") { $doc_obj->associate_file("$screenviewfilename", $filehead."_screen.$screenviewtype", "image/$screenviewtype",$section); $doc_obj->add_metadata ($section, "ScreenType", $screenviewtype); $doc_obj->add_metadata ($section, "Screen", $filehead."_screen.$screenviewtype"); $doc_obj->add_metadata ($section, "screenicon", ""); # get screenview dimensions, size and type if ($result =~ m/[0-9]+x[0-9]+=>([0-9]+)x([0-9]+)/) { $doc_obj->add_metadata ($section, "ScreenWidth", $1); $doc_obj->add_metadata ($section, "ScreenHeight", $2); } elsif ($result =~ m/([0-9]+)x([0-9]+)/) { #if the image hasn't changed size, the previous regex doesn't match $doc_obj->add_metadata ($section, "ScreenWidth", $1); $doc_obj->add_metadata ($section, "ScreenHeight", $2); } } else { my $outhandle = $self->{'outhandle'}; print $outhandle "Couldn't find screenview file $screenviewfilename\n"; } } sub convert { my $self = shift(@_); my $source_file_path = shift(@_); my $target_file_type = shift(@_); my $convert_options = shift(@_) || ""; my $convert_type = shift(@_) || ""; my $outhandle = $self->{'outhandle'}; my $verbosity = $self->{'verbosity'}; # Determine the full name and path of the output file my $filehead = &util::get_tmp_filename(); my $target_file_path = $filehead . "." . $target_file_type; push(@{$self->{'tmp_file_paths'}}, $target_file_path); # Generate and run the convert command my $convert_command = "convert -interlace plane -verbose $convert_options \"$source_file_path\" \"$target_file_path\""; print $outhandle "$convert_type $convert_command\n" if ($verbosity > 2); my $result = `$convert_command 2>&1`; print $outhandle "$convert_type RESULT = $result\n" if ($verbosity > 2); return $result; } # Discover the characteristics of an image file with the ImageMagick # "identify" command. sub identify { my ($image, $outhandle, $verbosity) = @_; # Use the ImageMagick "identify" command to get the file specs my $command = "identify \"$image\" 2>&1"; print $outhandle "$command\n" if ($verbosity > 2); my $result = ''; $result = `$command`; print $outhandle "$result\n" if ($verbosity > 3); # Read the type, width, and height my $type = 'unknown'; my $width = 'unknown'; my $height = 'unknown'; my $image_safe = quotemeta $image; if ($result =~ /^$image_safe (\w+) (\d+)x(\d+)/) { $type = $1; $width = $2; $height = $3; } # Read the size my $size = "unknown"; if ($result =~ m/^.* ([0-9]+)b/) { $size = $1; } elsif ($result =~ m/^.* ([0-9]+)(\.([0-9]+))?kb?/) { $size = 1024 * $1; if (defined($2)) { $size = $size + (1024 * $2); # Truncate size (it isn't going to be very accurate anyway) $size = int($size); } } elsif ($result =~ m/^.* (([0-9]+)(\.([0-9]+))?e\+([0-9]+))(kb|b)?/) { # Deals with file sizes on Linux of type "3.4e+02kb" where e+02 is 1*10^2. # 3.4e+02 therefore evaluates to 3.4 x 1 x 10^2 = 340kb. # Programming languages including Perl know how that 3.4e+02 is a number, # so we don't need to do any calculations. $size = $1*1; # turn the string into a number by multiplying it by 1 #if we did $size = $1; $size would be merely the string "3.4e+02" $size = int($size); # truncate size } print $outhandle "file: $image:\t $type, $width, $height, $size\n" if ($verbosity > 2); # Return the specs return ($type, $width, $height, $size); } sub clean_up_temporary_files { my $self = shift(@_); foreach my $tmp_file_path (@{$self->{'tmp_file_paths'}}) { if (-e $tmp_file_path) { &util::rm($tmp_file_path); } } } 1;