Latest posts for tag ruby
Extract tags out of digikam
I've always wanted to tag my image collection, but it's big and a pain to do by hand. Today I found out that digikam has got to a point in which it can be used as a nice interface to categorise images, so I now have something cool for the tagging work.
Now, I'd like to play with the tags using my debtags toolchain. Digikam stores data in a SQLite3 database, so it's easy to convert it into the text format used by tagcoll. Here's the script to do it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
|
I didn't understand why if I perform a precompiled query I get a row object that cannot be indexed, while if I perform an instant query then everything is fine (see the comment in the script).
I'm still on the learning side of Ruby, so I welcome people telling me of better ways to write this script, and I'll be glad to update this entries with what I receive.
Done the little script, now I can plug my images collection into tagcoll and have a bit of fun::
./gettags | tagcoll related /2005/12-15-03-Taiwan-Newcamera/dsci0051.jpg ./gettags | tagcoll hierarchy ./gettags | tagcoll implications ./gettags | tagcoll findspecials
Cute! And this is another little step to somehow connect pieces of the debtags toolchain to the web, which is something I'd like to explore both for the web interface of the central database, my blog and my picture gallery.
Custom signals with Ruby-GTK2
How to create a custom signal in Ruby-GTK2
I'm playing with the GTK2 bindings for Ruby. When coding GUI things, I usually like to build my own higher level widgets by subclassing containers and populating them with other widgets.
For example, I'm creating an image browser and I like to make an ImageList class that subclasses a Gtk::ScrolledWindow and builds the TreeView inside it:
class ImageList < Gtk::ScrolledWindow
def initialize
super
@files = Gtk::ListStore.new(String, String, Gdk::Pixbuf)
@fileList = Gtk::TreeView.new(@files)
renderer = Gtk::CellRendererPixbuf.new
col = Gtk::TreeViewColumn.new("Thumb", renderer, :pixbuf => 2)
@fileList.append_column(col)
renderer = Gtk::CellRendererText.new
col = Gtk::TreeViewColumn.new("File name", renderer, :text => 1)
@fileList.append_column(col)
self.add @fileList
end
def readDir (root)
Dir.foreach root do |dir|
file = root+'/'+dir
if !FileTest.directory?(file) && dir =~ /\.jpe?g$/ && FileTest.readable?(file)
thumb = getThumbnail(file)
iter = @files.append
iter[0] = file
iter[1] = dir
iter[2] = Gdk::Pixbuf.new thumb
File.delete(thumb)
end
end
end
end
When working like this, I find myself very soon in need of creating custom signals: in this case I want to make a signal that ImageList emits when the user select an image from the TreeView, like this:
fileList.signal_connect("selected") do |filename|
imageDetails.load(filename)
end
Now, how do I implement that extra 'selected' signal in my ImageList? Ruby documentation is usually very good and easy to find, but this time Google had little to say to me.
When the going gets tough, the tough gets to IRC::
enrico> Hi. http://ruby-gnome2.sourceforge.jp/?News_20031116_1 says that it is
possible to create custom signals, however I could not find any
documentation on how to do it. Anyone has a link or a short explanation?
pterjan> glib/sample in the source IIRC
pterjan> # define new signal "hoge"
pterjan> signal_new("hoge", # name
pterjan> GLib::Signal::RUN_FIRST, # flags
pterjan> nil, # accumulator (XXX: not supported yet)
pterjan> nil, # return type (void == nil)
pterjan> Integer, Integer # parameter types
pterjan> )
pterjan> in glib/sample/type-register.rb
enrico> ooh!
enrico> pterjan: thanks!
enrico> I'll blog about it, it might make it easier for others to google this answer
Thanks pterjan, and oh, coolness! So there are nice examples that I was silly
enough to miss. Are they included in the Debian packages? Oh, yes! Right in
/usr/share/doc/libglib2-ruby/examples/type-register.rb
.
Here's the ImageList class with the new signal::
class ImageList < Gtk::ScrolledWindow
type_register
signal_new("selected", # name
GLib::Signal::RUN_FIRST, # flags
nil, # accumulator (XXX: not supported yet)
nil, # return type (void == nil)
String # parameter types
)
def initialize
super
@files = Gtk::ListStore.new(String, String, Gdk::Pixbuf)
@fileList = Gtk::TreeView.new(@files)
renderer = Gtk::CellRendererPixbuf.new
col = Gtk::TreeViewColumn.new("Thumb", renderer, :pixbuf => 2)
@fileList.append_column(col)
renderer = Gtk::CellRendererText.new
col = Gtk::TreeViewColumn.new("File name", renderer, :text => 1)
@fileList.append_column(col)
self.add @fileList
sel = @fileList.selection
sel.signal_connect("changed") do |sel|
if iter = sel.selected
puts "Double-clicked row contains name #{iter[0]}!"
self.signal_emit("selected", iter[0])
end
end
end
def signal_do_selected(file)
puts "Selected " + file
#p caller
end
def readDir (root)
Dir.foreach root do |dir|
file = root+'/'+dir
if !FileTest.directory?(file) && dir =~ /\.jpe?g$/ && FileTest.readable?(file)
thumb = getThumbnail(file)
iter = @files.append
iter[0] = file
iter[1] = dir
iter[2] = Gdk::Pixbuf.new thumb
File.delete(thumb)
end
end
end
end
And here's the controller code that binds the signal to some effect::
imageList.signal_connect("selected") do |imagelist, filename|
puts "File #{filename} was clicked!"
image.load(filename)
end
It's quite easy, and (finally!) it does what I want without needing to write thousands of lines of code. YAY! And I finally fulfull my dream of connecting closures instead of callbacks to GTK signals.
Yes, I could have done it in Perl. Yes I could have done it in Python. But Ruby is soo cute!
My curriculum
I finally finished restructuring my curriculum. It needed to have two properties:
- I only want to maintain information once, without copying around and information getting outdated.
- I need translations, and I want to translate using smart tools.
Here's how it works now:
- It all starts with informations scattered around the file system.
- Some Ruby scripts go around digging for them and generate some XML files.
- The XML files have tags with special markers so that intltool can extract the strings inside and generate .pot files with them.
- I translate .pot files with all the tools one normally uses with them.
- Intltool generates multiple XML versions with clean tags and translated strings.
- At this point, I have XSLT sheets that can generate:
- My CV
- The Talks page
- A page with a summary of the free software projects I'm involved in
...and it's all driven by Makefiles.
The day I feel like it, I'll add an XSLT to generate a CV in OpenDocument format.
Javier Candeira called this "Rube Goldberg Hacking", but then noone could figure out simpler ways of doing it with the properties I wanted.
Scripts available on request if someone is crazy enough to walk along a similar path.
Interesting links:
Including inline images in Ruby GTK2
Including inline images in Ruby GTK2
I'm making a simple application and I'd like to keep it self-contained into a single file; however, I'd like to use some custom icons in it.
I tried storing a pixbuf in a string::
ICON = <<EOT
/* XPM */
[...]
};
EOT
icon = Gdk::Pixbuf.new ICON
but it tried to open a file called "/* XPM */\n...."
.
I tried with an array::
icon = Gdk::Pixbuf.new ICON.split("\n")
But I kept getting GdkPixbuf-WARNING **:Inline XPM data is broken: Invalid
XPM header
. Note that trying to write that data to a file and loading the
file, worked.
This worked:
icon = Gdk::Pixbuf.new "pippo.xpm"
This didn't::
tmp = IO.readlines "pippo.xpm"
icon = Gdk::Pixbuf.new tmp
I finally managed using csource:
gdk-pixbuf-csource --raw --name=antani image.png > /tmp/antani
-
insert
/tmp/antani
in the Ruby source code, strip away the comments, concat the various strings:ICON = ""+ "GdkP"+ "\0\0\4\30"+ "\1\1\0\2"+ "\0\0\0@"+ "\0\0\0\20"+ "\0\0\0\20"+ "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"+ [...]
-
load the data with
icon = Gdk::Pixbuf.new ICON.unpack("C*"), true
A possible improvement could be using --rle in gdk-pixbuf-csource: raw is good for avoiding to copy the image data, but I don't feel comfortable in doing it since the image data is an integer array temporarily generated by unpack.
As usual, if you know of better ways please send me a mail and I'll update the blog entry.
drezza - Get a picture collection ready for publishing
I've been having three wishes since some time:
- Lean Ruby
- Find an easy and fast way to find digital camera shoots that need an invocation of exiftran, and invoke it
- Find a comfy way to code user interfaces. In particular, I've always dreamed of sticking closures into event handlers.
I've recently managed to fulfill these three wishes in a single shot by coding drézza, a minimal picture browser with quick links to invoke exiftran. If anyone is wondering, "drézza" means "make it straight" in Bolognese.
It is simple, it is easy, it does all I need: you invoke it and it will show all the pictures in the current directory. If you invoke it with a directory as commandline argument, it will show all the pictures in that directory.
It will display the pictures in a list together with their thumbnail. The thumbnail is taken from the EXIF thumbnail. If a JPEG file has no EXIF thumbnail, it invokes exiftran to generate it.
Clicking on an image in the list shows it in detail. In the toolbar there are buttons to rotate the image with exiftran, which uses a lossless transform and respects exif data.
The tool comes in a single file, no need to install. The source code is clean and commented, and is also a nice demo of various Ruby/GTK2 and Ruby/Gnome2 features and programming tricks, including:
- subclassing GTK widgets
- creating custom signals
- reacting to widget resize
- processing GTK events during long computations
- updating the Gnome status bar
- embedding pixmaps in the source code
- using custom pixmaps for the toolbar
You can get it from http://www.enricozini.org/galleries/drezza.
If you play with it, let me know and I'll keep it up to date.