# +-----------------------------------------------------------------------+ # | pLoader - a Perl photo uploader for Piwigo | # +-----------------------------------------------------------------------+ # | Copyright(C) 2008 Piwigo Team http://piwigo.org | # +-----------------------------------------------------------------------+ # | This program is free software; you can redistribute it and/or modify | # | it under the terms of the GNU General Public License as published by | # | the Free Software Foundation | # | | # | This program is distributed in the hope that it will be useful, but | # | WITHOUT ANY WARRANTY; without even the implied warranty of | # | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | # | General Public License for more details. | # | | # | You should have received a copy of the GNU General Public License | # | along with this program; if not, write to the Free Software | # | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | # | USA. | # +-----------------------------------------------------------------------+ package Uploader::ImageList; use strict; use Carp; use base qw/Uploader::Object/; use Image::ExifTool qw(:Public); use Image::Magick; use File::Spec; use Uploader::Image; use Data::Dumper; use Storable; use Digest::MD5::File qw/file_md5_hex md5_hex/; use Wx::Locale qw/:default/; use Wx; # this class implements a collection of image files with associated data $|=1; __PACKAGE__->mk_accessors( qw/ thumb_size preview_ratio categories type filter blur quality resize_w resize_h hd_filter hd_blur hd_quality hd_w hd_h hd_interlace prefix author count new_files storable_file wx_thumb_size current_image images image_selection exif_metadata wx_thumb_imglist wx_thumb_dir site_resized_dir site_thumb_dir userdata_dir progress_msg last_error_msg default_photo_name default_photo_name_method default_name_prefix SetNewFilesViewerRefreshCallback SetNewFilesProgressCallback SetNewFilesDisplayEndInfoCallback YieldCallback UploadImagesViewerCallback progress_thumbnail_refresh progress_msg_details_refresh progress_msg_refresh progressbar_refresh progress_endinfo_refresh RescaleCallback ResizeCallback upload_rejects pwg upload_high upload_hd remove_uploaded_from_selection wx_quality th_quality auto_rotate interlace create_resized use_exif_preview image_sums upload_image_sums sums version imagelist_version uploaded_images watermark_activate watermark_activate_pwg_high watermark_text watermark_text_size watermark_position watermark_y watermark_x watermark_color gravity rgbcolor upload_msg upload_selection_count upload_uploaded_count upload_rejected_count upload_last_error upload_error_content upload_begin_time upload_end_time upload_duration upload_file upload_name ReuploadCallback reupload_action_files reupload_action_properties reupload_action_properties_m reupload_not_ask / ); sub Init { my ( $self ) = @_; $self->uploaded_images([]); $self->gravity( { 'Top' => 'North', 'Left' => 'West', 'Right' => 'East', 'Bottom' => 'South', 'Top left' => 'NorthWest', 'Top right' => 'NorthEast', 'Bottom left' => 'SouthWest', 'Bottom right' => 'SouthEast', 'Center' => 'Center', } ); $self->rgbcolor( { "White" => '#FFFFFF', "Black" => '#000000', } ); } # save exif preview image if available # otherwise create a preview image sub _write_preview_image { my ( $self, $imagedata ) = @_; # If PreviewImage is available, we use it if(defined $imagedata ) { print "_write_preview_image, use exif PreviewImage\n"; eval { open PREVIEW_FILE, ">", $self->current_image->preview_file ; binmode PREVIEW_FILE; print PREVIEW_FILE $$imagedata; close PREVIEW_FILE; }; $self->last_error_msg($@) if $@; } } sub _set_exif_tag { my ( $self, $file, $tag, $newValue ) = @_; my $options = {}; # Create a new Image::ExifTool object my $exifTool = new Image::ExifTool; # Extract meta information from an image $exifTool->ExtractInfo($file, $options); # Set a new value for a tag $exifTool->SetNewValue($tag, $newValue); # Write new meta information to a file $exifTool->WriteInfo($file); } sub _set_current_image_filepaths { my ( $self ) = @_; my $filename = sprintf( "%s.%s", $self->current_image->file_sum, $self->type, ); $self->current_image->wx_thumb_file( File::Spec->catfile( $self->wx_thumb_dir, $filename ) ); $self->current_image->site_thumb_file( File::Spec->catfile( $self->site_thumb_dir, $filename ) ); } sub SetCurrentImage { my ( $self, $indx ) = @_; $self->current_image( $self->GetImage($indx) ); } sub SetNewFiles { my ( $self, $files ) = @_; $self->new_files( $files ); # if some files have been previously selected my $i = scalar @{$self->sums}; printf("SetNewFiles %s\n", $i); my $count = 0; $self->count($count); my $errors = 0; map { my $info = $self->_read_exif_metatdata($_->{ANSIPathName}); my $is_new_image = $self->_add_image($_, $info, $i); $self->SetCurrentImage($i); $self->_set_current_image_filepaths(); if($is_new_image){ #my $use_wx_resize = $self->_create_gui_preview($info); $self->_create_gui_thumbnail(); # ok if(!$@){ $self->progress_msg(gettext("Selection thumbnail created for %s")); } else { $self->progress_msg("An error has occured when processing %s\n$@"); # remove from list splice @{$self->sums}, $i, 1; $errors++; } $self->SetNewFilesProgressCallback->(); } $i++; $count++; $self->count($count); $self->SetNewFilesViewerRefreshCallback->(); } @{$files}; $self->SetNewFilesDisplayEndInfoCallback->( sprintf( "%s : %s\n\n%s : %s", gettext("photos added to the selection"), $self->count, gettext("errors"), $errors, ) ); $self->Store; } sub _read_exif_metatdata { my ( $self, $file ) = @_; # read exif metadata my $info; eval { $info = ImageInfo( $file ); }; $info = {} if($@); $info; } # key is file path sub _add_image { my ( $self, $file, $info, $i ) = @_; my $is_new_image; # for legacy imagelist that do not have image_sums property $self->image_sums( {} ) if !$self->image_sums; my $sum = file_md5_hex($file->{ANSIPathName}); my $image; if ( !exists $self->image_sums->{$sum} ){ #print "_add_image ", Dumper $file, "\n"; # append to image list $image = Uploader::Image->new( { file => $file->{ANSIPathName}, file_sum => $sum, site_name => $self->_default_photo_name($file->{PathName}, $info, $i), site_author => $self->author, exif_metadata => $self->_select_exif_data($info), add_rank => $i, site_categories => [], site_tags => [], site_high_file => $file->{ANSIPathName}, } ); $self->image_sums->{$sum} = $image ; $is_new_image = 1; } else { $image = $self->image_sums->{$sum}; } $self->sums->[$i] = $sum ; $is_new_image; } sub _default_photo_name { my ( $self, $file, $info, $i ) = @_; my $name; my $create_date = $info->{CreateDate}; my $ext; my ( $vol, $path, $filename ) = File::Spec->splitpath($file); ( $filename, $ext ) = split /\.\w+$/, $filename; my ( $yyyy, $mm, $dd, $hh, $mi, $ss ) = split /[:\s]/, $create_date ; my $chrono = join('', $yyyy, $mm, $dd); if('Prefix' eq $self->default_photo_name){ $name = $self->default_name_prefix } elsif('File name' eq $self->default_photo_name){ $name = $filename } elsif('File path and name' eq $self->default_photo_name){ $name = sprintf( "%s", File::Spec->catfile($path, $filename), ) } elsif('Prefix + rank number' eq $self->default_photo_name){ $name = sprintf( "%s%s", $self->default_name_prefix, 1+$i, ) } elsif('Rank number + prefix' eq $self->default_photo_name){ $name = sprintf( "%s%s", 1+$i, $self->default_name_prefix, ) } elsif('Prefix + create date chrono' eq $self->default_photo_name){ $name = sprintf( "%s%s", $self->default_name_prefix, $chrono, ) } elsif('Create date chrono + prefix' eq $self->default_photo_name){ $name = sprintf( "%s%s", $chrono, $self->default_name_prefix, ) } $name; } sub _create_gui_thumbnail { my ( $self ) = @_; eval { printf("create gui thumbnail\n"); # use the preview image to create a gui display thumbnail if(!$self->CreateGUIThumbnail()) { print "CreateGUIThumbnail failed, use callback\n"; $self->ResizeCallback->( $self->current_image->file, $self->current_image->wx_thumb_file, $self->type, $self->wx_thumb_size, $self->wx_thumb_size, $self->wx_quality, ); } }; } sub RemoveImageSelection { my ( $self ) = @_; return if (! scalar @{$self->sums} ); return if (! defined $self->image_selection ); $self->_remove_image_list($self->image_selection); # clear image selection $self->image_selection([]); } sub _remove_image_list { my ( $self, $list ) = @_; # higher first, to keep same indexes during remove my @images = reverse @$list; map { $self->DeleteImage($_); splice @{$self->sums}, $_, 1 ; $self->wx_thumb_imglist->Remove($_); shift @images; } @images; } sub RemoveImage { my ( $self, $index ) = @_; return if (! defined $self->image_selection ); return if (! defined $index ); $self->DeleteImage($index); splice @{$self->sums}, $index, 1 ; $self->wx_thumb_imglist->Remove($index); } # used for display in GUI. has to fit a square box ( wxImageList ) sub CreateGUIThumbnail { my ( $self ) = @_; # return 1 if( -e $self->current_image->wx_thumb_file ); my $rval = 0; print "CreateGUIThumbnail ", $self->current_image->wx_thumb_file, "\n"; my $image = new Image::Magick; my $size = $self->wx_thumb_size||100; my $status = $image->Set(size=>sprintf("%sx%s", 2*$size, 2*$size)); warn "$status" if $status ; $status = $image->ReadImage( $self->current_image->file ); warn "$status" if $status; return $rval if $status; $self->current_image->width( $image->Get('width') ); $self->current_image->height( $image->Get('height') ); printf("%sx%s%s\n", $size, $size, '^'); # maximize size and keep aspect ratio $status = $image->Thumbnail( geometry=>sprintf("%s%s>", $size*$size, '@') ); # to get adjusted to a square box #$status = $image->Thumbnail( # geometry=>sprintf("%sx%s%s", $size, $size, '^') #); warn "$status" if $status; return $rval if $status; # causes strange behaviour with i18n -> yellow borders when local is other than EN # $status = $image->Set(background=>"white"); # warn "$status" if $status ; $status = $image->Set(Gravity=>"Center"); warn "$status" if $status ; $image->Extent( geometry=>sprintf("%sx%s", $size, $size), gravity=>'center', ); $image->Set( quality=>$self->wx_quality||90 ); $status = $image->Strip(); warn "$status" if $status ; # exif from original image my $orientation = $self->current_image->exif_metadata->{Orientation}; # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW if( $orientation =~ m/Rotate (\d+)/ ){ printf( "Rotate %s\n", $1 ); $image->Rotate( degrees=>$1 ) if $self->auto_rotate; } $image->Write( sprintf( "%s:%s", $self->type, $self->current_image->wx_thumb_file, ) ); undef $image; $rval = 1; return $rval; } sub CreateResized { my ( $self ) = @_; my $rval = 1 ; #return $rval if( -e $self->current_image->site_resized_file ); printf( "Create resized %s\n", $self->current_image->file, ); my $image = new Image::Magick; my $status = $image->ReadImage( $self->current_image->file ); warn "$status" if $status ; return 0 if $status; my $w = $image->Get('width'); my $h = $image->Get('height'); # should calculate the aspect ratio my $resize_w = $self->resize_w; my $resize_h = $self->resize_h; if( $w < $h ){ my $resize_w_ = $resize_w; $resize_w = $resize_h; $resize_h = $resize_w_; } printf("resize with blur value %s\n", $self->blur); $status = $image->Resize( geometry => sprintf("%sx%s>", $resize_w, $resize_h), filter => sprintf("%s", $self->filter), blur => $self->blur ); warn "$status" if $status ; return 0 if $status; $status = $image->Set(Gravity=>"Center"); warn "$status" if $status ; # exif from original image my $orientation = $self->current_image->exif_metadata->{Orientation}; # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW if( $orientation =~ m/Rotate (\d+)/ ){ printf( "Rotate %s\n", $1 ); $image->Rotate( degrees=>$1 ); } printf("resize with quality value %s\n", $self->quality); $status = $image->Set(quality=>$self->quality); warn "$status" if $status ; $status = $image->Set(interlace=>$self->interlace); warn "$status" if $status ; $image->Write( sprintf( "%s:%s", $self->type, $self->current_image->site_resized_file, ) ); warn "$status" if $status ; return 0 if $status; undef $image; $rval = 0 if $status; return $rval; } sub CreateThumbnail { my ( $self ) = @_; #return 1 if( -e $self->current_image->site_thumb_file ); my $rval = 1; my $image = new Image::Magick; my $status = $image->ReadImage( $self->current_image->site_resized_file ); warn "$status" if $status ; $status = $image->Resize( geometry => sprintf( "%sx%s>", $self->thumb_size, $self->thumb_size ), ); warn "$status" if $status ; $status = $image->Set(Gravity=>"Center"); warn "$status" if $status ; $status = $image->Set(quality=>$self->th_quality); warn "$status" if $status ; $status = $image->Strip(); warn "$status" if $status ; $image->Write( sprintf( "%s:%s", $self->type, $self->current_image->site_thumb_file, ) ); undef $image; $rval = 0 if $status; return $rval; } sub _select_exif_data { my ( $self, $exif ) = @_; return { map { $_ => $exif->{$_}, } qw/ CreateDate ImageWidth ImageHeight Orientation DateTimeOriginal ISO ExposureTime ApertureValue FocalLength Lens Exposure Make Model / }; } sub Store { my ( $self ) = @_; my $data = $self->get_storable( [ qw/ images thumb_size preview_ratio type filter blur quality wx_quality th_quality prefix author count resize_w resize_h hd_filter hd_blur hd_quality hd_w hd_h hd_interlace new_files storable_file wx_thumb_size current_image exif_metadata wx_thumb_dir site_resized_dir site_thumb_dir userdata_dir progress_msg default_photo_name default_name_prefix upload_high upload_hd remove_uploaded_from_selection auto_rotate interlace create_resized use_exif_preview image_sums sums version imagelist_version watermark_activate watermark_activate_pwg_high watermark_text watermark_text_size watermark_position watermark_y watermark_x watermark_color reupload_action_files reupload_action_properties reupload_action_properties_m / ] ); eval { store $data, $self->storable_file; }; if($@){ print $@, "\n"; } } sub UploadSelection { my ( $self ) = @_; my $viewer_callback = $self->UploadImagesViewerCallback ; $self->image_selection([]) if !defined $self->image_selection; $self->upload_rejects( [] ); $self->count( 1 ); $self->upload_uploaded_count(0); $self->upload_rejected_count(0); $self->upload_begin_time(time); $self->upload_selection_count(scalar @{$self->image_selection}); # for re-upload management $self->upload_image_sums( [ map { $self->GetImage($_)->file_sum } @{$self->image_selection} ] ); # check if already exist on server my $uploaded = $self->pwg->IsAlreadyUploaded($self->upload_image_sums); my @already_uploaded = grep { $_ } values %$uploaded ; $self->ReuploadCallback->() if ( scalar @already_uploaded and !$self->reupload_not_ask ); foreach(@{$self->image_selection}) { # current image object $self->current_image( $self->GetImage($_) ); # prepare resized, high, thumbnail # if not already uploaded $self->_set_site_resized_file(); $self-> _set_site_high_file (); # photo metadata $self->_prepare_upload_properties(); $self->_upload_selection_prepare() if (!$uploaded->{$self->current_image->file_sum} or $self->reupload_action_files); # transfert resized, high, thumbnail to site my $status = $self->_upload_selection_transfert(); # log operations $self->_upload_selection_log($status); $self->count( 1+$self->count ); } if($self->remove_uploaded_from_selection){ $self->_remove_image_list($self->uploaded_images); $viewer_callback->(); } $self->_upload_selection_final_log(); } sub _upload_selection_prepare { my ( $self ) = @_; $self->progress_thumbnail_refresh->(); # PREPARE $self->_set_upload_msg(gettext("Preparing resized image for")); $self->_upload_progress(); if( $self->create_resized ){ $self->_create_site_resized_file(); $self->_set_upload_msg(gettext("Resized image done for")); $self->_upload_progress(); } # the original is at the right size, no need to create a resize else { $self->current_image->site_resized_file( $self->current_image->file, ); } my $decode = { 'No' => 0, 'Yes, use HD resized of the original photo' => 'HD', 'Yes, use a copy of the original photo' => 'ORIGINAL', }; printf("upload HD %s\n", $self->upload_hd); $self->upload_high( $decode->{$self->upload_hd} ); # if upload high, rotate a copy of original file if($self->upload_high){ $self->CreateHigh(); $self->_set_upload_msg(gettext("HD image done for")); $self->_upload_progress(); } eval { $self->CreateThumbnail(); }; $self->_set_upload_msg(gettext("Thumbnail image done for")); $self->_upload_progress(); } sub _upload_progress { my ( $self, $value ) = @_; eval { $self->progress_msg_refresh->( $self->upload_msg ); # set current image thumbnail # update upload progress dialog #$self->progressbar_refresh->($value); }; # user cancelled : dialog box is destroyed croak gettext("Upload cancelled"), " .", $@ if $@ ; } sub _set_upload_msg { my ( $self, $msg, $errmsg ) = @_; $self->upload_msg( sprintf( "%s : %s - %s\n\n%s %s %s %s\n%s", $msg, $self->upload_file, $self->upload_name, gettext("Photo"), $self->count, gettext("on"), $self->upload_selection_count, $errmsg ) ); } sub _upload_selection_transfert { my ( $self ) = @_; $self->_set_upload_msg(gettext("Uploading")); $self->_upload_progress(0); # UPLOAD my ( $status, $status_msg, $content ) = $self->pwg->UploadImage( { yield=>$self->YieldCallback, bar=>$self->progressbar_refresh, msg=>$self->progress_msg_refresh, msg_details=>$self->progress_msg_details_refresh, resized_msg=>gettext("Uploading resized"), thumbnail_msg=>gettext("Uploading thumbnail"), highdef_msg=>gettext("Uploading high definition"), checksum_msg=>gettext("Checksum for"), original_sum=>$self->current_image->file_sum, } ); my $ok = 0; # HTTP REQUEST OK if ( $status ){ # PIWIGO RESULT ( HTTP may be ok while Piwigo is not ) $ok = 'fail' eq $content->{stat} ? 0 : 1; } else{ Wx::LogMessage( "%s %s : %s", gettext("Communication error with"), $self->pwg->site_url, $status_msg, ); } $self->upload_last_error( $status_msg ); $self->upload_error_content( $content ); $ok; } sub _upload_selection_log { my ( $self, $ok ) = @_; if($ok){ $self->_set_upload_msg(gettext("Uploaded")); $self->_upload_progress(0); push @{$self->uploaded_images}, $_; $self->upload_uploaded_count( 1+$self->upload_uploaded_count ); } else { $self->_set_upload_msg(gettext("An error has occured"), Dumper($self->upload_error_content)); $self->upload_rejected_count( 1+$self->upload_rejected_count ); } } sub _upload_selection_final_log { my ( $self ) = @_; $self->upload_end_time(time); $self->upload_duration( $self->upload_end_time - $self->upload_begin_time ); $self->progress_endinfo_refresh->( sprintf( "%s : %s\n\n%s : %s\n\n%s : %s\n\n\n%s : %s %s", gettext("images processed"), $self->count - 1, gettext("images uploaded"), $self->upload_uploaded_count, gettext("images in errors and not uploaded"), $self->upload_rejected_count, gettext("Duration"), $self->upload_duration, gettext("seconds"), ) ); } sub _set_site_resized_file { my ( $self ) = @_; my ( $vol, $dir, $file ) = File::Spec->splitpath( $self->current_image->file ); $self->upload_file( $file ); $self->upload_name( $self->current_image->site_name ); my $filename = $self->current_image->file_sum ; # lately defined to make sure we have the last global properties ( resize_w, resize_h ) $self->current_image->site_resized_file( File::Spec->catfile( $self->site_resized_dir, sprintf( "%s_%sx%s.%s", $filename, $self->resize_w, $self->resize_h, $self->type, ) ) ); } sub _create_site_resized_file { my ( $self ) = @_; eval { if(!$self->CreateResized()){ $self->__create_resized_fallback(); }; $self->_set_exif_tag( $self->current_image->site_resized_file, 'Orientation', 'Horizontal (normal)', ) if $self->auto_rotate; $self->CreateWatermark( $self->watermark_text, $self->watermark_text_size, $self->watermark_position, $self->watermark_x, $self->watermark_y, $self->watermark_color, $self->current_image->site_resized_file ) if $self->watermark_activate; } } sub _create_resized_fallback { my ( $self ) = @_; # use wx builtin rescale if IM fails printf("CreateResized failed %s. Use ResizeCallback\n", $@); # use method provided by the caller # source, target, type, ratio, width, $height $self->ResizeCallback->( $self->current_image->file, $self->current_image->site_resized_file, $self->type, undef, $self->resize_w, $self->resize_h, $self->quality, ); $self->RotateImage( $self->current_image->site_resized_file, ) if $self->auto_rotate; } # if we need to rotate sub CreateHigh { my ( $self ) = @_; printf("CreateHigh %s\n", $self->upload_high); my $bModifyOriginal; my $bRotate; my $bAddWatermark; my $bResize; my $orientation = $self->current_image->exif_metadata->{Orientation}; my $degrees; # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW if( $self->auto_rotate and $orientation =~ m/Rotate (\d+)/ ){ $bModifyOriginal = 1; $bRotate = 1; $degrees = $1; } if( $self->watermark_activate_pwg_high ){ $bModifyOriginal = 1; $bAddWatermark = 1; } # HD resize if('HD' eq $self->upload_high){ $bModifyOriginal = 1; $bResize = 1; } if($bModifyOriginal){ my $image = Image::Magick->new(); # we read original my $status = $image->Read( $self->current_image->file ); warn "$status ", $self->current_image->file, "\n" if $status ; return 0 if $status; if($bResize){ $status = $image->Resize( geometry => sprintf("%sx%s>", $self->hd_w, $self->hd_h), filter => sprintf("%s", $self->hd_filter), blur => $self->hd_blur ); warn "$status" if $status ; return 0 if $status; } printf("resize with quality value %s\n", $self->quality); $status = $image->Set(quality=>$self->quality); warn "$status" if $status ; $status = $image->Set(interlace=>$self->interlace); warn "$status" if $status ; if($bRotate){ $image->Rotate( degrees=>$degrees ); } $image->Write( $self->current_image->site_high_file ); warn "$status ", $self->current_image->site_high_file, "\n" if $status ; return 0 if $status; undef $image; if($bAddWatermark){ my $file_out = $self->current_image->site_high_file; $self->CreateWatermark( $self->watermark_text, $self->watermark_text_size, $self->watermark_position, $self->watermark_x, $self->watermark_y, $self->watermark_color, $file_out ); } $self->_set_exif_tag( $self->current_image->site_high_file, 'Orientation', 'Horizontal (normal)', ); # Now all images that need to be rotated are done. Update exif $self->current_image->exif_metadata->{Orientation} = 'Horizontal (normal)'; } else{ # high file is the original file $self->current_image->site_high_file( $self->current_image->file ); } return 1; } # file name for original copy sub _set_site_high_file { my ( $self ) = @_; my ( $vol, $dir, $file ) = File::Spec->splitpath( $self->current_image->file ); my ( $filename, $ext ) = split /\./, $file ; # high_file is a resized of original $self->current_image->site_high_file( File::Spec->catfile( $self->site_resized_dir, sprintf( "%s_high.%s", $filename, $self->type, ) ) ); } sub CreateWatermark { my ( $self, $text, $text_size, $position, $x, $y, $color, $file_out ) = @_; my $rval = 1 ; my $gravity = $self->gravity->{$position}; my $fill = $self->rgbcolor->{$color}; # debug printf("Create watermark %s\n", $file_out); my $image = new Image::Magick; my $status = $image->ReadImage( $file_out ); my $ratio = $image->Get('height')/($self->resize_h||$image->Get('height')); $ratio||=1; $text ||="Your watermark"; $image->Annotate( pointsize => $text_size*$ratio, fill => $fill, x => $x*$ratio, y => $y*$ratio, text => $text, gravity => $gravity, ); $image->Write( sprintf( "%s:%s", $self->type, $file_out, ) ); } sub _prepare_upload_properties { my ( $self ) = @_; $self->pwg->reupload_action_files( $self->reupload_action_files||1 ); $self->pwg->reupload_action_properties( $self->reupload_action_properties||2 ); $self->pwg->reupload_action_properties_m( $self->reupload_action_properties_m||1 ); $self->pwg->upload_high( $self->upload_high ); $self->pwg->site_high_file( $self->current_image->site_high_file ); $self->pwg->site_resized_file( $self->current_image->site_resized_file ); $self->pwg->site_thumb_file( $self->current_image->site_thumb_file ); $self->pwg->site_author( $self->current_image->site_author ); $self->pwg->site_comment( $self->current_image->site_comment ); $self->pwg->site_image_name( $self->current_image->site_name ); $self->pwg->site_img_date_creation( substr($self->current_image->create_date, 0, 10) ); $self->current_image->site_categories( $self->categories ); $self->pwg->categories( sprintf( "%s", join(';', @{$self->categories}) ) ); $self->pwg->site_tags( join(',', @{$self->current_image->site_tags}) ); } # read Orientation exif tag from original image # apply rotation to $file image sub RotateImage { my ( $self, $file ) = @_; # exif from original image my $orientation = $self->current_image->exif_metadata->{Orientation}; # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW if( $orientation =~ m/Rotate (\d+)/ ){ printf( "Rotate %s\n", $1 ); my $image = Image::Magick->new(); # read resized file my $status = $image->Read( $file ); warn "$status ", $file, "\n" if $status ; return 0 if $status; $image->Rotate( degrees=>$1 ); # write resized file $image->Write( $file ); warn "$status ", $file, "\n" if $status ; return 0 if $status; undef $image; } return 1; } sub GetImage { my ( $self, $indx ) = @_; my $sum = $self->sums->[$indx]; $self->image_sums->{$sum}; } sub DeleteImage { my ( $self, $indx ) = @_; my $sum = $self->sums->[$indx]; delete $self->image_sums->{$sum}; } 1;