Make Pretty Push Pinned Images

May 30th, 2011

Overview

I've created a Django form field as a sub-class of an ImageField. The field accepts an image to upload and based on certain settings, notably the size of the resulting image, the sizes and colors of 3 different borders, as well as the color of the push pin, a re-sized image is created and stored on the server with its path and optionally height and width stored in the database.

Below you will find a demo of the field in action, the resources, as well as usage instructions on how to use the code.

Demo

Resources

The resources consist of one python file containing the code and a PNG file that contains an image of a push pin.

PushPinImage.py

Usage

Make sure PushPinImage.py is on your python path and then import the module wherever you intend to use it, most likely in models.py or forms.py. The Python Imaging Library (PIL) is used for the image operations and will also need to be installed and available on your python path.

The field is constructed as follows:

class PushPinImageField(push_pin_path, max_width=150, max_height=100,
	fixed_width=0, fixed_height=0, push_pin_color='#ffff33', format='PNG',
	border=(0, '#ffffff'), inner_border_stroke=(0,'#000000'), 
	outer_border_stroke=(0, '#000000'), *args, **kwargs):

The field is a descendant of an ImageField and therefore also accepts all of the ImageField parameters, notably upload_to, height_field and width_field. Here is an explanation of the PushPinImageField specific parameters:

push_pin_path:

The path to the push pin image file (push_pin.png). This is the only parameter specific to this field (not its parent) that does not have a default value.

max_width=150, max_height=100, fixed_width=0, fixed_height=0:

The image size parameters are values in pixels. If both a fixed_height and fixed_width are provided with values greater than 0, the image will be sized to a fixed size based on the fixed size parameters. Otherwise, the image will be re-sized based on the max size parameters. Both types of resizing will maintain the aspect ratio of the image.

Resizing based on the max size parameters will ensure that the image width and height do not exceed the given values. If the aspect ratio of the image does not match the aspect ratio of the provided max size values, then the re-sized image will end up having one of its dimensions matching one of the provided values, while the other dimension will be smaller than the other provided value.

Resizing based on the fixed size parameters will ensure that the resulting re-sized image will be the exact size as the given values. The image will initially be re-sized so that one of its dimensions matches its corresponding provided dimension and the remaining dimension exceeds its corresponding provided dimension. The center of the image will then be cropped, so the resulting image is sized to the specific provided fixed values, while maintaining its original aspect ratio. This will likely not be ideal for particularly wide or tall images where the subject is off-center.

push_pin_color='#ffff33':

This should be a 6 digit hexadecimal representation of a color - shorthand notation (e.g. #FFF) is not acceptable. The push pin will be colorized based on this value.

In order to colorize the pin, the hue and saturation of the provided color will be used. Each pixel of the original push pin image will have its hue, saturation and value analyzed. If the existing hue is greater than 0 (the shadow will not be colorized), the hue will be set to the hue of the provided push_pin_color. The saturation will be adjusted by an offset value that is computed by subtracting the saturation of the highest saturated pixel in the original push pin image from the saturation of the provided color.

The value (lightness/darkness) will be disregarded as the values of the original push pin will be maintained. This is done to retain the shading of the push pin. This algorithm can result in some unexpected results for certain colors. The most dramatic examples of this are black and white. Since black and white have the same hue and saturation (0), the resulting push pin for each color will be the same color. This is an extreme example and in most cases the colorization should mostly work as one would reasonably expect.

format='PNG':

This represents the format the resulting re-sized image will be saved as. Although it defaults to PNG, in practice this will automatically be overridden with the format of the uploaded image.

border=(0, '#ffffff'), inner_border_stroke=(0,'#000000'), outer_border_stroke=(0, '#000000'):

The re-sized image can contain three types of borders as described in the following image:

Each of the borders is set with a tuple containing two elements. The first should be a positive integer representing the size of the border in pixels. The sum of the inner_border_stroke size and outer_board_stroke size cannot exceed the size of the border. The second item in the tuple should be a 6 digit hexadecimal representation of a color - shorthand notation (e.g. #FFF) is not acceptable.


blog comments powered by Disqus