#!/usr/bin/perl -w #d # GUI front-end to jpegtran to rotate and flip jpegs without loss # # 2000-06-14 Dobrica Pavlinusic use Gtk; use strict; init Gtk; set_locale Gtk; my $DEBUG = 1; sub pdebug { print STDERR @_,"\n" if ($DEBUG); } my $false = 0; my $true = 1; # $X[0](dir|filename|w|h|pix) my @X; my $xv_pic_dir=".xvpics"; #$xv_pic_dir="/mnt/f/tmp2/PICS/.xvpics" if ($DEBUG); if (! $ARGV[0] && !-d ".xvpics") { print "Usage: $0 [path to directory with pictures (in which is .xvpics dir)]\n"; exit 1; } $xv_pic_dir = $ARGV[0]."/.xvpics" if ($ARGV[0]); if (! -d $xv_pic_dir) { print "$xv_pic_dir is not directory!"; } #-------------------------------------------------------------------- # scan directory pdebug "reading dir $xv_pic_dir"; opendir(DIR, $xv_pic_dir) || die "can't opendir $xv_pic_dir: $!"; my @pic_filenames = grep { !/^\./ && -f "$xv_pic_dir/$_" } readdir(DIR); closedir(DIR); pdebug "found $#pic_filenames files in $xv_pic_dir"; my $dir=$xv_pic_dir; $dir=~s/\.xvpics//; foreach my $filename (@pic_filenames) { pdebug "gronk $filename"; my ($w,$h,$pix) = xvpic_read("$xv_pic_dir/$filename"); my (%tmp) = ( dir=>$dir, filename=>$filename, w=>$w, h=>$h, pix=>$pix ); push @X,\%tmp; } #-------------------------------------------------------------------- # read xvpic from disk # xvpic_read($filename) # returns: # ($w,$h,$xv_pix) sub xvpic_read { my ($xv_pic) = @_; my ($w,$h,$cols) = (0,0,0); open(XV,$xv_pic) || die "$xv_pic: $!"; my $l=; chomp $l; if ($l!~m/^P7 332$/) { warn "$xv_pic not XV thumbnail file ($l)"; return; } while() { chomp; next if (/^#/); if (/^(\d+) (\d+) (\d+)$/) { ($w,$h,$cols) = ($1,$2,$3); last; } warn "expected w,h,cols, got: $_"; } warn "$xv_pic number of colors is not 255 (strange)" if ($cols != 255); my $buf; # tmp buffer for read; # read pixels read XV,$buf,($w*$h); return ($w,$h,$buf); } #-------------------------------------------------------------------- # Generate 332 colour-cube colourmap sub generate_xpm_colmap { my @xpm_colmap; for (my $i=0; $i<256; $i++) { push(@xpm_colmap,sprintf ("%02x c #%02x%02x%02x",$i, (255*(($i&(7<<5))>>5))/7, (255*(($i&(7<<2))>>2))/7, (255*(($i&(3<<0))>>0))/3 )); } return @xpm_colmap; } #-------------------------------------------------------------------- # main my ($w,$h) = (0,0); my $xv_pix; my @xpm_colmap=generate_xpm_colmap(); #($w,$h,@xv_pix) = xvpic_read($xv_pic); my $xv_pic = $X[0]{filename}; $w = $X[0]{w}; $h = $X[0]{h}; $xv_pix = $X[0]{pix}; #-------------------------------------------------------------------- # make rotated pictures #sub make_rotated { # my ($w,$h,$xv_pix) #/* width height ncolors chars_per_pixel */ #my @xpm_0= ( "$w $h 256 2" ); my @xpm_180= ( "$w $h 256 2" ); my @xpm_90= ( "$h $w 256 2" ); my @xpm_270= ( "$h $w 256 2" ); my @xpm_h= ( "$w $h 256 2" ); my @xpm_v= ( "$w $h 256 2" ); #push @xpm_0,@xpm_colmap; push @xpm_180,@xpm_colmap; push @xpm_90,@xpm_colmap; push @xpm_270,@xpm_colmap; push @xpm_h,@xpm_colmap; push @xpm_v,@xpm_colmap; my @pix_0; my @pix_180; my @pix_90; my @pix_270; my @pix_h; my @pix_v; my @xv_pix=unpack("C*",$xv_pix); for(my $y=0; $y<$h; $y++) { for (my $x=0; $x<$w; $x++) { if (defined($xv_pix[$y*$w+$x])) { $pix_0[$y*$w+$x] = sprintf("%02x",$xv_pix[$y*$w+$x]); $pix_180[($h-$y-1)*$w+($w-$x-1)] = sprintf("%02x",$xv_pix[$y*$w+$x]); $pix_270[($w-$x-1)*$h+$y] = sprintf("%02x",$xv_pix[$y*$w+$x]); $pix_90[$x*$h+$y] = sprintf("%02x",$xv_pix[$y*$w+$x]); $pix_h[$y*$w+($w-$x-1)] = sprintf("%02x",$xv_pix[$y*$w+$x]); $pix_v[($h-$y-1)*$w+$x] = sprintf("%02x",$xv_pix[$y*$w+$x]); } else { warn "undef pixel $x,$y!\n"; } } } # fill in pixels now my $tmp; # portrait my $lw=$w*2; #$tmp=join('',@pix_0); while ($tmp=~s/^(.{$lw})//) { push(@xpm_0,$1); } $tmp=join('',@pix_180); while ($tmp=~s/^(.{$lw})//) { push(@xpm_180,$1); } $tmp=join('',@pix_v); while ($tmp=~s/^(.{$lw})//) { push(@xpm_v,$1); } $tmp=join('',@pix_h); while ($tmp=~s/^(.{$lw})//) { push(@xpm_h,$1); } # landscape $lw=$h*2; $tmp=join('',@pix_90); while ($tmp=~s/^(.{$lw})//) { push(@xpm_90,$1); } $tmp=join('',@pix_270); while ($tmp=~s/^(.{$lw})//) { push(@xpm_270,$1); } #-------------------------------------------------------------------- # GTK GUI my $window; my ($pixmapwid_0, $pixmapwid_180, $pixmapwid_90, $pixmapwid_270, $pixmapwid_v, $pixmapwid_h); my ($button_0, $button_180, $button_90, $button_270, $button_v, $button_h); my ($pixmap_0, $pixmap_180, $pixmap_90, $pixmap_270, $pixmap_v, $pixmap_h); my $mask; my $style; $window = new Gtk::Window( "toplevel" ); $window->signal_connect( "delete_event", sub { Gtk->exit( 0 ); } ); $window->border_width( 10 ); $window->set_title( "GTK jpegtran" ); $window->realize(); # now for the pixmap from gdk $style = $window->get_style()->bg( 'normal' ); #( $pixmap_0, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_0 ); # ## a pixmap widget to contain the pixmap #$pixmapwid_0 = new Gtk::Pixmap( $pixmap_0, $mask ); #$pixmapwid_0->show(); # ## a button to contain the pixmap widget #$button_0 = new Gtk::Button(); #$button_0->add( $pixmapwid_0 ); #$button_0->show(); ##$button_0->signal_connect( "clicked", \&jpegtran, "-optimize" ); ## make button_0 inactive #$button_0->set_sensitive( $false ); # rotate 180 ( $pixmap_180, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_180 ); $pixmapwid_180 = new Gtk::Pixmap( $pixmap_180, $mask ); $pixmapwid_180->show(); $button_180 = new Gtk::Button(); $button_180->add( $pixmapwid_180 ); $button_180->show(); $button_180->signal_connect( "clicked", \&jpegtran, "-rotate 180" ); # rotate 90 ( $pixmap_90, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_90 ); $pixmapwid_90 = new Gtk::Pixmap( $pixmap_90, $mask ); $pixmapwid_90->show(); $button_90 = new Gtk::Button(); $button_90->add( $pixmapwid_90 ); $button_90->show(); $button_90->signal_connect( "clicked", \&jpegtran, "-rotate 90" ); # rotate 270 ( $pixmap_270, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_270 ); $pixmapwid_270 = new Gtk::Pixmap( $pixmap_270, $mask ); $pixmapwid_270->show(); $button_270 = new Gtk::Button(); $button_270->add( $pixmapwid_270 ); $button_270->show(); $button_270->signal_connect( "clicked", \&jpegtran, "-rotate 270" ); # rotate v ( $pixmap_v, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_v ); $pixmapwid_v = new Gtk::Pixmap( $pixmap_v, $mask ); $pixmapwid_v->show(); $button_v = new Gtk::Button(); $button_v->add( $pixmapwid_v ); $button_v->show(); $button_v->signal_connect( "clicked", \&jpegtran, "-flip vertical" ); # rotate h ( $pixmap_h, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @xpm_h ); $pixmapwid_h = new Gtk::Pixmap( $pixmap_h, $mask ); $pixmapwid_h->show(); $button_h = new Gtk::Button(); $button_h->add( $pixmapwid_h ); $button_h->show(); $button_h->signal_connect( "clicked", \&jpegtran, "-flip horizontal" ); # pack, show, draw my $hbox_top = new Gtk::HBox( $false, 0 ); my $hbox_mid = new Gtk::HBox( $true, 0 ); my $hbox_bot = new Gtk::HBox( $true, 0 ); #-------------------------------------------------------------------- # sub pix2xpm { my ($nr,$w,$h,$xv_pix) = @_; pdebug("pix2xpm w:$w h:$w pix:",length($xv_pix)); my @xpm=( "$w $h 256 2" ); push @xpm,@xpm_colmap; my @xv_pix=unpack("C*",$xv_pix); my $pix; for(my $i=0; $i<$#xv_pix; $i++) { $pix .= sprintf("%02x",$xv_pix[$i]); } my $lw=$w*2; while ($pix=~s/^(.{$lw})//) { push(@xpm,$1); } pdebug "pix2xpm retured ",length(join("",@xpm))," bytes, $#xpm lines"; return (\@xpm); } sub xpm_button { my ($nr) = @_; pdebug "xpm_button($nr): xpm/pix len: ", length $X[$nr]{xpm},"/",length $X[$nr]{pix}; ( $X[$nr]{pixmap}, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm_d( $window->window, $style, @{$X[$nr]{xpm}} ); # ( $pixmap, $mask ) = Gtk::Gdk::Pixmap->create_from_xpm( $window->window, $style, "test.xpm" ); $X[$nr]{pixmapwid} = new Gtk::Pixmap( $X[$nr]{pixmap}, $mask ); $X[$nr]{pixmapwid}->show(); $X[$nr]{button} = new Gtk::Button(); $X[$nr]{button}->add( $X[$nr]{pixmapwid} ); $X[$nr]{button}->show(); $X[$nr]{button}->signal_connect( "clicked", \&select_pic, $nr ); return ($X[$nr]{button}); } my $arr_l = create_arrow_button( 'left', 'in' ); $hbox_top->pack_start( $arr_l, $false, $false, 0 ); #$hbox_top->pack_start( $button_0, $false, $false, 0 ); for (my $i=0; $i<$#X; $i++) { #for (my $i=0; $i<0; $i++) { $X[$i]{xpm} = pix2xpm($i,$X[$i]{w},$X[$i]{h},$X[$i]{pix}); $X[$i]{button}=xpm_button($window, $i ); $hbox_top->pack_start( $X[$i]{button}, $false, $false, 0 ); } my $arr_r = create_arrow_button( 'right', 'in' ); $hbox_top->pack_start( $arr_r, $false, $false, 0 ); $hbox_mid->pack_start( $button_90, $false, $false, 0 ); $hbox_mid->pack_start( $button_180, $false, $false, 0 ); $hbox_mid->pack_start( $button_270, $false, $false, 0 ); $hbox_bot->pack_start( $button_v, $false, $false, 0 ); $hbox_bot->pack_start( $button_h, $false, $false, 0 ); $hbox_top->show(); $hbox_mid->show(); $hbox_bot->show(); sub create_arrow_button { my ( $arrow_type, $shadow_type ) = @_; my $button; my $arrow; $button = new Gtk::Button(); $arrow = new Gtk::Arrow( $arrow_type, $shadow_type ); $button->add( $arrow ); $button->show(); $arrow->show(); return ( $button ); } my $hbox = new Gtk::HBox( $true, 0 ); my $filename_label = new Gtk::Label($xv_pic); $filename_label->show(); $hbox->pack_start( $filename_label, $false, $false, 0 ); $hbox->show(); my $hseparator = new Gtk::HSeparator(); $hseparator->show(); my $hseparator2 = new Gtk::HSeparator(); $hseparator2->show(); my $vbox = new Gtk::VBox( $false, 5 ); $vbox->pack_start( $hbox_top, $false, $false, 0 ); $vbox->pack_start( $hseparator, $false, $false, 0 ); $vbox->pack_start( $hbox, $false, $false, 0 ); $vbox->pack_start( $hseparator2, $false, $false, 0 ); $vbox->pack_start( $hbox_mid, $false, $false, 0 ); $vbox->pack_start( $hbox_bot, $false, $false, 0 ); $vbox->show(); $window->add($vbox); $window->show(); main Gtk; exit( 0 ); #-------------------------------------------------------------------- # call jpegtran command sub jpegtran { my ( $widget, $data ) = @_; print "jpegtran $data\n"; } #-------------------------------------------------------------------- # select picture sub select_pic { my ( $widget, $data ) = @_; my $xvpic=$X[$data]{filename}; print "picture selected: $data ($xvpic)\n"; $filename_label->set_text($xvpic); }