2012-12-29

ImageMagick, making glyphs transparent

I've been installing the WikiHiero extension used in Wikipedia and because my webpage has a non-white background, and since the images of the hieroglyphs have a white background, it didn't look that good. So, I made some research for how to convert the images to transparent, and to make a grey-scale mask for smooth anti-aliased edges.

There are about 1,000 images in the map, but the execution went in a second or so, it's really quick. The first command creates the mask:

$ for file in hiero_*.png; do convert $file -negate mask_$file.png; done

Then apply the mask to the image:

$ for file in hiero_*.png; do convert $file -alpha Off \
> mask_$file.png -compose CopyOpacity -composite $file; done

That's it, now all images have a nice transparency:

Cross Compiling and Pkg-config

My host is Ubuntu 64, and target Win32 using MinGW32, for the examples in this article. Also it is assumed that the mingw32 target is named i686-w64-mingw32, so if it isn't, just substitute with the target on your system.

When running a Makefile targeted for cross compilation, pkg-config is unfortunately not looking in the mingw32-directory by itself by just installing mingw32. You will have to somehow redirect it. One way is to create a shell script and place with your ming32-gcc. Name the script with the same name pattern as your mingw32-gcc, on my system it's i686-w64-mingw32-gcc, so name it i686-w64-mingw32-pkg-config.

The script that I ended up with that works for me looks like this:

#!/bin/bash
MINGW_ROOT=/usr/i686-w64-mingw32
export PKG_CONFIG_LIBDIR=${MINGW_ROOT}/lib/pkgconfig
export PKG_CONFIG_PATH=${MINGW_ROOT}/share/pkgconfig
pkg-config --define-variable=prefix=${MINGW_ROOT} $@

Since I've chosen to use CMake instead of autotools for my projects, this script isn't called because CMake works in a different way. CMake finds the correct pkgconfig path, but often the .pc-files has an erroneous prefix, which is fixed in the script above by calling pkg-config with the flag --define-variable=prefix=${MINGW_ROOT}. Instead we have to edit the .pc-files and correct the prefix. In my lib/pkgconfig directory there are 190 .pc-files, but we can do this with a file search and regex substitution.

$ find /usr/i686-w64-mingw32/lib/pkgconfig -type f -exec sed \
> -i "s/^prefix=.*$/prefix=\/usr\/i686-w64-mingw32/g" {} \;

This will work in some lucky situations, but have a look at this gtk+-2.0.pc and you'll see why it won't work always:

prefix=/usr/i686-w64-mingw32/sys-root/mingw
exec_prefix=/usr/i686-w64-mingw32/sys-root/mingw
libdir=/usr/i686-w64-mingw32/sys-root/mingw/lib
includedir=/usr/i686-w64-mingw32/sys-root/mingw/include
target=win32

gtk_binary_version=2.10.0
gtk_host=i686-w64-mingw32

Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.24.10
Requires: gdk-${target}-2.0 atk cairo gdk-pixbuf-2.0 gio-2.0
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0 -mms-bitfields

The prefix isn't used by the other variables, so how do we fix this then? If we know the prefix and also knows that it's the same in all .pc-files, then we can replace it with a regex, but if it's not, and we may not be sure and checking 190 files is a bit tiresome, it's not a good solution. We'll have to find the prefix, replace it with the correct prefix and then replace all other instances of the prefix directory with '${prefix}'. This script will do the trick:

#!/usr/bin/perl
my $prefix = shift;
my $dir = "$prefix/lib/pkgconfig";
opendir(DIR, $dir) or die $!;
my @files = grep { /\.pc$/ && -f "$dir/$_" } readdir(DIR); 

closedir(DIR);

foreach my $fn (@files) {
    my ($file,$p,$fp);
    open($fp, "<$dir/$fn") or die $!;
    local $/;
    $file = <$fp>;
    close($fp);

    # Substitute 'prefix=(.*)' with a dummy tag, and store prefix in $p:
    if($file =~ s/\bprefix\=(.*)\b/$p=$1;"\$prefix"/e) {
        $file =~ s/$p/\$\{prefix\}/g; # Substitute $p with '${prefix}'
        $file =~ s/\$prefix/prefix=$prefix/; # Replace dummy tag
        open(OUTFILE,">$dir/$fn") or die $!;
        print OUTFILE $file;
        close(OUTFILE);
    }
}

Save this script as pkg-config-fix.pl and run (for safety's sake, make a backup of the files in /usr/i686-w64-ming32/lib/pkgconfig):

$ sudo chmod +x pkg-config-fix.pl
$ ./pkg-config-fix.pl /usr/i686-w64-mingw32
Have a look at gtk+-2.0.pc, it should look like this:
prefix=/usr/i686-w64-mingw32
exec_prefix=${prefix}
libdir=${prefix}/lib
includedir=${prefix}/include
target=win32

gtk_binary_version=2.10.0
gtk_host=i686-w64-mingw32

Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.24.10
Requires: gdk-${target}-2.0 atk cairo gdk-pixbuf-2.0 gio-2.0
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0 -mms-bitfields

The script is safe to run several times if you install new packages. Now CMake will work properly and find all libraries and headers.

2012-12-28

Fontconfig error: Cannot load default config file

I got this error when starting a GTK+ application:

Fontconfig error: Cannot load default config file

It means that the fonts.conf file can't be found by Fontconfig. A fonts.conf file has to be installed in the C:\WINDOWS directory (or anywhere really). Then open regedit and add a couple of keys.

Windows:

$ regedit

Wine:

$ wine regedit

Open: HKEY_CURRENT_USER\Environment

Add the keys:

FONTCONFIG_FILE => C:\WINDOWS\font.conf
FONTCONFIG_PATH => C:\WINDOWS

The fonts.conf file is an XML-document, it should look something like this on windows:




    C:\WINDOWS\fonts
    C:\WINDOWS\Cache\Fontcache
    C:\WINDOWS\Cache\Fontcache

    
    Z:\usr\share\fonts
    Z:\usr\local\share\fonts
    Z:\usr\X11R6\lib\X11\fonts

MinGW32, Cross Compile Packages

Well, so I've been looking around for packages to build a cross compile environment. It was just a complete mess finding the correct DLLs, or having to compile one package only to find out it needed thirty other packages that also needed compiling, because precompiled packages wouldn't be compatible.

There are plenty of excellent guides on how to set up a cross compile environment. I'm not going to explain this here. My host is Ubuntu 64, and my target Win32.

Nobody ever wrote in any guide, that Fedora has all the mingw32 packages neatly compiled and ordered all over the web. There are massive numbers of FTP-servers mirroring hundreds of mingw32 packages, so no need to compile anything, and all DLLs are compatible! What a waste of time, spent on finding this out!

All that is needed is to open FileZilla (or whichever your FTP-client is), locate the local FTP-server (which since I live in Stockholm is ftp.sunet.se), find the right directory and download galore. The right directory is usually something similar to "/pub/.../fedora/.../i386/.../". Google "fedora mingw32 glib rpm" and you'll get a number of pages listing ftp-servers. Look at the URL where the file is located, and in the same directory you'll find the rest of the mingw32 packages. You won't need any password to open the server with your FTP-client.

The packages are RPM-files, incompatible with Ubuntu, but easily extracted with for example File Roller. They usually extract to a directory similar to "/usr/i686-w64-mingw32.../mingw/" (with a few "/usr/bin" and "/usr/share" that you can safely ignore, only the files in the ".../mingw/" directory is of interest) and so the files are simply moved to the mingw32 directory, which happens to be /usr/i686-w64-mingw32 on my computer.

Most pkgconfig files need to be corrected, so that the compiler will find the right libraries and headers. There's a simple command to correct all .pc files at once:

$ find /usr/i686-w64-mingw32/lib/pkgconfig -type f -exec sed \
> -i "s/^prefix=.*$/prefix=\/usr\/i686-w64-mingw32/g" {} \;

This command lists all files in the pkgconfig directory, and executes a regex replace. This will do the trick, at least most of it. If it doesn't, adjust the regex segment, or simply edit the files manually.

After this, cross compiling runs smoothly.