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

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

Feature 1650 added : ability to create square thumbnails.

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