source: extensions/pLoader/trunk/src/Uploader/ImageList.pm @ 5155

Last change on this file since 5155 was 5155, checked in by ronosman, 14 years ago

Feature 1449 added : when adding photos, automatically hide status dialog box at the end of processing if no error to report.

  • Property svn:eol-style set to LF
File size: 38.6 KB
Line 
1# +-----------------------------------------------------------------------+
2# | pLoader - a Perl photo uploader for Piwigo                            |
3# +-----------------------------------------------------------------------+
4# | Copyright(C) 2008-2010 Piwigo Team                  http://piwigo.org |
5# +-----------------------------------------------------------------------+
6# | This program is free software; you can redistribute it and/or modify  |
7# | it under the terms of the GNU General Public License as published by  |
8# | the Free Software Foundation                                          |
9# |                                                                       |
10# | This program is distributed in the hope that it will be useful, but   |
11# | WITHOUT ANY WARRANTY; without even the implied warranty of            |
12# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
13# | General Public License for more details.                              |
14# |                                                                       |
15# | You should have received a copy of the GNU General Public License     |
16# | along with this program; if not, write to the Free Software           |
17# | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
18# | USA.                                                                  |
19# +-----------------------------------------------------------------------+
20package Uploader::ImageList;
21use strict;
22use Carp;
23use base qw/Uploader::Object/;
24use Image::ExifTool qw(:Public);
25use Image::Magick;
26use File::Spec;
27use Uploader::Image;
28use Data::Dumper;
29use Storable;
30use Digest::MD5::File qw/file_md5_hex md5_hex/;
31use Wx::Locale qw/:default/;
32use Wx;
33
34# this class implements a collection of image files with associated data
35$|=1;
36__PACKAGE__->mk_accessors( 
37    qw/
38                thumb_size
39                preview_ratio
40                categories
41                type
42                filter
43                blur
44                quality
45                resize_w
46                resize_h
47                hd_filter
48                hd_blur
49                hd_quality
50                hd_w
51                hd_h
52                hd_interlace
53                prefix
54                author
55                count
56                new_files
57                storable_file
58                wx_thumb_size
59                current_image
60                images
61                image_selection
62                exif_metadata
63                wx_thumb_imglist
64                wx_thumb_dir
65                site_resized_dir
66                site_thumb_dir
67                userdata_dir
68                progress_msg
69                last_error_msg
70                default_photo_name
71                default_photo_name_method
72                default_name_prefix
73                SetNewFilesViewerRefreshCallback
74                SetNewFilesProgressCallback
75                SetNewFilesDisplayEndInfoCallback
76                YieldCallback
77                UploadImagesViewerCallback
78                progress_thumbnail_refresh
79                progress_msg_details_refresh
80                progress_msg_refresh
81                progressbar_refresh
82                progress_endinfo_refresh
83                ResizeCallback
84                upload_rejects
85                pwg
86                upload_high
87                upload_hd
88                remove_uploaded_from_selection
89                wx_quality
90                th_quality
91                auto_rotate
92                interlace
93                create_resized
94                use_exif_preview
95                image_sums
96                upload_image_sums
97                sums
98                version
99                imagelist_version
100                uploaded_images
101                watermark_activate
102                watermark_activate_pwg_high
103                watermark_text
104                watermark_text_size
105                watermark_position
106                watermark_y
107                watermark_x
108                watermark_color
109                gravity
110                rgbcolor
111                upload_msg
112                upload_selection_count
113                upload_uploaded_count
114                upload_rejected_count
115                upload_last_error
116                upload_error_content
117                upload_begin_time
118                upload_end_time
119                upload_duration
120                upload_file
121                upload_name
122                ReuploadCallback
123                reupload_action_files
124                reupload_action_properties
125                reupload_action_properties_m
126                reupload_not_ask
127                display_mode
128                stop_processing
129                image_selection_tags
130                image_selection_privacy_level
131                image_selection_name
132                image_selection_comment
133                image_selection_author
134                image_selection_create_date
135     /
136);
137
138
139sub Init {
140    my ( $self ) = @_;
141   
142    $self->image_selection([]) if !defined $self->image_selection;
143    $self->uploaded_images([]);
144    $self->gravity(
145        { 
146            'Top'          => 'North',
147            'Left'         => 'West',
148            'Right'        => 'East',
149            'Bottom'       => 'South',
150            'Top left'     => 'NorthWest',
151            'Top right'    => 'NorthEast',
152            'Bottom left'  => 'SouthWest',
153            'Bottom right' => 'SouthEast',
154            'Center'       => 'Center',
155       }   
156    );   
157
158    $self->rgbcolor(
159        {
160            "White" => '#FFFFFF',
161            "Black" => '#000000',
162        }   
163    );
164   
165    $self->image_selection_tags(
166        []
167    ) unless defined $self->image_selection_tags;
168}
169
170sub _set_exif_tag {
171    my ( $self, $file, $tag, $newValue ) = @_;   
172
173  my $options = {};
174  # Create a new Image::ExifTool object
175  my $exifTool = new Image::ExifTool;
176
177  # Extract meta information from an image
178  $exifTool->ExtractInfo($file, $options);
179
180  # Set a new value for a tag
181  $exifTool->SetNewValue($tag, $newValue);
182
183  # Write new meta information to a file
184  $exifTool->WriteInfo($file);
185
186}
187
188
189sub _set_current_image_filepaths {
190    my ( $self ) = @_;
191
192    my $filename = sprintf(
193        "%s.%s",
194        $self->current_image->file_sum,
195        $self->type,
196    );
197
198
199    $self->current_image->wx_thumb_file( 
200        File::Spec->catfile(
201            $self->wx_thumb_dir,
202            $filename
203        )
204    );
205
206    $self->current_image->site_thumb_file( 
207        sprintf("%s.%s",
208            File::Spec->catfile(
209                $self->site_thumb_dir,
210                'thumbnail'
211            ),
212            $self->type
213        )
214    );
215
216}
217
218
219sub SetCurrentImage {
220    my ( $self, $indx ) = @_;   
221
222    $self->current_image(
223        $indx != -1 ? $self->GetImage($indx) : Uploader::Image->new()
224    );
225}
226
227
228sub SetNewFiles {
229    my ( $self, $files ) = @_;
230
231    $self->stop_processing(0);
232
233    $self->new_files( $files );
234
235    # if some files have been previously selected
236    my $i = scalar @{$self->sums};
237    #printf("SetNewFiles %s\n", $i);
238    my $count = 0;
239    $self->count($count);
240    my $errors = 0;
241
242    foreach my $file ( @{$files} ) {
243        my $info = $self->_read_exif_metatdata($file->{ANSIPathName});
244           my $is_new_image = $self->_add_image($file, $info, $i);   
245        $self->SetCurrentImage($i);
246        $self->_set_current_image_filepaths();
247
248        if($is_new_image){
249            #my $use_wx_resize = $self->_create_gui_preview($info);
250            $self->_create_gui_thumbnail();
251
252            # ok
253            if(!$@){
254                $self->progress_msg(gettext("Selection thumbnail created for %s"));
255            }
256            else {
257                $self->progress_msg("An error has occured when processing %s\n$@");
258                # remove from list
259                splice @{$self->sums}, $i, 1;
260                $errors++;
261            }
262       
263            $self->SetNewFilesProgressCallback->();
264        }
265        $i++;
266        $count++;
267        $self->count($count);
268        $self->SetNewFilesViewerRefreshCallback->();
269        last if $self->stop_processing;
270    }
271
272    $self->SetNewFilesDisplayEndInfoCallback->(
273        sprintf(
274            "%s : %s\n\n%s : %s",
275            gettext("photos added to the selection"),
276            $self->count,
277            gettext("errors"),
278            $errors,
279           
280        ),
281        $errors
282    );
283   
284    $self->Store;
285   
286}
287
288sub _read_exif_metatdata {
289    my ( $self, $file ) = @_;
290   
291    # read exif metadata
292    my $info;
293    eval {
294        $info = ImageInfo( $file );
295    };
296    $info = {} if($@);
297   
298    $info;
299}
300
301# key is file path
302sub _add_image {
303    my ( $self, $file, $info, $i ) = @_;   
304
305    my $is_new_image;
306
307    # for legacy imagelist that do not have image_sums property
308    $self->image_sums(
309        {}
310    ) if !$self->image_sums;
311
312    my $sum = file_md5_hex($file->{ANSIPathName});
313
314    my $image;
315    if ( !exists $self->image_sums->{$sum} ){
316        #print "_add_image ", Dumper $file, "\n";
317        # append to image list
318        $image = Uploader::Image->new(
319        {
320                file              => $file->{ANSIPathName},
321                file_sum          => $sum,
322                site_name         => $self->_default_photo_name($file->{PathName}, $info, $i),
323                site_author       => $self->author,
324                exif_metadata     => $self->_select_exif_data($info),
325                add_rank          => $i,
326                site_categories   => [],
327                site_tags         => [],
328                site_high_file    => $file->{ANSIPathName},
329            }
330        );
331
332        $self->image_sums->{$sum} = $image ;
333        $is_new_image = 1;
334    } else {
335        $image = $self->image_sums->{$sum};
336    }
337
338       
339    $self->sums->[$i] = $sum ;
340
341    $is_new_image;
342}
343
344
345sub _default_photo_name {
346    my ( $self, $file, $info, $i ) = @_;
347   
348   
349    my $name;
350    my $create_date = $info->{CreateDate};
351    my $ext;
352    my ( $vol, $path, $filename ) = File::Spec->splitpath($file);
353    ( $filename, $ext ) = split /\.\w+$/, $filename;
354   
355    my ( $yyyy, $mm, $dd, $hh, $mi, $ss ) = split /[:\s]/, $create_date ;
356 
357    my $chrono = join('', $yyyy, $mm, $dd);
358    if('Prefix' eq $self->default_photo_name){
359        $name = $self->default_name_prefix
360    }
361    elsif('File name' eq $self->default_photo_name){
362        $name = $filename
363    }
364    elsif('File path and name' eq $self->default_photo_name){
365        $name = sprintf(
366            "%s", 
367            File::Spec->catfile($path, $filename), 
368        )       
369    }   
370    elsif('Prefix + rank number' eq $self->default_photo_name){
371        $name = sprintf(
372            "%s%s", 
373            $self->default_name_prefix, 
374            1+$i,
375        )       
376    }   
377    elsif('Rank number + prefix' eq $self->default_photo_name){
378        $name = sprintf(
379            "%s%s", 
380            1+$i,
381            $self->default_name_prefix, 
382        )       
383    }   
384    elsif('Prefix + create date chrono' eq $self->default_photo_name){
385        $name = sprintf(
386            "%s%s", 
387            $self->default_name_prefix, 
388            $chrono,
389        )       
390    }   
391    elsif('Create date chrono + prefix' eq $self->default_photo_name){
392        $name = sprintf(
393            "%s%s", 
394            $chrono,
395            $self->default_name_prefix, 
396        )       
397    }
398
399    $name;
400}
401
402
403sub _create_gui_thumbnail {
404    my ( $self ) = @_;
405
406     eval {
407        if(!$self->CreateGUIThumbnail())
408        {
409            $self->ResizeCallback->(
410                $self->current_image->file,
411                $self->current_image->wx_thumb_file,
412                $self->type,
413                $self->wx_thumb_size,
414                $self->wx_thumb_size,
415                $self->wx_quality,
416            );
417           
418        }
419     };
420}
421
422sub RemoveImageSelection {
423    my ( $self ) = @_;
424   
425    return if (! scalar @{$self->sums} );
426    return if (! defined $self->image_selection );
427   
428    $self->_remove_image_list($self->image_selection);
429    # clear image selection
430    $self->image_selection([]);
431}
432
433sub _remove_image_list {
434    my ( $self, $list ) = @_;
435    # the list is sorted, ascendant
436    # we reverse it to have
437    # higher first, and keep same indexes during remove
438    @$list = reverse @$list;     
439    map {
440        $self->DeleteImage($_);
441        splice @{$self->sums}, $_, 1 ;
442        $self->wx_thumb_imglist->Remove($_);
443        shift @$list;
444    }
445    @$list;
446}
447
448
449# used for display in GUI. has to fit a square box ( wxImageList )
450sub CreateGUIThumbnail {
451    my ( $self ) = @_;
452
453    my $rval = 0;
454    my $image = new Image::Magick;
455
456    my $size = $self->wx_thumb_size||100;
457
458    my $status = $image->Set(size=>sprintf("%sx%s", 2*$size, 2*$size));
459    warn "$status" if $status ;
460
461    $status = $image->ReadImage(
462        $self->current_image->file
463    );
464    warn "$status" if $status;
465    return $rval if $status;
466
467    $self->current_image->width(
468        $image->Get('width')
469    );
470    $self->current_image->height(
471        $image->Get('height')
472    );
473
474
475    # maximize size and keep aspect ratio
476    $status = $image->Thumbnail(
477        geometry=>sprintf("%s%s>", $size*$size, '@')
478    );
479    # to get adjusted to a square box
480    #$status = $image->Thumbnail(
481    #    geometry=>sprintf("%sx%s%s", $size, $size, '^')
482    #);
483    warn "$status" if $status;
484    return $rval if $status;
485
486#    causes strange behaviour with i18n -> yellow borders when local is other than EN
487#    $status = $image->Set(background=>"white");
488#    warn "$status" if $status ;
489
490    $status = $image->Set(Gravity=>"Center");
491    warn "$status" if $status ;
492
493    $image->Extent(
494        geometry=>sprintf("%sx%s", $size, $size),
495        gravity=>'center',
496    );
497   
498    $image->Set(
499        quality=>$self->wx_quality||90
500    );
501
502    $status = $image->Strip();
503    warn "$status" if $status ;
504
505    # exif from original image
506    my $orientation = $self->current_image->exif_metadata->{Orientation};
507   
508    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
509    if( $orientation =~ m/Rotate (\d+)/ ){
510        printf(
511            "Rotate %s\n",
512            $1
513        );
514   
515        $image->Rotate( degrees=>$1 ) if $self->auto_rotate;   
516    }
517   
518
519    $image->Write(
520        sprintf(
521            "%s:%s",
522            $self->type,
523            $self->current_image->wx_thumb_file,
524        )
525    );
526
527    undef $image;
528   
529    $rval = 1;
530   
531    return $rval;
532}
533
534
535
536
537sub CreateResized {
538    my ( $self ) = @_;
539   
540    my $rval = 1 ;
541
542
543    my $image = new Image::Magick;
544
545    my $status = $image->ReadImage(
546        $self->current_image->file
547    );
548    warn "$status" if $status ;
549    return 0 if $status;
550
551    my $w = $image->Get('width');
552    my $h = $image->Get('height');
553
554    $status = $image->Set(Gravity=>"Center");
555    warn "$status" if $status ;
556
557    # exif from original image
558    my $orientation = $self->current_image->exif_metadata->{Orientation};
559   
560    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
561    if( $orientation =~ m/Rotate (\d+)/ ){
562        printf(
563            "Rotate %s\n",
564            $1
565        );
566   
567        $image->Rotate( degrees=>$1 ) if $self->auto_rotate;   
568    }
569
570
571    #printf("resize with blur value %s\n", $self->blur);
572    $status = $image->Resize(
573        geometry => sprintf("%sx%s>", $self->resize_w, $self->resize_h), 
574        filter => sprintf("%s", $self->filter), 
575        blur => $self->blur
576    );
577    warn "$status" if $status ;
578    return 0 if $status;
579
580    #printf("resize with quality value %s\n", $self->quality);
581    $status = $image->Set(quality=>$self->quality);
582    warn "$status" if $status ;
583
584    $status = $image->Set(interlace=>$self->interlace);
585    warn "$status" if $status ;
586
587    $image->Write(
588        sprintf(
589            "%s:%s",
590            $self->type,
591            $self->current_image->site_resized_file,
592        )
593    );
594    warn "$status" if $status ;
595    return 0 if $status;
596   
597    undef $image;
598
599   
600    $rval = 0 if $status;
601
602    return $rval;
603}
604
605sub CreateThumbnail {
606    my ( $self ) = @_;
607   
608    #return 1 if( -e $self->current_image->site_thumb_file );
609   
610    my $rval = 1;
611
612    my $image = new Image::Magick;
613
614    my $status = $image->ReadImage(
615        $self->current_image->site_resized_file
616    );
617    warn "$status" if $status ;
618
619   
620    $status = $image->Resize(
621        geometry => sprintf(
622                                "%sx%s>", 
623                                $self->thumb_size, 
624                                $self->thumb_size
625                           ),
626    );
627    warn "$status" if $status ;
628
629    $status = $image->Set(Gravity=>"Center");
630    warn "$status" if $status ;
631
632    $status = $image->Set(quality=>$self->th_quality);
633    warn "$status" if $status ;
634
635    $status = $image->Strip();
636    warn "$status" if $status ;
637
638
639    $image->Write(
640        sprintf(
641            "%s:%s",
642            $self->type,
643            $self->current_image->site_thumb_file,
644        )
645    );
646   
647    undef $image;
648
649
650    $rval = 0 if $status;
651
652    return $rval;
653}
654
655
656
657sub _select_exif_data {
658    my ( $self, $exif ) = @_;
659
660    return {
661        map {
662            $_ => $exif->{$_},
663        }
664        qw/
665            CreateDate
666            ImageWidth
667            ImageHeight
668            Orientation
669            DateTimeOriginal
670            ISO
671            ExposureTime
672            ApertureValue
673            FocalLength
674            Lens
675            Exposure
676            Make
677            Model
678        /
679    };   
680}
681
682sub Store {
683    my ( $self ) = @_;
684   
685    my $data = $self->get_storable(
686        [ 
687            qw/
688                images
689                thumb_size
690                preview_ratio
691                type
692                filter
693                blur
694                quality
695                wx_quality
696                th_quality
697                prefix
698                author
699                count
700                resize_w
701                resize_h
702                hd_filter
703                hd_blur
704                hd_quality
705                hd_w
706                hd_h
707                hd_interlace
708                new_files
709                storable_file
710                wx_thumb_size
711                current_image
712                exif_metadata
713                wx_thumb_dir
714                site_resized_dir
715                site_thumb_dir
716                userdata_dir
717                progress_msg
718                default_photo_name
719                default_name_prefix
720                upload_high
721                upload_hd
722                remove_uploaded_from_selection
723                auto_rotate
724                interlace
725                create_resized
726                use_exif_preview
727                image_sums
728                sums
729                version
730                imagelist_version
731                watermark_activate
732                watermark_activate_pwg_high
733                watermark_text
734                watermark_text_size
735                watermark_position
736                watermark_y
737                watermark_x
738                watermark_color
739                reupload_action_files
740                reupload_action_properties
741                reupload_action_properties_m
742                display_mode
743                image_selection_tags
744            /
745        ] 
746   
747    );
748    eval {
749        store $data, $self->storable_file;
750    };
751    if($@){
752        print $@, "\n";   
753    }
754}
755
756
757
758sub UploadSelection {
759    my ( $self ) = @_;
760
761    $self->stop_processing(0);
762
763    my $viewer_callback = $self->UploadImagesViewerCallback ;
764
765    $self->image_selection([]) if !defined $self->image_selection;
766    $self->upload_rejects(
767        []
768    );
769
770    $self->count(
771        1
772    );
773
774    $self->upload_uploaded_count(0);
775    $self->upload_rejected_count(0);
776    $self->upload_begin_time(time);
777    $self->upload_selection_count(scalar @{$self->image_selection});
778    # for re-upload management
779    $self->upload_image_sums( [
780            map { $self->GetImage($_)->file_sum }
781            @{$self->image_selection}
782        ] 
783    );
784
785    # check if already exist on server
786    my $uploaded = $self->pwg->IsAlreadyUploaded($self->upload_image_sums);
787    my @already_uploaded = grep { $_ } values %$uploaded ; 
788    $self->ReuploadCallback->() if ( scalar @already_uploaded and !$self->reupload_not_ask );
789
790   
791    foreach(@{$self->image_selection}) {
792    # current image object       
793        $self->current_image(
794            $self->GetImage($_)
795        ); 
796        # prepare resized, high, thumbnail
797        # if not already uploaded
798        $self->_set_site_resized_file();
799        $self-> _set_site_high_file ();
800        # photo metadata
801        $self->_upload_selection_prepare() if (!$uploaded->{$self->current_image->file_sum} or $self->reupload_action_files);
802        $self->_prepare_upload_properties();       
803
804        # transfert resized, high, thumbnail to site
805        my $status = $self->_upload_selection_transfert();
806        # log operations
807        $self->_upload_selection_log($status);
808        $self->count(
809            1+$self->count
810        );
811        # remove thumbnail, resized
812        # to make sure everything is clean
813        # keep site_high_file because it can be the original !!!
814        $self->_remove_resized_from_cache;
815
816        last if $self->stop_processing;
817    }
818
819    $self->stop_processing(0);
820
821    if($self->remove_uploaded_from_selection){
822        $self->_remove_image_list($self->uploaded_images);
823        # clear thumbnail imagelistctrl
824        $viewer_callback->();
825    }
826
827    $self->_upload_selection_final_log();
828
829}
830
831
832sub _remove_resized_from_cache {
833    my ( $self ) = @_;
834
835    unlink $self->current_image->site_thumb_file if -e $self->current_image->site_thumb_file;
836
837    map {
838        my $file = File::Spec->catfile(
839            $self->site_resized_dir,
840            sprintf(
841                "%s.%s",
842                 $_,
843                $self->type,
844            )
845        );
846        unlink $file if -e $file;
847    } qw /resized high/;
848
849
850}
851
852sub _upload_selection_prepare {
853    my ( $self ) = @_;
854
855    $self->progress_thumbnail_refresh->();
856    # PREPARE
857    $self->_set_upload_msg(gettext("Preparing resized image for"));
858    $self->_upload_progress();
859    #printf("resized %s\n", $self->create_resized);
860    if( $self->create_resized ){
861        $self->_create_site_resized_file();
862        $self->_set_upload_msg(gettext("Resized image done for"));
863        $self->_upload_progress();
864    }
865    # the original is at the right size, no need to create a resize
866    else {
867        #printf("original no resized %s\n", $self->create_resized);
868        $self->current_image->site_resized_file(
869            $self->current_image->file,
870        );
871    }
872
873    my $decode = {
874        'No' => 0,
875        'Yes, use HD resized of the original photo' => 'HD',
876        'Yes, use a copy of the original photo' => 'ORIGINAL',
877    };   
878    #printf("upload HD %s\n", $self->upload_hd);
879    $self->upload_high(
880        $decode->{$self->upload_hd}
881    );
882    #printf("upload High %s\n", $self->upload_high);
883   
884    # if upload high, rotate a copy of original file
885    if($self->upload_high){
886        $self->CreateHigh();
887        $self->_set_upload_msg(gettext("HD image done for"));
888        $self->_upload_progress();
889    }
890
891    eval {
892        $self->CreateThumbnail();
893    };
894    $self->_set_upload_msg(gettext("Thumbnail image done for"));
895    $self->_upload_progress();
896
897
898}
899
900sub _upload_progress {
901    my ( $self, $value ) = @_;
902
903    eval {
904        $self->progress_msg_refresh->(
905            $self->upload_msg
906        );
907    };
908    # user cancelled : dialog box is destroyed
909    croak gettext("Upload cancelled"), " .", $@ if $@ ;
910
911
912}
913
914sub _set_upload_msg {
915    my ( $self, $msg, $errmsg ) = @_;
916
917    $self->upload_msg(
918        sprintf(
919            "%s : %s - %s\n\n%s %s %s %s\n%s",
920            $msg,
921            $self->upload_file,
922            $self->upload_name,
923            gettext("Photo"),
924            $self->count,
925            gettext("on"),
926            $self->upload_selection_count,
927            $errmsg
928        )
929    );
930}
931
932sub _upload_selection_transfert {
933    my ( $self ) = @_;
934
935    return if $self->stop_processing;
936
937    $self->_set_upload_msg(gettext("Uploading"));
938    $self->_upload_progress(0);
939
940    # UPLOAD
941    my ( $status, $status_msg, $content ) = $self->pwg->UploadImage(
942        { 
943            yield           => $self->YieldCallback, 
944            bar             => $self->progressbar_refresh, 
945            msg             => $self->progress_msg_refresh,
946            msg_details     => $self->progress_msg_details_refresh,
947            resized_msg     => gettext("Uploading resized"),
948            thumbnail_msg   => gettext("Uploading thumbnail"),
949            highdef_msg     => gettext("Uploading high definition"),
950            checksum_msg    => gettext("Checksum for"),
951            original_sum    => $self->current_image->file_sum,
952            stop_processing => $self->stop_processing,
953        } 
954    );
955    my $ok = 0;
956    # HTTP REQUEST OK
957    if ( $status ){
958        # PIWIGO RESULT ( HTTP may be ok while Piwigo is not )
959        $ok = 'fail' eq $content->{stat} ? 0 : 1;
960    }
961    else{
962        Wx::LogMessage(
963            "%s %s : %s",
964            gettext("Communication error with"),
965            $self->pwg->site_url,
966            $status_msg,
967        );
968    }
969    $self->upload_last_error(
970        $status_msg
971    );
972
973    $self->upload_error_content(
974        $content
975    );
976
977    $ok;
978}
979
980sub _upload_selection_log {
981    my ( $self, $ok ) = @_;
982
983    if($ok){
984        $self->_set_upload_msg(gettext("Uploaded"));
985        $self->_upload_progress(0);
986        push @{$self->uploaded_images}, $_;
987        $self->upload_uploaded_count(
988            1+$self->upload_uploaded_count       
989        );
990    } else {
991        $self->_set_upload_msg(gettext("An error has occured"), Dumper($self->upload_error_content));
992        $self->upload_rejected_count(
993            1+$self->upload_rejected_count
994        );
995    }   
996       
997}
998
999sub _upload_selection_final_log {
1000    my ( $self ) = @_;
1001
1002    $self->upload_end_time(time);
1003    $self->upload_duration(
1004        $self->upload_end_time - $self->upload_begin_time
1005    );
1006
1007    $self->progress_endinfo_refresh->(
1008        sprintf(
1009            "%s : %s\n\n%s : %s\n\n%s : %s\n\n\n%s : %s %s",
1010            gettext("images processed"),
1011            $self->count - 1,
1012            gettext("images uploaded"),
1013            $self->upload_uploaded_count,
1014            gettext("images in errors and not uploaded"),
1015            $self->upload_rejected_count,
1016            gettext("Duration"),
1017            $self->upload_duration,
1018            gettext("seconds"),
1019        )
1020    );
1021}
1022
1023sub _set_site_resized_file {
1024    my ( $self ) = @_;
1025
1026    my ( $vol, $dir, $file ) = File::Spec->splitpath(
1027        $self->current_image->file
1028    );
1029
1030    $self->upload_file(
1031        $file
1032    );
1033       
1034    $self->upload_name(
1035        $self->current_image->site_name
1036    );
1037    my $filename = $self->current_image->file_sum ;
1038
1039    # lately defined to make sure we have the last global properties ( resize_w, resize_h )
1040    $self->current_image->site_resized_file( 
1041        File::Spec->catfile(
1042            $self->site_resized_dir,
1043            sprintf(
1044                "%s.%s",
1045                'resized',
1046                $self->type,
1047            )
1048        )
1049    );
1050    printf("_set_site_resized_file %s\n", $self->current_image->site_resized_file);
1051}
1052
1053sub _create_site_resized_file {
1054    my ( $self ) = @_;
1055
1056    eval {
1057        if(!$self->CreateResized()){
1058            $self->_create_resized_fallback();
1059        };
1060
1061        $self->_set_exif_tag(
1062            $self->current_image->site_resized_file,
1063            'Orientation',
1064            'Horizontal (normal)',
1065        ) if $self->auto_rotate;
1066
1067        $self->CreateWatermark(
1068            $self->watermark_text,
1069            $self->watermark_text_size,
1070            $self->watermark_position,
1071            $self->watermark_x,
1072            $self->watermark_y,
1073            $self->watermark_color,
1074            $self->current_image->site_resized_file
1075        ) if $self->watermark_activate;
1076    }
1077}
1078
1079sub _create_resized_fallback {
1080    my ( $self ) = @_;
1081    # use wx builtin rescale if IM fails
1082    printf("CreateResized failed %s. Use ResizeCallback\n", $@);
1083    # use method provided by the caller
1084    # source, target, type, ratio, width, $height
1085    $self->ResizeCallback->(
1086        $self->current_image->file,
1087        $self->current_image->site_resized_file,
1088        $self->type,
1089        $self->resize_w,
1090        $self->resize_h,
1091        $self->quality,
1092    );
1093               
1094    $self->RotateImage(
1095        $self->current_image->site_resized_file,
1096    ) if $self->auto_rotate;
1097}
1098
1099# if we need to rotate
1100sub CreateHigh {
1101    my ( $self ) = @_;
1102
1103    #printf("CreateHigh %s\n", $self->upload_high);
1104    my $bModifyOriginal;
1105    my $bRotate;
1106    my $bAddWatermark;
1107    my $bResize;
1108    my $orientation = $self->current_image->exif_metadata->{Orientation};
1109    my $degrees;
1110   
1111    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
1112    if( $self->auto_rotate and $orientation =~ m/Rotate (\d+)/ ){
1113        $bModifyOriginal = 1;
1114        $bRotate = 1;
1115        $degrees = $1;
1116    }
1117
1118    if( $self->watermark_activate_pwg_high ){
1119        $bModifyOriginal = 1;
1120        $bAddWatermark = 1;
1121    }
1122   
1123    # HD resize
1124    if('HD' eq $self->upload_high){
1125        $bModifyOriginal = 1;
1126        $bResize = 1;
1127    }
1128
1129    if($bModifyOriginal){
1130
1131        my $image = Image::Magick->new();
1132        # we read original
1133        my $status = $image->Read(
1134            $self->current_image->file
1135        );
1136        warn "$status ", $self->current_image->file, "\n" if $status ;
1137        return 0 if $status;
1138
1139        if($bRotate){
1140            $image->Rotate( degrees=>$degrees );   
1141        }       
1142        $image->Write(
1143            $self->current_image->site_high_file
1144        );
1145        warn "$status ", $self->current_image->site_high_file, "\n" if $status ;
1146        return 0 if $status;
1147
1148        if($bResize){
1149            $status = $image->Resize(
1150                geometry => sprintf("%sx%s>", $self->hd_w, $self->hd_h), 
1151                filter => sprintf("%s", $self->hd_filter), 
1152                blur => $self->hd_blur
1153            );
1154            warn "$status" if $status ;
1155            return 0 if $status;
1156        }
1157       
1158        #printf("resize with quality value %s\n", $self->quality);
1159        $status = $image->Set(quality=>$self->quality);
1160        warn "$status" if $status ;
1161
1162        $status = $image->Set(interlace=>$self->interlace);
1163        warn "$status" if $status ;
1164       
1165       
1166        undef $image;
1167
1168        if($bAddWatermark){
1169          my $file_out = $self->current_image->site_high_file;
1170          $self->CreateWatermark(
1171             $self->watermark_text,
1172                $self->watermark_text_size,
1173                $self->watermark_position,
1174                $self->watermark_x,
1175                $self->watermark_y,
1176                $self->watermark_color,
1177                $file_out
1178            );
1179        }
1180
1181
1182        $self->_set_exif_tag(
1183            $self->current_image->site_high_file,
1184            'Orientation',
1185            'Horizontal (normal)',
1186        );
1187
1188        # Now all images that need to be rotated are done. Update exif
1189        $self->current_image->exif_metadata->{Orientation} = 'Horizontal (normal)';
1190
1191
1192    }
1193    else{
1194        # high file is the original file
1195        $self->current_image->site_high_file(
1196            $self->current_image->file
1197        );
1198        #printf("site high file %s\n", $self->current_image->site_high_file);
1199    }
1200
1201    return 1;
1202}
1203
1204# file name for original copy
1205# we do not need the original file name
1206sub _set_site_high_file {
1207        my ( $self ) = @_;
1208
1209        my ( $vol, $dir, $file ) = File::Spec->splitpath(
1210            $self->current_image->file
1211        );
1212       
1213        $self->current_image->site_original_filename(
1214            $file
1215        );
1216        my ( $filename, $ext ) = split /\./, $file ;
1217   
1218        # high_file is a resized of original
1219        $self->current_image->site_high_file( 
1220            File::Spec->catfile(
1221                $self->site_resized_dir,
1222                sprintf(
1223                    "%s.%s",
1224                     'high',
1225                    $self->type,
1226                )
1227            )
1228        );
1229}
1230
1231
1232
1233sub CreateWatermark {
1234    my ( $self, $text, $text_size, $position, $x, $y, $color, $file_out ) = @_;
1235   
1236    my $rval = 1 ;
1237    my $gravity = $self->gravity->{$position};
1238    my $fill = $self->rgbcolor->{$color};
1239
1240    # debug
1241    #printf("Create watermark %s\n", $file_out);
1242
1243   
1244
1245    my $image = new Image::Magick;
1246   
1247    my $status = $image->ReadImage(
1248        $file_out
1249    );     
1250
1251    my $ratio = $image->Get('height')/($self->resize_h||$image->Get('height'));
1252    $ratio||=1;
1253    $text ||="Your watermark";
1254    $image->Annotate(
1255        pointsize => $text_size*$ratio,
1256        fill => $fill,
1257        x => $x*$ratio,
1258        y => $y*$ratio,
1259        text => $text,
1260        gravity => $gravity,
1261    );
1262                     
1263    $image->Write(
1264        sprintf(
1265            "%s:%s",
1266            $self->type,
1267            $file_out,
1268        )
1269    );
1270}
1271
1272sub _prepare_upload_properties {
1273    my ( $self ) = @_;
1274
1275    # set default values only if not defined
1276    # || operator is not used because 0 is a choice value
1277    # and would replace a valid choice with a default value
1278    $self->reupload_action_files(1) 
1279        unless defined $self->reupload_action_files;
1280
1281    $self->pwg->reupload_action_properties(1)
1282        unless defined $self->pwg->reupload_action_properties;
1283
1284    $self->pwg->reupload_action_properties_m(1)
1285        unless defined $self->pwg->reupload_action_properties_m;
1286
1287    $self->pwg->reupload_action_files(
1288        $self->reupload_action_files
1289    );
1290    $self->pwg->reupload_action_properties(
1291        $self->reupload_action_properties
1292    );
1293
1294    $self->pwg->reupload_action_properties_m(
1295        $self->reupload_action_properties_m
1296    );
1297   
1298    $self->pwg->upload_high(
1299        $self->upload_high
1300    );
1301
1302    $self->pwg->site_high_file(
1303        $self->current_image->site_high_file
1304    );
1305
1306    $self->pwg->site_original_filename(
1307        $self->current_image->site_original_filename
1308    );
1309
1310
1311    $self->pwg->site_resized_file(
1312        $self->current_image->site_resized_file
1313    );
1314
1315    $self->pwg->site_thumb_file(
1316        $self->current_image->site_thumb_file
1317    );
1318
1319    $self->pwg->site_author(
1320        $self->current_image->site_author
1321    );
1322
1323    $self->pwg->site_comment(
1324        $self->current_image->site_comment
1325    );
1326
1327    $self->pwg->site_image_name(
1328        $self->current_image->site_name
1329    );
1330
1331    $self->pwg->site_img_date_creation(
1332        substr($self->current_image->create_date, 0, 10)
1333    );
1334
1335    $self->pwg->privacy_level(
1336        $self->current_image->privacy_level
1337    );
1338   
1339    $self->current_image->site_categories(
1340        $self->categories
1341    );
1342
1343    $self->pwg->categories(
1344        sprintf(
1345            "%s",
1346            join(';', @{$self->categories})
1347        )
1348    );
1349
1350    $self->pwg->site_tags(
1351        join(',', @{$self->current_image->site_tags})
1352    );
1353
1354   
1355}
1356
1357# read Orientation exif tag from original image
1358# apply rotation to $file image
1359sub RotateImage {
1360    my ( $self, $file ) = @_;
1361   
1362    # exif from original image
1363    my $orientation = $self->current_image->exif_metadata->{Orientation};
1364
1365    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
1366    if( $orientation =~ m/Rotate (\d+)/ ){
1367        printf(
1368            "Rotate %s\n",
1369            $1
1370        );
1371
1372        my $image = Image::Magick->new();
1373       
1374        # read resized file
1375        my $status = $image->Read(
1376            $file
1377        );
1378        warn "$status ", $file, "\n" if $status ;
1379        return 0 if $status;
1380   
1381        $image->Rotate( degrees=>$1 );   
1382       
1383        # write resized file
1384        $image->Write(
1385            $file
1386        );
1387        warn "$status ", $file, "\n" if $status ;
1388        return 0 if $status;
1389       
1390        undef $image;
1391   
1392    }   
1393    return 1;
1394}
1395
1396sub GetImage {
1397    my ( $self, $indx ) = @_;
1398   
1399    my $sum = $self->sums->[$indx];
1400
1401    $self->image_sums->{$sum};
1402}
1403
1404sub DeleteImage {
1405    my ( $self, $indx ) = @_;
1406   
1407    my $sum = $self->sums->[$indx];
1408
1409    delete $self->image_sums->{$sum};
1410}
1411
1412sub multi_selection_mode {
1413    my ( $self ) = @_;
1414
1415    scalar @{$self->image_selection} > 1;
1416}
1417
1418
1419sub SetImageSelectionTags {
1420    my ( $self, $tags ) = @_;
1421
1422    $self->image_selection_tags($tags) if 'ARRAY' eq ref $tags;
1423
1424    #print Dumper $self->image_selection_tags;
1425    # append to each image
1426    # if multiple selection
1427    if($self->multi_selection_mode){
1428        map {
1429            # need to dedup
1430            my $tags = [
1431                @{$self->GetImage($_)->site_tags},
1432                @{$self->image_selection_tags},
1433            ];
1434            #deduplicate
1435            my $uniq = {
1436                 map { $_ => 1 } @$tags
1437            };
1438            @$tags = keys %$uniq;
1439            $self->GetImage($_)->site_tags(
1440                $tags
1441            );
1442        }@{$self->image_selection};
1443    }
1444
1445    $self->image_selection_tags;
1446}
1447
1448
1449sub SetImageSelectionPrivacyLevel {
1450    my ( $self, $privacy_level ) = @_;
1451
1452    # append to each image
1453    # if multiple selection
1454    if($self->multi_selection_mode){
1455        if(defined $privacy_level){
1456            $self->image_selection_privacy_level($privacy_level);
1457            map {
1458                $self->GetImage($_)->privacy_level(
1459                    $privacy_level
1460                ) ;
1461            }@{$self->image_selection}
1462        };
1463    }
1464
1465    $self->image_selection_privacy_level;
1466}
1467
1468sub SetImageSelectionName {
1469    my ( $self, $name ) = @_;
1470
1471    # append to each image
1472    # if multiple selection
1473    if($self->multi_selection_mode){
1474        if(defined $name){
1475            $self->image_selection_name($name);
1476            map {
1477                $self->GetImage($_)->site_name(
1478                    $name
1479                ) ;
1480            }@{$self->image_selection}
1481        };
1482    }
1483
1484    $self->image_selection_name;
1485}
1486
1487sub SetImageSelectionAuthor {
1488    my ( $self, $author ) = @_;
1489
1490    # append to each image
1491    # if multiple selection
1492    if($self->multi_selection_mode){
1493        if(defined $author){
1494            $self->image_selection_author($author);
1495            map {
1496                $self->GetImage($_)->site_author(
1497                    $author
1498                ) ;
1499            }@{$self->image_selection}
1500        };
1501    }
1502
1503    $self->image_selection_author;
1504}
1505
1506sub SetImageSelectionComment {
1507    my ( $self, $comment ) = @_;
1508
1509    # append to each image
1510    # if multiple selection
1511    if($self->multi_selection_mode){
1512        if(defined $comment){
1513            $self->image_selection_comment($comment);
1514            map {
1515                $self->GetImage($_)->site_comment(
1516                    $comment
1517                ) ;
1518            }@{$self->image_selection}
1519        };
1520    }
1521
1522    $self->image_selection_comment;
1523}
1524
1525
1526sub SetImageSelectionCreateDate {
1527    my ( $self, $date ) = @_;
1528
1529    # append to each image
1530    # if multiple selection
1531    if($self->multi_selection_mode){
1532        if(defined $date){
1533            $self->image_selection_create_date($date);
1534            map {
1535                $self->GetImage($_)->create_date(
1536                    $date
1537                ) ;
1538            }@{$self->image_selection}
1539        };
1540    }
1541
1542    $self->image_selection_create_date;
1543}
1544
15451;
Note: See TracBrowser for help on using the repository browser.