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

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

Refactor thread management to reduce memory footprint ( pLoader now starts with 60 Mo instead of 90 Mo ).

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