Friday, February 18, 2011

Exporting slices from Inkscape, part 2

I previously wrote about how to export slices from an Inkscape file, using a bash script. Here's a better script, using Python, which doesn't require you to give your slices any special label.

The new process is as follows:

  • First, draw your image as usual.
  • Then, add a layer that will hold the slices; name it slices (this is important). Set the layer's opacity to about 50% to be able to see what you're doing. Enable the grid, and make sure it is set to pixels: you want your slices to align with pixel boundaries.
  • Draw your slice rectangles onto the slices layer, aligned to the grid. Ensure that the rectangles have no border; the fill is irrelevant (I use red).
  • Right-click a slice, and choose Object Properties. Change Id field to the name of the eventual PNG file, without the extension. The area defined by a rectangle named foo will be saved to foo.png. Repeat this for all slices.
  • Hide the slices layer. If you forget this, the script will print a warning.
  • Save your image. Let's say you called it layout.svg.
  • Run the script as follows:
    ./export.py layout.svg
    You should see each of your slices being exported to a PNG file in the same directory.

Here's the code for the script. Save this to a file export.py and make it executable.

#!/usr/bin/env python

import sys
import os
from xml.dom import minidom

if len(sys.argv) < 2:
    print 'Usage:  %s filename.svg' % sys.argv[0]
    sys.exit(0)
input_file = sys.argv[1]

dom = minidom.parse(input_file)
groups = dom.getElementsByTagName('g')
for group in groups:
    if group.getAttribute('inkscape:groupmode') == 'layer' and group.getAttribute('inkscape:label') == 'slices':
        if 'display:none' not in group.getAttribute('style'):
            print 'Warning: slices layer might still be visible'
        for element in group.getElementsByTagName('rect'):
            export_id = element.getAttribute('id')
            filename = '%s.png' % export_id
            print 'Exporting %s...' % filename
            os.system('inkscape --export-id="%s" --export-png="%s" --file="%s"' % (export_id, filename, input_file))
        break
else:
    print 'No layer named "slices" found; not exporting anything'
    sys.exit(1)

Wednesday, February 2, 2011

Editor's Prick?

Some time ago, I received an e-mail concerning my little open source program Taekwindow:

Monday, Jan 17, 2011, 10:27
From: F.R.
To: me

My name is F., Customer Manager of WareSeeker.com, a professional software directory. I would like to propose a solution to promote your software on our site.

We would like to take this opportunity to introduce ourselves. Wareseeker is one of top 5 professional software directories in the world and currently serving about 2 million page views per day. Many renowned software publishers rely on us as their primary media of promoting their products, thus increasing the sales or download dramatically.

We have tested thoroughly and guarantee that Taekwindow 0.3.1 is 100% SAFE TO INSTALL, which means it does not contain any form of malware: spyware, viruses, trojans and dialers.

Taekwindow 0.3.1 has been received Editor’s Pick Award from us.

We hope that you will gain more benefit through this Award. Moreover, we would like to request you add our link and Editor's Pick icon on your Awards category at http://taekwindow.sourceforge.net/download.html

It's not the first time Taekwindow receives such an award, and they generally don't mean very much. But still, it's a nice gesture, and I've done other download sites the same favour, so I replied in the positive.

Since the Taekwindow site is largely built by an automated build system that only runs on Windows, and I am spending all my time in Linux lately, I did not make any promises when I would get round to it. It would probably have been later that week.

Two days later, I received two e-mails in quick succession.

Wed, Jan 19, 2011, 02:40
From: F.R.
To: me

How about our request of our link and Editor's Pick icon at http://taekwindow.sourceforge.net/download.html

You will do that, ok? but when

Keep contact me

Wed, Jan 19, 2011, 09:46
From: F.R.
To: me

How long you got message of mine? I will remind you in final time for our link and Editor's Pick icon on your site.

Give me the respond when you reached this email

Okay, so he expects me to answer to e-mail within 7 hours and 6 minutes, while I'm asleep. And he's getting pushy. But at least I could tell him that I received his mails.

Wed, Jan 19, 2011, 12:04
From: me
To: F.R.

I got your messages alright. I'm a busy person, and I do not appreciate your impatience about me doing you a favour. Please stop pushing me. I'll get to it as soon as I have time.

I might still have done it later that week, but I didn't get round to it. Today, another e-mail appeared.

Tue, Jan 25, 2011, 02:42
From: F.R.
To: me

I don't know how are you busy, I'm also a busy man with a huge business volume each day but I still spend some minutes to write for me to remind you about our request.

Today If you don't reply my mail, I will remove our award for your product on my site. Contact me immediately when you reached this mail

Is that how you treat people when you want them to do you a favour? Not appreciated.

Tue, Jan 25, 2011, 11:45
From: me
To: F.R.

Dear Mr. R.,

The usual nature of awards is that they are given without requesting anything in return. In spite of that, I graciously agreed to return the favour, although due to other obligations I couldn't say when. After a few days, a gentle reminder might certainly have been appropriate. However, two reminders within eight hours (during which I was asleep, I might add), of an increasingly unfriendly nature, did not increase the likelihood that I would answer to your request. Your further pushy behaviour did not improve the situation, and now you request has turned into a demand, with a corresponding punishment should I not comply.

I noticed that Taekwindow has received 13 downloads through your site, and this number has not changed in the last few days. Compared to 149 downloads at Softoxi and 1121 downloads at Softpedia, I doubt there is much value for Taekwindow to be hosted on your site. Given the apparent attitude of the site's employees, it might even do more harm than good.

If it must be like this, I would prefer not to have anything to do with you or your site anymore. I have removed the staged modifications to the Taekwindow website. I will now proceed to write a post about our exchange on my blog, which receives a moderate amount of traffic. Good luck with your future endeavours.

Sincerely,

Thomas

P.S. Incidentally, the download page for Taekwindow on WareSeeker reads: "Software piracy is theft, Using crack, password, serial numbers, registration codes, key generators, cd key, hacks is illegal and prevent future development of Taekwindow 0.3.1 Edition." None of these statements are true. Software piracy may be considered a crime in most countries, but it is distinct from theft. The use of password[s], serial numbers, registration codes and/or cd keys is often a part of software installation required by the software's manufacturer, without which the software will not function, so this can hardly be considered illegal. Finally, the use of any of these will not impact the future development of Taekwindow 0.3.1 in the slightest.

Here's that blog post. See? I do keep my promises — mostly.

Saturday, October 9, 2010

Installing Rails 3 in Ubuntu 10.4

For the record, and for those of my friends who are going to participate in the Rails Rumble next weekend: here's how you install Rails 3 on your Ubuntu Karmic system. (10.10, known as Maverick, is supposed to arrive tomorrow and might make this post obsolete. But I won't be risking an upgrade before the weekend.)

  1. Install Ruby; apt contains the required version:
    sudo apt-get install ruby
  2. Uninstall RubyGems, because we'll install a more recent version from source:
    sudo apt-get remove rubygems
  3. Install RubyGems from source:
    cd /tmp
    wget http://production.cf.rubygems.org/rubygems/rubygems-1.3.7.tgz
    tar xzf rubygems-1.3.7.tgz
    cd rubygems-1.3.7
    sudo ruby setup.rb
    sudo ln -s gem1.8 /usr/bin/gem
  4. Install Rails:
    sudo gem install rails

Sunday, July 18, 2010

Exporting slices from Inkscape

If you have a Python interpreter available, you can use the slightly better alternative from Part 2.

In Photoshop, it's possible to “slice” an image into pieces, name the individual pieces, and export each to a separate file. This is really useful for web design: you can do the whole design in one image, then export the bits and pieces for later reassembling in HTML/CSS. Can we do the same slicing trick with Inkscape?

It turns out that we can; it's even on the Inkscape Tips and Tricks page. However, the exporting itself remains manual labour. I wrote a bash script to automate that; the code is given below.

The process is as follows:

  • First, draw your image as usual.
  • Then, add a layer that will hold the slices; name it, for example, slices. Set the layer's opacity to about 50% to be able to see what you're doing. Enable the grid, and make sure it is set to pixels: you want your slices to align with pixel boundaries.
  • Draw your slice rectangles onto the slices layer, aligned to the grid. Ensure that the rectangles have no border; the fill is irrelevant (I use red).
  • Right-click a slice, and choose Object Properties. Change Id field to EXP-something and hit Enter. The tag EXP- indicates that this rectangle is intended for export; something will become the filename (something.png). Repeat this for all slices.
  • Hide the slices layer, and save your image. Let's say you called it layout.svg.
  • Run the script as follows:
    ./export.sh layout.svg
    You should see each of your slices being exported to a PNG file in the same directory.

Here's the code for the script. Save this to a file export.sh and make it executable.

#!/bin/bash

if [[ -z $1 ]] ; then
 echo "Usage: $0 [FILE]"
 exit 0
else
 FILENAME=$1
fi

PREFIX=EXP-

for ID in `grep -o "id=\"$PREFIX.*\"" $FILENAME | cut -d\" -f2` ; do
 OUTPUT=${ID#$PREFIX}.png
 echo "Exporting area $ID to $OUTPUT..."
 inkscape --export-id=$ID --export-png=$OUTPUT --file=$FILENAME
done

Thursday, May 20, 2010

Are C++ iostreams really slow?

In the C++ world, one often hears the statement “iostreams are slow, you should use printf instead”. Is this true?

It is possible that this story results from abuse of endl. Beginner's C++ books often recommend endl over '\n' for writing a newline. The observable result is often the same, but endl results in extra overhead: it flushes the stream. This results in a system call, slowing things down while often unnecessary.

Using my newly written TimedSection class, I tested whether the story is actually true, or just a myth. I tried three methods of printing:

  • cout with endl for line endings
  • cout with '\n' for line endings
  • printf (also with '\n' for line endings, so no forced flushing)

Each of these was tested in the following scenarios:

  • printing an empty line
  • printing a line containing a string literal
  • printing a line containing a string variable, a string literal, and an integer variable

All strings used were 20 characters long; I figured this would be a typical average length for printing messages. Newline characters were absorbed into string constants wherever possible.

Each of these was run 10 million times, redirecting the output to /dev/null. The testing machine is an Intel i7 920, running Ubuntu 10.4, Linux 2.6.32 and gcc 4.4.3.

Here are the results:

cout with only endl                     1461.310252 ms
cout with only '\n'                      343.080217 ms
printf with only '\n'                     90.295948 ms
cout with string constant and endl      1892.975381 ms
cout with string constant and '\n'       416.123446 ms
printf with string constant and '\n'     472.073070 ms
cout with some stuff and endl           3496.489748 ms
cout with some stuff and '\n'           2638.272046 ms
printf with some stuff and '\n'         2520.318314 ms

Surprise! Yes, for printing newlines, printf greatly outperforms cout. We can also see the huge slowdown of using endl inappropriately, something which is clearly to be avoided.

However, even for printing a moderately-sized string constant, cout outperforms printf. This effect becomes more pronounced as the string gets longer, probably because printf has to do more processing per character.

Finally, for some slightly more complicated formatting, the difference is quite small. For longer string constants, it becomes even smaller.

We can conclude that iostreams are definitely not always slower than C-style printf. It depends on the particular use, and as the formatting becomes more complicated, the difference drops to zero. Part of the myth may be ascribed to inappropriate use of endl; maybe another part is due to unoptimized implementations of the standard library. Either way: myth busted.

Update: For the curious, here is the full source code. You may need to link with -lrt to get clock_gettime.

#include <stdio.h>
#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    timespec d_start;
    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            clock_gettime(CLOCK_REALTIME, &d_start);
        }
        ~TimedSection() {
            timespec end;
            clock_gettime(CLOCK_REALTIME, &end);
            double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
            std::cerr << d_name << '\t' << std::fixed << duration << " ms\n"; 
        }
};

int main() {
    const int iters = 10000000;
    char const *text = "01234567890123456789";
    {
        TimedSection s("cout with only endl");
        for (int i = 0; i < iters; ++i)
            std::cout << std::endl;
    }
    {
        TimedSection s("cout with only '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << '\n';
    }
    {
        TimedSection s("printf with only '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("\n");
    }
    {
        TimedSection s("cout with string constant and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789" << std::endl;
    }
    {
        TimedSection s("cout with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789\n";
    }
    {
        TimedSection s("printf with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("01234567890123456789\n");
    }
    {
        TimedSection s("cout with some stuff and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << std::endl;
    }
    {
        TimedSection s("cout with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << '\n';
    }
    {
        TimedSection s("printf with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("%s01234567890123456789%i\n", text, i);
    }
}

Timing a section of code in C++

Sometimes it's useful to measure how long a certain part of your C++ code takes to execute. Here's a little utility class that makes this extremely easy. It can be used like this:

void foo() {
    TimedSection s("foo()");
    // do some long operation...
}

Calling foo() will print something like this to stderr:

foo()   336.856127 ms

As you may have guessed, a TimedSection records the time between its construction and its destruction. Since C++ has no garbage collection, destructors are called at a deterministic moment: when the local object (called s above) goes out of scope. If you want to time a section that is not a scope by itself, you can introduce a pair of braces to scope the object. If the section is even more complex (e.g. spanning multiple functions), you can use new and delete, but that destroys the elegant simplicity of TimedSection's usage.

The implementation is rather simple as well:

#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    timespec d_start;
    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            clock_gettime(CLOCK_REALTIME, &d_start);
        }
        ~TimedSection() {
            timespec end;
            clock_gettime(CLOCK_REALTIME, &end);
            double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
            std::cerr << d_name << '\t' << std::fixed << duration << " ms\n"; 
        }
};
I hereby release this little code snippet into the public domain. Enjoy!

Monday, April 5, 2010

So long, and thanks for all the glass

When I first installed Windows 7 after nearly a decade of using XP, I decided I'd not customize it. I'd just leave the settings at their default values and see what the wise men at Microsoft had decided for me. After all, there are thousands of hours of usability testing behind those decisions, so it seemed a good idea to give them a chance.

Now, half a year later, I've gotten used to most of Windows 7. Although I've tweaked the occasional thing here and there (show me the damn file extensions already!), I think most of it is pretty reasonable. But there's one thing I just can't get used to: the Aero theme.

It's not that it's semi-transparent. It's not that it fades and zooms and zips and zaps. It's just the minor little thing that I can't see the difference anymore between active and inactive windows.

When you activate a window, the title bar and borders become a little bit darker, the shadow becomes a little bit blacker, and the close button changes its colour from glassy to red. You can see the changes happen while you're switching focus, but telling the difference at a glance from a static image is hard. And because the title bar is transparent, the colour depends on the things behind it, making it even harder. There's just no single, consistent look for active and inactive title bars. I kept having to look at the close button to tell which window was active.

The subtle difference between an inactive and active title bar in Windows Aero

So what am I to do? Am I to magically know which window is active? When I've just clicked it, or when I'm typing into it, sure, I'll know. But being the Alt+Tab guy that I am, I shift focus without clicking all the time, and not always to the correct window right away. And what if some unexpected window suddenly pops up that might have stolen my focus, like an auto-updater? How can I tell if I can continue typing, or that I'd better yank my hands away from the keyboard in case I inadvertedly activate the Launch Nukes button?

Unfortunately, there is no way to change the look. The wise men at Microsoft have decided that a “theme” will be nothing more than a single colour for the glass, along with a set of wallpapers. There's no way to select different colours for active and inactive windows, like there is for the “classic” themes. There's also no way to install a clearer Aero theme without resorting to commercial third-party software like WindowBlinds.

So in the end, after my millionth focus fuckup, I switched back to the classic Windows 2000 lookalike theme. Blue versus gray seems like a distinction my eyes can handle.

Why do I have to sacrifice good looks to gain usability? Why can't Microsoft just make them get along?