3
###################################################
5
# Copyright (C) 2008, 2009 Mario Kemper <mario.kemper@googlemail.com> and Shutter Team
7
# This file is part of Shutter.
9
# Shutter is free software; you can redistribute it and/or modify
10
# it under the terms of the GNU General Public License as published by
11
# the Free Software Foundation; either version 3 of the License, or
12
# (at your option) any later version.
14
# Shutter is distributed in the hope that it will be useful,
15
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
# GNU General Public License for more details.
19
# You should have received a copy of the GNU General Public License
20
# along with Shutter; if not, write to the Free Software
21
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
###################################################
30
use POSIX qw/setlocale strftime/;
32
use Glib qw/TRUE FALSE/;
33
use FindBin '$Bin'; #path where plugin is located
34
use File::Temp qw/ tempfile tempdir /;
35
use Time::HiRes qw/usleep/;
37
#load modules at custom path at runtime
38
#--------------------------------------
40
import lib $ENV{'SHUTTER_ROOT'}."/share/shutter/resources/modules";
42
#proc (Thanks to Michael Schilli)
45
#load shutter's modules
46
#--------------------------------------
47
require Shutter::App::SimpleDialogs;
49
#configure gettext using ENV Variable (setup during shutter start)
50
setlocale( LC_MESSAGES, "" );
51
my $d = Locale::gettext->domain("shutter-plugins");
52
$d->dir( $ENV{'SHUTTER_INTL'} );
54
#shutter will ask for some infos
55
my %plugin_info = ( 'name' => $d->get( "barrel distortion" ),
56
'sort' => $d->get( "effect" ),
57
'tip' => $d->get("apply a distortion effect to your screenshot"),
60
binmode( STDOUT, ":utf8" );
61
if ( exists $plugin_info{$ARGV[ 0 ]} ) {
62
print $plugin_info{$ARGV[ 0 ]};
66
#these variables are passed to the plugin
67
my $socket_id = $ARGV[ 0 ];
68
my $filename = $ARGV[ 1 ];
69
my $width = $ARGV[ 2 ];
70
my $height = $ARGV[ 3 ];
71
my $filetype = $ARGV[ 4 ];
74
utf8::decode $filename;
76
my $plug = Gtk2::Plug->new( $socket_id );
78
$plug->set_default_icon_from_file( $ENV{'SHUTTER_ICON'} );
80
$plug->set_border_width( 10 );
82
$plug->signal_connect( destroy => sub { Gtk2->main_quit } );
85
my $tooltips = Gtk2::Tooltips->new;
87
#configure buttons and other needed controls
88
my $c1_label = Gtk2::Label->new( $d->get( "A:" ) );
89
my $c1_sbutton = Gtk2::SpinButton->new_with_range( -1, 1, 0.1 );
90
$c1_sbutton->set_value( 0.2 );
92
my $c2_label = Gtk2::Label->new( $d->get( "B:" ) );
93
my $c2_sbutton = Gtk2::SpinButton->new_with_range( -1, 1, 0.1 );
94
$c2_sbutton->set_value( 0 );
96
my $c3_label = Gtk2::Label->new( $d->get( "C:" ) );
97
my $c3_sbutton = Gtk2::SpinButton->new_with_range( -1, 1, 0.1 );
98
$c3_sbutton->set_value( 0 );
100
my $c4_label = Gtk2::Label->new( $d->get( "D:" ) );
101
my $c4_sbutton = Gtk2::SpinButton->new_with_range( -1, 1, 0.1 );
102
$c4_sbutton->set_value( 1.0 );
107
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
114
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
121
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
128
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
135
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
142
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
149
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
156
"The parameter d describes the linear scaling of the image. Using d=1, and a=b=c=0 leaves the image as it is. Choosing other d-values scales the image by that amount. a,b and c distort the image. Using negative values shifts distant points away from the center.\n\nDefined by Barrel Correction Distortion, by Helmut Dersch.\nhttp://www.all-in-one.ee/~dersch/barrel/barrel.html"
160
my $back_color_label = Gtk2::Label->new( $d->get("Background color"). ":" );
161
my $back_color = Gtk2::ColorButton->new();
162
$back_color->set_color( Gtk2::Gdk::Color->parse('gray') );
163
$back_color->set_alpha( int( 0 * 65535 ) );
164
$back_color->set_use_alpha(TRUE);
165
$back_color->set_title( $d->get("Choose background color") );
167
#all labels on the left side
168
#need to have the same size
169
my $sgl = Gtk2::SizeGroup->new ('both');
170
$sgl->set ('ignore-hidden' => FALSE);
171
$sgl->add_widget($c1_label);
172
$sgl->add_widget($c2_label);
173
$sgl->add_widget($c3_label);
174
$sgl->add_widget($c4_label);
176
#we define two Gtk2::Image widgets
177
#to store the screenshot
178
#and a throbber that is shown while the changes are processed
180
Gtk2::Image->new_from_pixbuf(
181
Gtk2::Gdk::Pixbuf->new_from_file_at_scale( $filename, 300, 300, TRUE ) );
184
Gtk2::Image->new_from_file( $ENV{'SHUTTER_ROOT'}."/share/shutter/resources/icons/throbber.gif" );
186
my $sg = Gtk2::SizeGroup->new ('both');
187
$sg->set ('ignore-hidden' => FALSE);
188
$sg->add_widget($preview);
189
$sg->add_widget($preview_throb);
192
#we define three Gtk2::Button widgets
193
#to refresh, save and cancel the plugin's work
194
my $refresh_btn = Gtk2::Button->new_from_stock( 'gtk-refresh' );
195
$refresh_btn->signal_connect( 'clicked', \&fct_imagemagick_bardistortion,
198
my $save_btn = Gtk2::Button->new_from_stock( 'gtk-save' );
199
$save_btn->signal_connect( 'clicked', \&fct_imagemagick_bardistortion, 'save' );
201
my $cancel_btn = Gtk2::Button->new_from_stock( 'gtk-cancel' );
202
$cancel_btn->signal_connect( 'clicked' => sub { Gtk2->main_quit; exit 2; }, 'cancel' );
204
#define the gui layout
205
my $hbox1 = Gtk2::HBox->new( FALSE, 8 );
206
my $hbox2 = Gtk2::HBox->new( FALSE, 8 );
207
my $hbox3 = Gtk2::HBox->new( FALSE, 8 );
208
my $hbox4 = Gtk2::HBox->new( FALSE, 8 );
209
my $hbox5 = Gtk2::HBox->new( FALSE, 8 );
211
my $hbox_row1 = Gtk2::HBox->new( TRUE, 8 );
212
my $hbox_row2 = Gtk2::HBox->new( FALSE, 8 );
214
my $vbox_param = Gtk2::VBox->new( FALSE, 8 );
215
my $vbox_left = Gtk2::VBox->new( FALSE, 8 );
216
my $vbox_right = Gtk2::VBox->new( FALSE, 8 );
218
my $hbox_btn = Gtk2::HBox->new( TRUE, 8 );
219
my $vbox_btn = Gtk2::VBox->new( FALSE, 8 );
220
my $vbox_main = Gtk2::VBox->new( FALSE, 8 );
223
$hbox1->pack_start( $c1_label, FALSE, TRUE, 5 );
224
$hbox1->pack_start( $c1_sbutton, TRUE, TRUE, 5 );
226
$hbox2->pack_start( $c2_label, FALSE, TRUE, 5 );
227
$hbox2->pack_start( $c2_sbutton, TRUE, TRUE, 5 );
229
$hbox3->pack_start( $c3_label, FALSE, TRUE, 5 );
230
$hbox3->pack_start( $c3_sbutton, TRUE, TRUE, 5 );
232
$hbox4->pack_start( $c4_label, FALSE, TRUE, 5 );
233
$hbox4->pack_start( $c4_sbutton, TRUE, TRUE, 5 );
235
$hbox5->pack_start( $back_color_label, FALSE, TRUE, 5 );
236
$hbox5->pack_start( $back_color, TRUE, TRUE, 5 );
239
$hbox_row1->pack_start_defaults( $hbox5 );
241
#controls on the left side
242
$vbox_left->pack_start_defaults( $hbox1 );
243
$vbox_left->pack_start_defaults( $hbox2 );
244
$vbox_left->pack_start_defaults( $hbox3 );
245
$vbox_left->pack_start_defaults( $hbox4 );
248
$vbox_right->pack_start_defaults( $preview );
249
$vbox_right->pack_start_defaults( $preview_throb );
252
$hbox_row2->pack_start_defaults( $vbox_left );
253
$hbox_row2->pack_start_defaults( $vbox_right );
255
$vbox_param->pack_start( $hbox_row1, TRUE, TRUE, 5 );
256
$vbox_param->pack_start( $hbox_row2, TRUE, TRUE, 5 );
258
$vbox_main->pack_start( $vbox_param, FALSE, TRUE, 5 );
259
$vbox_main->pack_start( $refresh_btn, TRUE, TRUE, 5 );
261
$hbox_btn->pack_start( $cancel_btn, TRUE, TRUE, 5 );
262
$hbox_btn->pack_start( $save_btn, TRUE, TRUE, 5 );
264
$vbox_main->pack_start( $hbox_btn, TRUE, TRUE, 5 );
266
$plug->add( $vbox_main );
270
#hide the preview widget at startup
274
my ( $tmpfh, $tmpfilename ) = tempfile();
276
$tmpfilename .= ".png";
278
#we fork a child process to do the work
279
my $process = Proc::Simple->new;
280
#create tempfiles for subprocess outputs
281
my ( $tmpfh_stdout, $tmpfilename_stdout ) = tempfile(UNLINK => 1);
282
my ( $tmpfh_stderr, $tmpfilename_sterr ) = tempfile(UNLINK => 1);
283
$process->redirect_output ($tmpfilename_stdout, $tmpfilename_sterr);
285
#generate first preview at startup
288
&fct_imagemagick_bardistortion( undef, 'refresh' );
296
sub fct_imagemagick_bardistortion {
297
my ( $widget, $data ) = @_;
299
$save_btn->set_sensitive(FALSE);
301
if ( $data eq 'save' ) {
303
my $image = Image::Magick->new;
304
$image->ReadImage( $tmpfilename );
305
$image->WriteImage( filename => $filename );
315
$preview_throb->show_all;
324
#so we can update the gui
325
while ( $process->poll ) {
331
$preview->set_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file_at_scale(
332
$tmpfilename, 300, 300, TRUE)
335
#error -> read output from tempfiles
338
my $error_string = "Plugin error:\n";
340
#reading stdout from file
341
while (<$tmpfh_stdout>){
344
#reading stderr from file
345
while (<$tmpfh_stderr>){
349
#get the parent window of the plug
350
require X11::Protocol;
351
my $x11 = X11::Protocol->new( $ENV{ 'DISPLAY' } );
353
my $plugp = Gtk2::Gdk::Window->foreign_new( &find_wm_window( $x11, $plug->get_id ));
356
my $shutter_dialog = Shutter::App::SimpleDialogs->new($plug, $plugp);
357
$shutter_dialog->dlg_error_message(
358
sprintf ( $d->get( "Error while executing plugin %s." ), "'" . $plugin_info{'name'} . "'" ) ,
359
$d->get( "There was an error executing the plugin." ),
372
$save_btn->set_sensitive(TRUE);
374
$preview_throb->hide_all;
382
my $color = $back_color->get_color;
384
#execute imagemagick command
386
. " -virtual-pixel Background -background '"
387
. sprintf( "#%04x%04x%04x%04x", $color->red, $color->green, $color->blue, $back_color->get_alpha )
388
. "' -distort Barrel '"
389
. $c1_sbutton->get_value
391
. $c2_sbutton->get_value
393
. $c3_sbutton->get_value
395
. $c4_sbutton->get_value
403
while ( Gtk2->events_pending ) {
404
Gtk2->main_iteration;
416
my ( $qroot, $qparent, @qkids ) = $x11->QueryTree($xid);
417
return undef unless ( $qroot || $qparent );
418
return $xid if ( $qroot == $qparent );