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

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

Feature 1478 added : Ability to set properties for a batch of selected photos. New implementation with specific gui layout.

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