Buttonzz has asked for the wisdom of the Perl Monks concerning the following question:

Hello everybody and thanks for reading my problem.

Im new in here and need some advice to overwhelm some trouble programming my exif-editor Tool with Perl and Perl-Tk.

Im dealing with two problems.

I)

I have a scrollable GridColumn with 2 columns. Before Im creating it, Im creating a menu where you can pick a file or directory. So I cant call $gc->refresh() in the menu's subs.

If I start the application and pick a file, the gridcolumns data sofore wont update.

Is there any way creating an event that "watches" if $file or $folder swap from undef to something else? - I 'overread' some sites dealing with events but cant find anything that really fits. (Or I didnt get deep enough.

II)

Dealing with Image:ExifTool - is there any 'easy' way to get all the info of more than one file (all files with exif info in a specific directory) together?

If I manage those 2 problems I might eb able to stick to my appointment next friday. Its an exercise I chose myself for the last course before my bachelor thesis.

Unfortunate my kid had lots of trouble with teeth - so we with sleep - and after that we all got ill, so it gets close to the deadline now and Im missing some things. Im sure my lecturer would give me another week. But I wont use this if I dont have to.

In case you need more information, feel free to ask. I wanted to keep it quite theoretically because I dont want anyone to do my work - I just need some 'slaps on the back of my head' as we German say. :) Have a nice evening and thx for anyone dealing with my post. :)

  • Comment on Questions regarding mixing up all the data from Image::ExifTool

Replies are listed 'Best First'.
Re: Questions regarding mixing up all the data from Image::ExifTool
by kcott (Archbishop) on Oct 14, 2017 at 11:44 UTC

    G'day Buttonzz,

    Welcome to the Monastery.

    "I wanted to keep it quite theoretically because I dont want anyone to do my work ..."

    This is most laudable! However, a little more practical information wouldn't have hurt. By "GridColumn" I'll assume you mean Tk::GridColumns. Do note that many module names are very similar: it's best to provide a link so we're all on the same page (see "What shortcuts can I use for linking to other information?"). It's unclear what "the menu's subs" refers to: some code to indicate what you'd tried would have helped. In general, a minimal example of what you've attempted allows us to help you better; for GUIs, leave out all the cosmetic code (colours, fonts, padding, etc.) and just concentrate on the main parts (basic layout, callbacks, and so on). Probably not necessary in this case but, with GUIs, a minimal piece of ASCII art is often far more enlightening than a lengthy, prosaic description.

    "Im dealing with two problems."

    Problem I: I'm guessing your issue is references. In the code I provide below, there's a &build_menu with "$$gc_ref->refresh;": "$gc_ref" is a reference to "$gc". The documentation I linked to has "$gc->refresh;" in several places: I'm assuming that's the same method you're referring to.

    Problem II: Again, with no code, it's difficult to know where you're having difficulties. The usual solution, in this type of situation, is to populate a hash with data you collect, then access that later for whatever processing is required. In the code I provide below, there's &_get_exif_data which collects data in a hash (as a hashref: "$exif_data"); and &_populate_grid which subsequently uses it. Both of those subroutines are called from a callback in &build_menu.

    In &_get_exif_data, you'll see that only one Image::ExifTool object is instantiated and reused on every call. Also note that it only extracts information once per filetype per directory: if your directory contents are changing, you may want to handle that differently. I've only stored the file type information for this code example: it sounds like you'll want more than this; however, the underlying technique should still be sound.

    One thing to note about the following code is that all variables are lexical (using my) and all have a very limited scope. There are no variables at the file-scope level; and anonymous blocks have been used to further restrict their scope within subroutines. Where variables have been passed around as function arguments, a reference to the variable, rather than the variable itself, has been used (in nearly every case): this is particularly important with callbacks (which often simply won't work, or will fail in hard-to-track-down ways, if you don't do this).

    #!/usr/bin/env perl use strict; use warnings; use autodie; use File::Spec; use Image::ExifTool; use Tk; use Tk::LabFrame; use Tk::GridColumns; build_gui(MainWindow::->new); MainLoop; sub build_gui { my ($mw) = @_; $mw->geometry('400x500+50+50'); build_ctrl($mw); { my $exif_data = {}; my ($gc, @gdata); build_menu($mw, \$exif_data, \$gc, \@gdata); build_grid($mw, \$gc, \@gdata); } } sub build_menu { my ($mw, $exif_data_ref, $gc_ref, $gdata_ref) = @_; my $frame = $mw->LabFrame(-label => 'Menu', -labelside => 'acrosst +op') ->pack(-fill => 'x'); my $dir_frame = $frame->Frame->pack(-fill => 'x'); my $ext_frame = $frame->Frame->pack(-fill => 'x'); my $pop_frame = $frame->Frame->pack(-fill => 'x'); my $directory = 'pm_1201345_test_files'; my $extensions = ''; $dir_frame->Label(-text => 'Directory: ')->pack(-side => 'left'); $dir_frame->Label(-textvariable => \$directory)->pack(-side => 'le +ft'); $ext_frame->Label(-text => 'Extensions: ')->pack(-side => 'left'); $ext_frame->Entry(-textvariable => \$extensions)->pack(-side => 'l +eft'); $pop_frame->Button(-text => 'Populate Grid', -command => sub { _get_exif_data($exif_data_ref, \$directory, \$extensions); _populate_grid(\$gdata_ref, $exif_data_ref, \$directory, \$ext +ensions); $$gc_ref->refresh; })->pack(-side => 'left'); return; } sub build_grid { my ($mw, $gc_ref, $gdata_ref) = @_; my $frame = $mw->LabFrame(-label => 'Grid', -labelside => 'acrosst +op') ->pack(-fill => 'both', -expand => 1); my @cols; $$gc_ref = $frame->GridColumns(-data => $gdata_ref, -columns => \@ +cols) ->pack(-fill => 'both', -expand => 1); @cols = ( { -text => 'Pathname', -weight => 1 }, { -text => 'File Type' }, ); $$gc_ref->refresh; return; } sub build_ctrl { my ($mw) = @_; my $frame = $mw->LabFrame(-label => 'Controls', -labelside => 'acr +osstop') ->pack(-side => 'bottom', -fill => 'x'); $frame->Button(-text => 'Exit', -command => sub { exit })->pack; return; } { my $exif; BEGIN { $exif = Image::ExifTool::->new } sub _get_exif_data { my ($exif_data, $dir, $exts) = map { $$_ } @_; my @unseen_exts = grep { ! exists $exif_data->{$dir}{$_} } spl +it ' ', $exts; return unless @unseen_exts; my $ext_re = '[.](' . join('|', @unseen_exts) . ')$'; { opendir(my $dh, $dir); while (readdir $dh) { next unless /$ext_re/; my $path = File::Spec::->catfile($dir, $_); $exif->ExtractInfo($path); $exif_data->{$dir}{$1}{$path} = $exif->GetValue('FileT +ype'); } } return; } } sub _populate_grid { my ($gdata_ref, $exif_data, $dir, $exts) = map { $$_ } @_; @$gdata_ref = (); for my $ext (sort split ' ', $exts) { for my $path (sort keys %{$exif_data->{$dir}{$ext}}) { push @$gdata_ref, [$path, $exif_data->{$dir}{$ext}{$path}] +; } } return; }

    To test this code, I created a directory called "pm_1201345_test_files", and populated it with a variety of PNG, SVG and WAV files.

    — Ken

Re: Questions regarding mixing up all the data from Image::ExifTool
by Discipulus (Canon) on Oct 14, 2017 at 15:13 UTC
    Hello Buttonzz and welcome to the monastery and to the wonderful world of Perl,

    you already got two wise answers by two wise monks.. I'll just some link and suggstions.

    Tk.. images.. grid.. exif.. it remember me something I've already done: infact in the past I realized a Tk program to show and pickup among photos that, not being perfect, affront the very same tasks you ask for.

    The project was published here at perlmonks: picwoodpecker -- a Tk program to choose and modify your photos and then I also put it at github.

    Each picture is examined using Image::ExifTool for example to get the exact rotation to display it better. A little wrapper around exiftool executable is available in the Advanced option pane that let you to clean all unwanted tags or everything exiftool can do and it's lot of things.

    Given a directory or an expression to glob pickwoodpecker build up a browsable grid of thumbnails.

    Run it and see if you recognize behaviours you are interested in: you are free to take inspiration (aka copy).

    I load images using GD module but anything you use you must be aware of possible memory leak (see also this bug).

    Infact first version of my program leaked a lot of memory: you must reuse as much as you can image variable and even this is not enough. See Tk photo display: memory never released where i asked how to prevent leaks. Pay attention to my own comments in the code at Re: Tk photo display: memory never released (not leaking solution feeding -data to Tk::Photo)

    Current version of my program leaks quite no memory and switching from grid view to photo view release that memory too (anyway i load every thumbnail in memory into a big hash along with size informations and rotation, so the program uses some hundreds Mb of RAM for one thousand of pictures loaded).

    When searching here at the monastery remember that kcott it's a neat Tk programmer but we have others too, notably zentara a master geek with Tk, and others good users too like choroba, tybalt89 .. I say the above because you must take inspiration from rigth authors.

    If you post some skeletal code you for sure get good advices.

    Share your progresses!

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Questions regarding mixing up all the data from Image::ExifTool
by stevieb (Canon) on Oct 13, 2017 at 20:54 UTC

    Here's an untested example of fetching all *.jpg and *.jpeg images from within a directory, then working on them with Image::ExifTool. It will search for the files recursively. If you don't want to find images in directories underneath of the directory you're looking in, put a ->maxdepth(1) line above the ->in(...) line in the call to File::Find::Rule.

    use warnings; use strict; use File::Find::Rule; use Image::ExifTool qw(:Public); my $dir = '~/Desktop'; my @files; if (-d $dir){ @files = File::Find::Rule->file() ->name('*.jpg', '*.jpeg') ->in($dir); } else { die "that's not a directory dude!\n"; } my $exif_tool = Image::ExifTool->new; for my $img (@files){ $exif_tool->ExtractInfo($img); # do other stuff with exif tool }