source: extensions/pLoader/trunk/src/Uploader/ResizeWorker.pm @ 6737

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

Clean up image files from cache when exiting.

File size: 15.2 KB
Line 
1package Uploader::ResizeWorker;
2use threads;
3use threads::shared;
4use strict;
5use base qw/Uploader::Object/;
6use Image::Magick;
7use Data::Dumper;
8
9$|=1;
10
11__PACKAGE__->mk_accessors(qw/
12    preferences
13    wx_thumb_dir
14    thumb_dir
15    resized_dir
16    write_type
17    progress_event
18    done_event
19    event_handler
20    cancel_event
21    gravity
22    rgbcolor
23/);
24
25
26sub Init {
27    my ( $self ) =@_;
28
29    $self->gravity(
30        { 
31            'Top'          => 'North',
32            'Left'         => 'West',
33            'Right'        => 'East',
34            'Bottom'       => 'South',
35            'Top left'     => 'NorthWest',
36            'Top right'    => 'NorthEast',
37            'Bottom left'  => 'SouthWest',
38            'Bottom right' => 'SouthEast',
39            'Center'       => 'Center',
40       }   
41    );   
42
43    $self->rgbcolor(
44        {
45            "White" => '#FFFFFF',
46            "Black" => '#000000',
47        }   
48    );
49}
50
51
52sub cancel_image {
53    my ( $self, $image ) = @_;
54   
55    #must check if $image is a valid hash
56    return unless 'HASH' eq ref $image;
57    return unless $image->{image_id};
58
59    $self->log_image_progress(
60        $image,
61        $self->localized_msg->{"cancelled"},
62        0,
63    );
64}
65
66
67sub process_image {
68    my ( $self, $handler, $progress_event, $resize_done_event, $image ) = @_;
69
70    $self->event_handler(
71        $handler
72    );
73
74
75    $self->progress_event(
76        $progress_event
77    );
78
79    $self->done_event(
80        $resize_done_event
81    );
82
83    $image->{update_files} = defined $image->{pwg_image_id} ?
84        $image->{preferences}{reupload_action_files} :
85        1;
86
87    if($image->{update_files}){
88        $self->resize_image($image);
89        $self->process_high_image($image);
90        $self->thumbnail_image($image);
91    }
92
93    $self->post_image_done_event($image);
94}
95
96
97sub post_image_progress_event {
98    my ( $self, $image ) = @_;
99
100    $self->post_image_event(
101        $self->progress_event,
102        $image
103    );
104}
105
106
107sub post_image_done_event {
108    my ( $self, $image ) = @_;
109
110    $image->{status}   = $self->localized_msg->{"prepared, waiting for transfer"};
111    $image->{progress} = 25;
112
113    $self->post_image_event(
114        $self->done_event,
115        $image
116    );
117}
118
119
120sub post_image_cancel_event {
121    my ( $self, $image ) = @_;
122
123    $image->{status}   = "cancelled";
124    $image->{progress} = 0;
125
126    $self->post_image_event(
127        $self->cancel_event,
128        $image
129    );
130}
131
132
133
134
135sub post_image_event {
136    my ( $self, $event_type, $image ) = @_;
137
138    my $thread_event = Wx::PlThreadEvent->new(
139        -1,
140        $event_type,
141        shared_clone($image)
142    );
143
144    eval {
145        Wx::PostEvent($self->event_handler, $thread_event);
146    }
147
148}
149
150
151sub resize_image {
152    my ( $self, $image ) = @_;
153
154    $self->log_image_progress(
155        $image,
156        $self->localized_msg->{"preparing web size"},
157        5,
158    );
159
160    my $preferences = $image->{preferences};
161
162    if( $preferences->{create_resized} ){
163        $self->create_resized($image);
164    }
165    # the original is at the right size, no need to create a resize
166    else {
167        #printf("original no resized %s\n", $self->create_resized);
168        $image->{site_resized_file} = $image->{file};
169    }
170
171    $self->log_image_progress(
172        $image,
173        $self->localized_msg->{"web size prepared"},
174        10,
175    );
176
177}
178
179
180sub log_image_progress {
181    my ( $self, $image, $status, $value ) = @_;
182
183    $image->{status}   = $status;
184    $image->{progress} = $value;
185    $self->post_image_progress_event($image);
186}
187
188
189sub process_high_image {
190    my ( $self, $image ) = @_;
191
192    my $decode = {
193        'No' => 0,
194        'Yes, use HD resized of the original photo' => 'HD',
195        'Yes, use a copy of the original photo' => 'ORIGINAL',
196    };
197
198    my $preferences = $image->{preferences};
199    $image->{upload_high} = $decode->{$preferences->{upload_hd}};
200    # if upload high, rotate a copy of original file
201    if($image->{upload_high}){
202        $self->create_high($image);
203    }
204}
205
206
207# $image is a hash, not an object
208sub create_resized {
209    my ( $self, $image ) = @_;
210
211    my $rval = 1 ;
212
213    $image->{site_resized_file} = File::Spec->catfile(
214        $self->resized_dir,
215        sprintf(
216            "%s.%s.%s",
217            $image->{image_id},
218            $image->{global_rank},
219            $self->write_type,
220        ),
221    );
222
223    my $imgk = new Image::Magick;
224
225    my $status = $imgk->ReadImage(
226        $image->{file}
227    );
228    warn "$status" if $status ;
229    return 0 if $status;
230
231    my $w = $imgk->Get('width');
232    my $h = $imgk->Get('height');
233
234    $status = $imgk->Set(Gravity=>"Center");
235    warn "$status" if $status ;
236
237    # exif from original image
238    my $orientation = $image->{exif_metadata}{Orientation};
239    my $preferences = $image->{preferences};
240   
241    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
242    if( $orientation =~ m/Rotate (\d+)/ ){
243        printf(
244            "Rotate %s\n",
245            $1
246        );
247   
248        $imgk->Rotate( degrees=>$1 ) if $preferences->{auto_rotate};   
249    }
250
251
252    #printf("resize with blur value %s\n", $self->blur);
253    $status = $imgk->Resize(
254        geometry => sprintf(
255            "%sx%s>",
256            $preferences->{resize_w},
257            $preferences->{resize_h}
258        ),
259        filter => sprintf(
260            "%s",
261            $preferences->{filter}
262        ), 
263        blur => $preferences->{blur}
264    );
265    warn "$status" if $status ;
266    return 0 if $status;
267
268    #printf("resize with quality value %s\n", $self->quality);
269    $status = $imgk->Set(quality=>$preferences->{quality});
270    warn "$status" if $status ;
271
272    $status = $imgk->Set(interlace=>$preferences->{interlace});
273    warn "$status" if $status ;
274
275    $imgk->Write(
276        sprintf(
277            "%s:%s",
278            $self->write_type,
279            $image->{site_resized_file},
280        )
281    );
282    warn "$status" if $status ;
283    return 0 if $status;
284   
285    undef $imgk;
286
287    if($preferences->{watermark_activate}){
288        $self->create_watermark(
289            $preferences,
290            $image->{site_resized_file}
291        );
292    }
293
294   
295    $rval = 0 if $status;
296
297    return $rval;
298}
299
300# $image is a hash, not an object
301sub thumbnail_image {
302    my ( $self, $image ) = @_;
303   
304    my $rval = 1;
305
306    $image->{site_thumb_file} = File::Spec->catfile(
307        $self->thumb_dir,
308        sprintf(
309            "%s.%s.%s",
310            $image->{image_id},
311            $image->{global_rank},
312            $self->write_type,
313        ),
314    );
315
316
317    my $imgk = new Image::Magick;
318
319    my $status = $imgk->ReadImage(
320        $image->{site_resized_file}
321    );
322    warn "$status" if $status ;
323
324    my $preferences = $image->{preferences};
325    my $pattern = $preferences->{thumbnail_shape_square} ?
326        "%sx%s^" :
327        "%sx%s>" ;
328    $status = $imgk->Resize(
329        geometry => sprintf(
330            $pattern, 
331            $preferences->{thumb_size}, 
332            $preferences->{thumb_size}
333        ),
334    );
335    warn "$status" if $status ;
336
337    $status = $imgk->Set(Gravity=>"Center");
338    warn "$status" if $status ;
339
340    $status = $imgk->Crop(
341        geometry=>sprintf(
342            "%sx%s+0+0",
343            $preferences->{thumb_size},
344            $preferences->{thumb_size}
345        )
346    ) if $preferences->{thumbnail_shape_square};
347
348
349    $status = $imgk->Set(quality=>$preferences->{th_quality});
350    warn "$status" if $status ;
351
352    $status = $imgk->Strip();
353    warn "$status" if $status ;
354
355
356    $imgk->Write(
357        sprintf(
358            "%s:%s",
359            $self->write_type,
360            $image->{site_thumb_file},
361        )
362    );
363   
364    undef $image;
365
366
367    $rval = 0 if $status;
368
369    return $rval;
370}
371
372
373sub create_high {
374    my ( $self, $image ) = @_;
375
376    $self->log_image_progress(
377        $image,
378        $self->localized_msg->{"preparing high"},
379        15,
380    );
381
382    $self->set_site_high_file($image);
383
384    my $bModifyOriginal;
385    my $bRotate;
386    my $bAddWatermark;
387    my $bResize;
388    my $orientation = $image->{exif_metadata}{Orientation};
389    my $degrees;
390   
391    my $preferences = $image->{preferences};
392    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
393    if( $preferences->{auto_rotate} and $orientation =~ m/Rotate (\d+)/ ){
394        $bModifyOriginal = 1;
395        $bRotate = 1;
396        $degrees = $1;
397    }
398
399    if( $preferences->{watermark_activate_pwg_high} ){
400        $bModifyOriginal = 1;
401        $bAddWatermark = 1;
402    }
403   
404    # HD resize
405    if('HD' eq $image->{upload_high}){
406        $bModifyOriginal = 1;
407        $bResize = 1;
408    }
409
410    if($bModifyOriginal){
411
412        my $imgk = Image::Magick->new();
413        # we read original
414        my $status = $imgk->Read(
415            $image->{file}
416        );
417        warn "$status ", $image->{file}, "\n" if $status ;
418        return 0 if $status;
419
420        if($bRotate){
421            $imgk->Rotate( degrees=>$degrees );   
422        }       
423        $imgk->Write(
424            $image->{site_high_file}
425        );
426        warn "$status ", $image->{site_high_file}, "\n" if $status ;
427        return 0 if $status;
428
429        if($bResize){
430            $status = $imgk->Resize(
431                geometry => sprintf(
432                    "%sx%s>",
433                    $preferences->{hd_w},
434                    $preferences->{hd_h}
435                ), 
436                filter => sprintf(
437                    "%s",
438                    $preferences->{hd_filter}
439                ), 
440                blur => $preferences->{hd_blur}
441            );
442            warn "$status" if $status ;
443            return 0 if $status;
444        }
445       
446        #printf("resize with quality value %s\n", $self->quality);
447        $status = $imgk->Set(quality=>$preferences->{quality});
448        warn "$status" if $status ;
449
450        $status = $imgk->Set(interlace=>$preferences->{interlace});
451        warn "$status" if $status ;
452       
453        $imgk->Write(
454            sprintf(
455                "%s:%s",
456                $self->write_type,
457                $image->{site_high_file},
458            )
459        );
460        warn "$status" if $status ;
461       
462        undef $imgk;
463
464        if($bAddWatermark){
465            $self->create_watermark(
466                $image->{preferences},
467                $image->{site_high_file}
468            );
469        }
470
471        $self->set_file_exif_tag(
472            $image->{site_high_file},
473            'Orientation',
474            'Horizontal (normal)',
475        );
476
477        # Now all images that need to be rotated are done. Update exif
478        $image->{exif_metadata}{Orientation} = 'Horizontal (normal)';
479
480
481    }
482    else{
483        # high file is the original file
484        $image->{site_high_file} = $image->{file};
485    }
486    $self->log_image_progress(
487        $image,
488        $self->localized_msg->{"high prepared"},
489        25,
490    );
491
492    return 1;
493
494}
495
496
497sub set_site_high_file {
498    my ( $self, $image ) = @_;
499
500    my ( $vol, $dir, $file ) = File::Spec->splitpath(
501        $image->{file}
502    );
503   
504    my ( $filename, $ext ) = split /\./, $file ;
505   
506    # high_file is a resized of original
507    $image->{site_high_file} = File::Spec->catfile(
508        $self->resized_dir,
509        sprintf(
510            "%s_high.%s.%s",
511            $image->{image_id},
512            $image->{global_rank},
513            $self->write_type,
514        ),
515    );
516}
517
518
519sub create_watermark {
520    my ( $self, $preferences, $file_out ) = @_;
521   
522    my $rval = 1 ;
523
524    my $text = $preferences->{watermark_text};
525    my $text_size = $preferences->{watermark_text_size};
526    my $w_position = $preferences->{watermark_position};
527    my $x = $preferences->{watermark_x};
528    my $y = $preferences->{watermark_y};
529    my $color = $preferences->{watermark_color};
530
531    my $gravity = $self->gravity->{$w_position};
532    my $fill = $self->rgbcolor->{$color};
533
534    # debug
535    #printf("Create watermark %s\n", $file_out);
536
537   
538
539    my $imgk = new Image::Magick;
540   
541    my $status = $imgk->ReadImage(
542        $file_out
543    );     
544
545    my $ratio = $imgk->Get('height')/($preferences->{resize_h}||$imgk->Get('height'));
546    $ratio||=1;
547    $text ||="Your watermark";
548    $imgk->Annotate(
549        pointsize => $text_size*$ratio,
550        fill => $fill,
551        x => $x*$ratio,
552        y => $y*$ratio,
553        text => $text,
554        gravity => $gravity,
555    );
556                     
557    $imgk->Write(
558        sprintf(
559            "%s:%s",
560            $self->write_type,
561            $file_out,
562        )
563    );
564}
565
566
567sub set_file_exif_tag {
568    my ( $self, $file, $tag, $newValue ) = @_;   
569
570    my $options = {};
571    # Create a new Image::ExifTool object
572    my $exifTool = new Image::ExifTool;
573
574    # Extract meta information from an image
575    $exifTool->ExtractInfo($file, $options);
576
577    # Set a new value for a tag
578    $exifTool->SetNewValue($tag, $newValue);
579
580    # Write new meta information to a file
581    $exifTool->WriteInfo($file);
582
583}
584
585
586# used for display in GUI. has to fit a square box ( wxImageList )
587# $image is an object
588sub create_wx_thumbnail {
589    my ( $self, $image ) = @_;
590
591
592    $image->wx_thumb_file( 
593        File::Spec->catfile(
594            $self->wx_thumb_dir,
595            sprintf(
596                "%s.%s.%s",
597                $image->image_id,
598                $image->global_rank,
599                $self->write_type,
600            ),
601        )
602    );
603
604
605    my $rval = 0;
606    my $imgk = new Image::Magick;
607
608    my $preferences = $image->{preferences};
609    my $size = $preferences->{wx_thumb_size}||100;
610
611    my $status = $imgk->Set(size=>sprintf("%sx%s", 2*$size, 2*$size));
612    warn "$status" if $status ;
613
614    $status = $imgk->ReadImage(
615        $image->file
616    );
617    warn "$status" if $status;
618    return $rval if $status;
619
620    # maximize size and keep aspect ratio
621    $status = $imgk->Thumbnail(
622        geometry=>sprintf("%s%s>", $size*$size, '@')
623    );
624    # to get adjusted to a square box
625    #$status = $image->Thumbnail(
626    #    geometry=>sprintf("%sx%s%s", $size, $size, '^')
627    #);
628    warn "$status" if $status;
629    return $rval if $status;
630
631    $status = $imgk->Set(Gravity=>"Center");
632    warn "$status" if $status ;
633
634    $imgk->Extent(
635        geometry=>sprintf("%sx%s", $size, $size),
636        gravity=>'center',
637    );
638   
639    $imgk->Set(
640        quality=>$preferences->{wx_quality}||90
641    );
642
643    $status = $imgk->Strip();
644    warn "$status" if $status ;
645
646    # exif from original image
647    my $orientation = $image->exif_metadata->{Orientation};
648   
649    # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
650    if( $orientation =~ m/Rotate (\d+)/ ){
651        printf(
652            "Rotate %s\n",
653            $1
654        );
655   
656        $imgk->Rotate( degrees=>$1 ) if $preferences->{auto_rotate};   
657    }
658   
659
660    $imgk->Write(
661        sprintf(
662            "%s:%s",
663            $self->write_type,
664            $image->wx_thumb_file,
665        )
666    );
667
668    undef $imgk;
669   
670    $rval = 1;
671   
672    return $rval;
673}
674
675
6761;
Note: See TracBrowser for help on using the repository browser.