[disclaimer]


This is a personal blog. The opinions expressed here represent my own and not those of any of my employers or customers.

Except if stated otherwise, all the code shared is reusable under a MIT/X11 licence. If a picture is missing a copyright notice, it's probably because I'm owning it.

Tuesday, March 10, 2009

A gift to the competition

For once, I didn't spend my weekends hacking time on patches for F-Spot. Instead, in my journey addressing an old and vocal request, I ended up writing xcf files support for eog, gthumb, gqview, F-Spot obviously and maybe some more.

The code for this is a GdkPixbuf loader, based on this specification (moved there since) and some xcf hexdumps, meaning it's suitable to be released under the LGPL for gdk-pixbuf inclusion. (Googling around, I found some mail archives stating that the GPL(The Gimp)/LGPL (gdk-pixbuf) issue was preventing the inclusion of a loader based on The Gimp's code in gdk).

Features:
  • read xcf files up to v002,
  • compressed and rle-encoded,
  • grayscale and rgb color modes,
  • supports all kinds of layer blending,
  • supports layer masks
TODO:
  • .xcf.gz and .xcf.bz2 support (for jimmac),
  • indexed mode


Clone this piece of awesomeness from git://gitorious.org/xcf-pixbuf-loader/mainline.git and report bugs by e-mail. Build it, copy the .so next to the others loaders on your system and run gdk-pixbuf-query-loaders[-64].

(Get the sample file I used for those screenshots from there)

23 comments:

  1. What a coincidence: only yesterday I was annoyed by the fact nautilus could show me XCF thumbnails, but eog couldn't. And today I see this blog post. Seriously cool.

    ReplyDelete
  2. I tried it, and it seems to work okay for basic files. Great, many thanks for your work!

    However, I have a (quite big) file here that doesn't show up correctly, though. Please let me know if you want me to send you that file, so that you can investigate the issue. If so, mail me at wbolster, gnome, org — I won't be reading new reactions to this blog post.

    ReplyDelete
  3. That is very cool!
    This was on my wish-list for a very long time, thank you for the work.

    ReplyDelete
  4. XCF is still a rubbish format for document exchange - PSD is unfortunately still the defacto standard - but thank you for making the whole process a little less unpleasant.

    ReplyDelete
  5. @Wouter: fixed

    @OpenRaster: I'm aware of some plans to replace the xcf format. But I'm not really expecting anything in the coming 2 years. For the time being, this small loader could help loading your own (Gimp) files in a picture management application.

    ReplyDelete
  6. This is a very nice addition to the PSD pixbuf loader (http://code.google.com/p/gdk-pixbuf-psd/). Now i can view files from the indutry and open standrd of imageing :) Great work!!!

    ReplyDelete
  7. Great stuff Stephane!

    This reminds me of the time a few years back when there was a bit of a ruckus over the XCF format and Henning wrote the spec: http://blogs.gnome.org/bolsh/2006/06/19/the-gimps-xcf-file-format/ and http://blogs.gnome.org/bolsh/2006/07/12/xcf-update/ has the story.

    From the first blog entry, I said: "For the record, I disagree (and have always done so) with the policy of discouraging other applications from using XCF. When something better comes along, we can abstract file load & save to a library, and everyone can use it. Until then, if someone wants to write a libxcf, why not? I’m all for interoperability where practical." It's a pity that didn't get done, but I'm really happy that you took on the job.

    Dave.

    ReplyDelete
  8. @Stephane
    How to built a binary? I'm using Ubuntu 8.04.
    I tried a simple "make" and getting the message a no targets message. The ./autogen.sh ends with:

    configure.ac:8: error: possibly undefined macro: AC_PROG_LIBTOOL

    and

    configure: error: cannot find install-sh or install.sh

    Please can you help me.
    Thanks.

    ReplyDelete
  9. @Dave: Thanks for your support :) I kind of agree with The Gimp devs when they say that xcf is not the greatest interchange format, and would be happy if they switch to anything gegl/xml/openraster/whatever based. But in the meantime, The Gimp produces images that needs to be viewable by _image_ viewers.

    @Bart: you're probably missing some pieces to build it. Make sure you get recent autoconf and automake

    ReplyDelete
  10. Great work! But unfortunately make fails for me:

    /bin/bash ./libtool --mode=compile gcc -DPACKAGE_NAME=\"io-xcf\" -DPACKAGE_TARNAME=\"io-xcf\" -DPACKAGE_VERSION=\"0.0.1\" -DPACKAGE_STRING=\"io-xcf\ 0.0.1\" -DPACKAGE_BUGREPORT=\"stephane@delcroix.org\" -DPACKAGE=\"\" -DVERSION=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_LIBBZ2=1 -I. -I. -g -c io-xcf.c
    libtool: compile: gcc -DPACKAGE_NAME=\"io-xcf\" -DPACKAGE_TARNAME=\"io-xcf\" -DPACKAGE_VERSION=\"0.0.1\" "-DPACKAGE_STRING=\"io-xcf 0.0.1\"" -DPACKAGE_BUGREPORT=\"stephane@delcroix.org\" -DPACKAGE=\"\" -DVERSION=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DLT_OBJDIR=\".libs/\" -DHAVE_LIBBZ2=1 -I. -I. -g -Wp,-MD,.deps/io-xcf.pp -c io-xcf.c -fPIC -DPIC -o .libs/io-xcf.o
    io-xcf.c:41:21: error: gmodule.h: No such file or directory
    io-xcf.c:42:35: error: gdk-pixbuf/gdk-pixbuf.h: No such file or directory
    io-xcf.c:43:38: error: gdk-pixbuf/gdk-pixbuf-io.h: No such file or directory
    io-xcf.c:117: Fehler: expected specifier-qualifier-list before »GdkPixbufModuleSizeFunc«
    io-xcf.c:130: Fehler: expected specifier-qualifier-list before »guint32«
    io-xcf.c:139: Fehler: expected specifier-qualifier-list before »guint32«
    io-xcf.c:153: Fehler: expected declaration specifiers or »...« before »gchar«
    io-xcf.c: In Funktion »rle_decode«:
    io-xcf.c:165: Fehler: »guchar« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:165: Fehler: (Jeder nicht deklarierte Bezeichner wird nur einmal aufgeführt
    io-xcf.c:165: Fehler: für jede Funktion in der er auftritt.)
    io-xcf.c:165: Fehler: expected »;« before »opcode«
    io-xcf.c:166: Fehler: expected »;« before »buffer«
    io-xcf.c:167: Fehler: expected »;« before »ch«
    io-xcf.c:174: Fehler: »opcode« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:176: Fehler: »buffer« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:179: Fehler: »ch« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:204: Fehler: »ptr« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c: Auf höchster Ebene:
    io-xcf.c:208: Fehler: expected »)« before »*« token
    io-xcf.c:238: Fehler: expected »)« before »*« token
    io-xcf.c:246: Fehler: expected declaration specifiers or »...« before »gchar«
    io-xcf.c:246: Fehler: expected declaration specifiers or »...« before »guchar«
    io-xcf.c: In Funktion »apply_mask«:
    io-xcf.c:251: Fehler: »guint32« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:251: Fehler: expected »;« before »tptr«
    io-xcf.c:252: Fehler: »tptr« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:256: Fehler: »gchar« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:256: Fehler: expected »;« before »pixels«
    io-xcf.c:257: Fehler: »compression« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:258: Fehler: »pixels« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c:258: Fehler: zu viele Argumente für Funktion »rle_decode«
    io-xcf.c:264: Fehler: »ptr« nicht deklariert (erste Benutzung in dieser Funktion)
    io-xcf.c: Auf höchster Ebene:
    io-xcf.c:272: Fehler: expected »)« before »*« token
    io-xcf.c:298: Fehler: expected »)« before »*« token
    io-xcf.c:306: Fehler: expected »)« before »*« token
    io-xcf.c:309: Fehler: expected »)« before »*« token
    io-xcf.c:317: Fehler: expected »)« before »*« token
    io-xcf.c:325: Fehler: expected »)« before »*« token
    io-xcf.c:335: Fehler: expected »)« before »*« token
    io-xcf.c:343: Fehler: expected »)« before »*« token
    io-xcf.c:353: Fehler: expected »)« before »*« token
    io-xcf.c:361: Fehler: expected »)« before »*« token
    io-xcf.c:369: Fehler: expected »)« before »*« token
    io-xcf.c:377: Fehler: expected »)« before »*« token
    io-xcf.c:385: Fehler: expected »)« before »*« token
    io-xcf.c:393: Fehler: expected »)« before »*« token
    io-xcf.c:401: Fehler: expected »)« before »*« token
    io-xcf.c:409: Fehler: expected »)« before »*« token
    io-xcf.c:417: Fehler: expected »)« before »*« token
    io-xcf.c:427: Fehler: expected »)« before »*« token
    io-xcf.c:454: Fehler: expected »)« before »*« token
    io-xcf.c:482: Fehler: expected »)« before »*« token
    io-xcf.c:510: Fehler: expected »)« before »*« token
    io-xcf.c:527: Fehler: expected »)« before »*« token
    io-xcf.c:773: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »*« token
    io-xcf.c:1168: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »*« token
    io-xcf.c:1267: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »xcf_image_begin_load«
    io-xcf.c:1303: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »xcf_image_stop_load«
    io-xcf.c:1327: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »xcf_image_load_increment«
    io-xcf.c:1418: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »void«
    io-xcf.c:1426: Fehler: expected »=«, »,«, »;«, »asm« or »__attribute__« before »void«
    make: *** [io-xcf.lo] Fehler 1

    ReplyDelete
  11. @Andreas: I added a check for gmodule in configure script, but your issue is there:
    io-xcf.c:41:21: error: gmodule.h: No such file or directory
    io-xcf.c:42:35: error: gdk-pixbuf/gdk-pixbuf.h: No such file or directory
    io-xcf.c:43:38: error: gdk-pixbuf/gdk-pixbuf-io.h: No such file or directory

    ReplyDelete
  12. Hello Stephane,
    i get it compiled yet, thanks for your help! But where to copy the binaries on Ubuntu 8.04? I tried to copy it to "/usr/lib/gtk-2.0/2.10.0/loaders" (like the PSD pixbuf loader) but without luck. It didn't work :(
    Do you have any idea?

    ReplyDelete
  13. @Bart: run gdk-pixbuf-query-loaders ...

    ReplyDelete
  14. Hello Stephan,

    thanks again but i'm getting this error:

    g_module_open() failed for /usr/lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xcf.so: /usr/lib/gtk-2.0/2.10.0/loaders/libpixbufloader-xcf.so: undefined symbol: g_set_error_literal
    g_module_open() failed for /usr/lib/gtk-2.0/2.10.0/loaders/libioxcf.so: /usr/lib/gtk-2.0/2.10.0/loaders/libioxcf.so: undefined symbol: g_set_error_literal

    :(

    ReplyDelete
  15. Just stumbled across this. I've build and installed it. gdk-pixbuf-query-loaders-32 (Fedora 10) shows it as present:

    "/usr/lib/gtk-2.0/2.10.0/loaders/libioxcf.so"
    "xcf" 0 "gtk20" "The XCF (The Gimp) image format" "LGPL"
    "image/x-xcf" "image/x-compressed-xcf" ""
    "xcf" "xcf.bz2" ""
    "gimp xcf" "" 100
    "BZh" "" 80

    But it doesn't seem to change anything. Geeqie (and GQView), and EOG all display a broken thumbnail or throw errors.

    Any ideas?

    ReplyDelete
  16. @Jon: drop me a mail with the error log

    ReplyDelete
  17. @Stephane: Resolved: I needed to run update-gdk-pixbuf-loaders. It now works perfectly...

    Thanks. You are a genius!

    ReplyDelete
  18. This did not work in ubuntu 7.10 until I ran this command:

    sudo gdk-pixbuf-query-loaders > /etc/gtk-2.0/gdk-pixbuf.loaders

    Now it seems to be working. I'm not sure if newer version of Ubuntu need this or not.

    Thanks Stephane!!!!!!

    ReplyDelete
  19. guys, read the blog post up to the end, so you'll know you have to run gdk-pixbuf-loader[-64]

    ReplyDelete
  20. @Stephane

    The blog post has "gdk-pixbuf-query-loaders[-64]" instead of "update-gdk-pixbuf-loaders". I tried both of these commands and neither of them worked. After some searching, I found the command I posted and it worked.

    It looks like the update-gdk-pixbuf-loaders script should do the exact same thing as the command I posted, but it doesn't. Must be a bug in Ubuntu 7.10 or a problem with my environment.

    I think the blog post should have the update command instead of the query command but I could be wrong.

    Thanks again. I like being able to see my gimp images in gnome apps.

    ReplyDelete
  21. Thanks Stephane! Others might find it useful to see exactly what I did to get it working on Ubuntu 9.04:

    > sudo apt-get install git-core autoconf libtool
    > sudo apt-get install libgtk2.0-dev libbz2-dev
    > cd ~
    > git clone git://gitorious.org/xcf-pixbuf-loader/mainline.git pixbuf
    > cd pixbuf
    > ./autogen.sh
    > make
    > cd .libs
    > sudo cp libioxcf.so /usr/lib/gtk-2.0/2.10.0/loaders
    > sudo gdk-pixbuf-query-loaders libioxcf.so
    > sudo gdk-pixbuf-query-loaders > /etc/gtk-2.0/gdk-pixbuf.loaders

    The only problem I had was that grayscale xcf images were somewhat garbled, but I'll take that over what I had before (which was nothing). :)

    ReplyDelete
  22. Thank you!

    But this solves only half of my problem How do I get the xcf file into the database of f-spot?

    ReplyDelete
  23. (Apologize if this is old news)

    Just want to say, Thanks for this!

    It is now available as an RPM.

    sudo yum install xcf-pixbuf-loader

    I had to run this to get it to work:

    sudo gdk-pixbuf-query-loaders-64 --update-cache

    I also had to restart Gnome - I think, I run Enlightenment, so not entirely sure - I exited Enlightenment, entered Gnome, exited, entered Enlightenment and it works.

    ReplyDelete