Technomancy

I'm going to FOSDEM!

written by rory, on Jan 13, 2009 5:54:51 PM.

I'm going to FOSDEM! :) I'm going to FOSDEM, the Free and Open Source Software Developers' European Meeting

How to upgrade Zine

written by rory, on Jan 11, 2009 3:03:00 PM.

When I initially installed Zine, I used the latest version, 0.1.1. There was a bug in it where you couldn't get a feed for a tag However when 0.1.2 was released, it fixed this bug, so I needed to upgrade Zine. I am using Zine through WSGI. I had configured it to be installed in /usr/local/, i.e. I had installed it with
$ unzip Zine-0.1.1.zip
$ cd Zine-0.1.1
$ ./configure --prefix=/usr/local/
Generated Makefile
type "make install" to install Zine
$ sudo make install
Installing to /usr/local
Using /usr/bin/python
All done.
In order to upgrade, I did something similar.
$ wget http://zine.pocoo.org/releases/Zine-0.1.2.zip
$ unzip Zine-0.1.2.zip
$ cd Zine-0.1.2
$ ./configure --prefix=/usr/local/
Generated Makefile
type "make install" to install Zine
Before installing the new version, I uninstalled the old version. I'm not sure if this is required, I just did it out of habit. In order to do this you need to keep the old Zine-0.1.1 directory around. i.e. don't delete that directory after installing.
$ cd ../Zine-0.1.1
$ sudo make uninstall
[: 7: ==: unexpected operator
Uninstalling Zine from /usr/local
All done.
I'm not sure what that error message is, however I was able to upgrade successfully. Then you need to install the new version.
$ cd ../Zine-0.1.2
$ sudo make install
Installing to /usr/local
Using /usr/bin/python
All done.
You then need to restart apache.
$ sudo /etc/init.d/apache2 restart
 * Restarting web server                                  [ OK ]
After that you should be using the latest version of Zine. You can check the version installed from the Admin page, through the System -> Information page.

reCAPTCHA Zine plugin done

written by rory, on Jan 11, 2009 1:51:00 AM.

I have completed my reCAPTCHA Zine plugin, and I've installed it on this site, so you'll have to enter a captcha in order to post comments. The code is kept under git, and is available here: http://repo.or.cz/w/recaptcha_spam_plugin.git. Feel free to check it out and make improvments.

How to go back in time in a git repository

written by rory, on Jan 9, 2009 2:11:24 PM.

I frequently use git to manage files that are not source code. For example, if I'm doing a lot of data processing on files, I like having the whole thing under git. This way I can add files, rename files, and keep the whole thing under git. I can use git's branching to say "These are the files I'm working on now, and these are the versions of the files that are in use on this system". I was also safe in the knowledge that I could delete files and know they were still around somewhere. Today I needed to look at these old versions of files. When you're creating a new branch with git, normally you create it based on the the current branch you have checked out, i.e. this is where the fork in the road is. However with git, you can branch from any point. So in order to go back in time, you can just create a branch from where you want to 'rewind to' and switch to that branch. All your current versions of files are kept in a different branch so are safe. Firstly check the logs to get the commit id of where you want to go back in time to.
$ git log
...

commit 31d4a2f7d06d3ed8d7af62055370a5914029040d
Author: Rory McCann <rory@technomancy.org>
Date:   Tue Jan 6 09:59:56 2009 +0000

    Removed these unneeded files

commit c19940a4b0e0623a131a923083b72f26b8a1b2f8
Author: Rory McCann <rory@technomancy.org>
Date:   Tue Jan 6 09:57:34 2009 +0000

    Added new CSV files

...
So I want to see the CSV files that I removed, so I want to go back in time to commit c19940a4b0e0623a131a923083b72f26b8a1b2f8. So I branch from that point and call it "my-old-files". That's the name of the branch that has the version of your files at that commit.
$ git branch my-old-files c19940a4b0e0623a131a923083b72f26b8a1b2f8
$ git checkout my-old-files
Switched to branch "my-old-files"

Scale an image to fit under a certain size

written by rory, on Jan 7, 2009 5:07:00 PM.

Many times you have an image that is of a certain size, but you need it to be less than a certain size. For example, photos uploaded to Flickr must be under 20 MiB. You can take a guess as to how much you can resize an image by, however most of the time you would like the image as large as possible, but still be under the required size. This is a little script that will try to find the largest resize that keeps the image under a certain size. It does this by doing a binary search on possible resize values (ie from 0% to 100%). It will always return an image that is less than or equal to the required max size.

Usage

$ image-max-size.py -h
Usage: image-max-size.py [options]

Options:
  -h, --help            show this help message and exit
  -s SIZE, --size=SIZE  Max size of the image (in MiB)
  -i IMAGE, --input-image=IMAGE
                        Filename of the image to use
  -o FILENAME, --output-image=FILENAME
                        Filename of the resultant image, it must not already
                        exist
  -a ACCURACY, --accuracy=ACCURACY
                        The accuracy to try for. This is a floating point
                        number between 0.0 and 1.0. The lower the value the
                        longer the programme will run for, but the result will
                        be closer to the target size. The default of 0.01 is
                        usually adequate.

Example Usage

$ image-max-size.py -i big-image.png -o smaller-image.png -s 10
Input file is of size 21.55 MiB which is 11.55 MiB (2.2x) too large
Scaling by 50% gives a size of 5.43 MiB, the file could be 4.57 MiB bigger
Scaling by 75% gives a size of 12.06 MiB, which is 2.06 MiB too large
Scaling by 62% gives a size of 8.30 MiB, the file could be 1.70 MiB bigger
Scaling by 68% gives a size of 9.96 MiB, the file could be 0.04 MiB bigger
Scaling by 71% gives a size of 10.84 MiB, which is 0.84 MiB too large
Scaling by 70% gives a size of 10.54 MiB, which is 0.54 MiB too large
Scaling by 69% gives a size of 10.25 MiB, which is 0.25 MiB too large
Scaling by 68% gives a size of 9.957MiB

The code

#! /usr/bin/python

import optparse, sys, os, os.path, tempfile, shutil, commands

def main():
    parser = optparse.OptionParser()
    parser.add_option("-s", "--size", help="Max size of the image (in MiB)", type='float')
    parser.add_option("-i", "--input-image", help="Filename of the image to use", metavar="IMAGE")
    parser.add_option("-o", "--output-image", help="Filename of the resultant image, it must not already exist", metavar="FILENAME")
    parser.add_option("-a", "--accuracy", help="The accuracy to try for. This is a floating point number between 0.0 and 1.0. The lower the value the longer the programme will run for, but the result will be closer to the target size. The default of 0.01 is usually adequate.", default=0.01, type="float")

    (options, args) = parser.parse_args()

    required = ['size', 'input_image', 'output_image']
    if not all(getattr(options, x) is not None for x in required):
        parser.print_help()
        sys.exit(1)

    if not os.path.isfile(options.input_image):
        print "Input file %s does not exist" % options.input_image
        parser.print_help()
        sys.exit(2)

    if os.path.isfile(options.output_image):
        print "Output file %s exists." % options.output_image
        parser.print_help()
        sys.exit(2)

    input = os.path.abspath(options.input_image)

    size = options.size

    # get the filesize in mebibytes
    file_size = float(os.path.getsize(input)) / 1024 / 1024
    print "Input file is of size %.2f MiB which is %.2f MiB (%.1fx) too large" % (file_size, file_size - size, file_size/size)

    upper = 1.0
    lower = 0.0

    file_extension = os.path.splitext(input)[1]

    # This is the temporary file for the scales
    temp_file_socket, temp_file_name = tempfile.mkstemp(prefix="scale_image_", suffix=file_extension)

    # A temporary file for the last file that's under the size limit.
    last_good_file_socket, last_good_file_name = tempfile.mkstemp(prefix="scale_image_last_good_", suffix=file_extension)
    last_good_attempt = None
    last_good_size = None

    shutil.copyfile(input, temp_file_name)

    while upper - lower > options.accuracy:
        attempt = ((upper - lower) / 2 ) + lower
        assert lower <= attempt <= upper
        status, output = commands.getstatusoutput(
            "convert -geometry %d%% \"%s\" \"%s\"" % (attempt * 100, input, temp_file_name))
        assert status == 0, output
        file_size = float(os.path.getsize(temp_file_name)) / 1024 / 1024
        if file_size > size:
            print (
                "Scaling by %2d%% gives a size of %.2f MiB, which is %.2f MiB too large"
                % (attempt * 100, file_size, file_size-size) )
            upper = attempt

        elif file_size < size:
            print (
                "Scaling by %2d%% gives a size of %.2f MiB, the file could be %.2f MiB bigger"
                % (attempt * 100, file_size, size-file_size) )
            lower = attempt
            shutil.copyfile(temp_file_name, last_good_file_name)
            last_good_attempt = attempt
            last_good_size = file_size

        elif file_size == size:
            print "Scaling by %d%% gives a size of %.2f MiB, which is just right" % (attempt * 100, file_size)
            shutil.copyfile(temp_file_name, last_good_file_name)
            break

    print "Scaling by %d%% gives a size of %.3fMiB" % (last_good_attempt*100, last_good_size)

    os.rename(last_good_file_name, options.output_image)

    # cleanup
    os.remove(temp_file_name)

if __name__ == '__main__':
    main()

Writing a reCAPTCHA plugin for Zine

written by rory, on Jan 5, 2009 4:35:00 PM.

I currently have comments enabled on this blog. Comment spam is a big problem. To combat it, I would like to use reCAPTCHA. There is no plugin for Zine yet, so I have to write one.

This will be a semantic blog

written by rory, on Dec 31, 2008 9:43:12 PM.

I recently discovered SIOC a set of RDF ontologies for the Web 2.0. So it includes things like "This is a blog. This is a comment". I'm making a new theme for Zine that includes all this data as RDFa.

First Post

written by rory, on Dec 31, 2008 2:40:01 PM.

This is a first post, so see if this blog works.