1
Phatch Contributors Guide
2
=========================
4
image::images/splashscreen2.png[Phatch Logo]
6
.Phatch = Photo & Batch!
7
**********************************************************************
8
Phatch is a simple to use cross-platform GUI Photo Batch Processor which handles all popular image formats and can duplicate (sub)folder hierarchies. Phatch can batch resize, rotate, rename, ... and more in minutes instead of hours or days if you do it manually. Phatch will also support a console version in the future to batch photos on webservers.
9
**********************************************************************
15
Thanks for contributing to Phatch!
17
* You might have exciting ideas how to extend the functionality with new features. The good news is that Phatch was designed from the ground up to make the development of actions as easy as possible.
18
* Or you might want to write some documentation or tutorial.
22
Developping Action plugins
23
^^^^^^^^^^^^^^^^^^^^^^^^^^
24
To develop actions for Phatch you only need to know http://www.python.org[Python] and http://www.pythonware.com/products/pil[PIL] (Python Image Library). Although Phatch uses http://www.wxpython.org[wxPython] for its cross-platform GUI, you don't need at all wxPython to write actions. Phatch will do all the GUI work automatically for you behind the scenes, so you can fully concentrate on the image manipulation. Also don't worry about internationalisation, Phatch will take care of that too.
28
Can you work with notepad, gedit or kate? Fine, that is all you need. The documentation is generated from plain text files, which follow the http://www.methods.co.nz/asciidoc[asciidoc] format. They can be translated afterwards in a lot of different formats, such as html and pdf. You don't need to install asciidoc to write documentation. You can send the plain text files to the Phatch development team and we will take care of it. However if you are curious, you will find instructions in this manual on how to install asciidoc on Ubuntu Feisty to generate pdfs. This might be usefull as well to install asciidoc on other operating systems.
32
* Translating the application Phatch is done through https://translations.launchpad.net/phatch/trunk/+pots/phatch[launchpad].
33
* Translating of documentation is done with plain text asciidoc files. Be sure to keep a copy of the source file on which you base your translation. This will allow you to quickly see what has changed with a diff viewer when new documentation is available for translation.
35
Developping Action Plugins
36
--------------------------
37
Getting Started: Invert
38
~~~~~~~~~~~~~~~~~~~~~~~
41
The best way to start is first to develop an PIL function which handles the manipulation. Afterwards you create input fields in order to pass the required parameters to the PIL function. 'Invert' is taken as a first case study as it doesn't require any parameters except for the image itself. Let's look at the source code:
43
.Invert Action Source Code
45
------------------------------------------------------------
46
from core import models
47
from core.translation import _t
51
return ImageChops.invert(image) <1>
53
class Action(models.Action):
56
email = 'spe.stani.be@gmail.com'
59
__doc__ = _t('Invert the colors of an image') <2>
61
def import_modules(self):
65
def apply(self,photo,setting,cache):
66
return self.apply_to_current_layer_image(photo) <3>
68
description = _t("""Invert the colors of the image.""") <4>
70
#icon = 'icon data' <5>
71
------------------------------------------------------------
74
<2> Defining The Action
75
<3> Applying The Action
76
<4> Describing The Action
81
For every action you need to add the first two lines which import the basic functionality for writing action plugins. The module models provide the architecture for the plugin: the `class Action` and the input fields. (As invert doesn't require any input, there are no fields here.) Every other module you need to import with the method `import_modules`, in which you declare them as global. For example to invert an image with PIL you need the `ImageChops` module.
83
NOTE: Why do modules have to be imported in a seperate method? The reason is that Phatch at startup imports all actions to extract the information it needs about the actions. If the imports would be declared normally, the startup would be delayed by maybe unneeded modules.
87
You need to create a new `class Action` which is derived from `models.Action`. You need to define the action with the `label`, `author`, `email`, `version`, `tags` and `__doc__` properties. `label` and `__doc__` will appear translated in the 'Add Action' dialog box. That is why you need to mark them with the `_t` function. At the moment `tags` and `description`, which can contain a longer description than the `__doc__` one-liner, are not exposed yet.
91
Internally Phatch works with 'photos'. 'Photos' consist of multiple 'layers'. Every 'layer' contains an 'image', but also has its own offset postion. Phatch doesn't expose this functionality yet, but will later support full layered photos, just like in Gimp. The hierarchy to remember is: Photo>Layer>Image. Luckily you don't have to worry about this in the beginning as Phatch provides you an easy method to apply a PIL function the current layer image: `apply_to_current_layer_image`.
95
In the description property you can describe the action more elaborately. Use triple quotes for multi-line text.
99
As in the example no specific icon was added, Phatch will use a default one. In the folder `phatch/pyWx/lib` there is an utility `img2py.py`. With the following command you can convert any image (eg.png) to a python file:
101
$ python img2py.py fileName icon.py
103
This will generate an `icon.py` file, in which you will find the following code:
106
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108
return zlib.decompress('icon data')
109
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
111
You can add now the 'icon data' to your action source file to define the icon:
114
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
115
class Action(models.Action):
116
description = """Invert the colors of the image."""
118
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120
Advanced: Drop Shadow
121
~~~~~~~~~~~~~~~~~~~~~
124
The following code was taken from the Python Cookbook:
125
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/474116[]
126
It demonstrates how easy it is to integrate existing PIL code into Phatch.
130
.Shadow Action Source Code
132
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
133
from core import models
134
from core.translation import _t
136
def dropShadow(image, x_offset=5, y_offset=5, back_colour=(255,255,255,0),
137
shadow_colour=0x444444, border=8, iterations=3,
138
force_back=False, cache={}):
140
Add a gaussian blur drop shadow to an image.
142
image - The image to overlay on top of the shadow.
143
offset - Offset of the shadow from the image as an (x,y) tuple.
144
Can be positive or negative.
145
back_colour - Background colour behind the image.
146
shadow_colour - Shadow colour (darkness).
147
border - Width of the border around the image. This must be wide
148
enough to account for the blurring of the shadow.
149
iterations - Number of times to apply the filter. More iterations
150
produce a more blurred shadow, but increase processing
159
#assert image is RGBA
162
id = ''.join([str(x) for x in ['shadow_',size,x_offset,y_offset,
163
border, iterations,back_colour,shadow_colour]])
166
if cache.has_key(id):
168
back, back_size = cache[id]
172
back_size = (size[0] + abs(x_offset) + 2*border,
173
size[1] + abs(y_offset) + 2*border)
177
image_mask = image.split()[-1]
178
shadow = Image.new('L',back_size,0)
180
image_mask = Image.new(mode,size,shadow_colour)
181
shadow = Image.new(mode,back_size,back_colour)
183
shadow_left = border + max(x_offset, 0)
184
shadow_top = border + max(y_offset, 0)
185
shadow.paste(image_mask, (shadow_left, shadow_top,
186
shadow_left + size[0], shadow_top + size[1]))
187
del image_mask #free up memory
191
#Apply the filter to blur the edges of the shadow. Since a small
192
#kernel is used, the filter must be applied repeatedly to get a decent
195
while n < iterations:
196
shadow = shadow.filter(ImageFilter.BLUR)
201
back = Image.new('RGBA',back_size,shadow_colour)
202
back.putalpha(shadow)
203
del shadow #free up memory
206
cache[id] = back, back_size
208
#Paste the input image onto the shadow backdrop
209
image_left = border - min(x_offset, 0)
210
image_top = border - min(y_offset, 0)
212
back.paste(image, (image_left, image_top),image)
214
mask = back.split()[-1]
215
back.paste(Image.new('RGB',back.size,back_colour),(0,0),
216
ImageChops.invert(mask))
219
back.paste(image, (image_left, image_top))
223
class Action(models.Action):
228
email = 'spe.stani.be@gmail.com'
230
tags = [_t('filter')]
231
__doc__ = _t('Drops a blurred shadow under a photo')
234
fields = models.Fields()
236
fields[_t('Horizontal Offset')] = models.PixelField('5')
237
fields[_t('Vertical Offset')] = models.PixelField('5')
238
fields[_t('Border')] = models.PixelField('8')
239
fields[_t('Shadow Blur')] = models.SliderField(3,1,20)
240
fields[_t('Background Colour')] = models.ColourField('#FFFFFF')
241
fields[_t('Shadow Colour')] = models.ColourField('#444444')
242
fields[_t('Force Background Colour')] = models.BooleanField(True)
244
super(Action,self).__init__(fields)
246
def apply(self,photo,setting,cache):
248
info = photo.get_info()
250
x0, y0 = info['new_size']
251
dpi = info['new_dpi']
254
'x_offset' : self.get_field_size('Horizontal Offset',
256
'y_offset' : self.get_field_size('Vertical Offset',
258
'border' : self.get_field_size('Border', info,x0,dpi),
259
'iterations' : self.get_field_value('Shadow Blur', info,),
260
'force_back' : self.get_field_value('Force Background Colour',
262
'back_colour' : self.get_field_value('Background Colour', info),
263
'shadow_colour' : self.get_field_value('Shadow Colour', info),
268
return self.apply_to_current_layer_image(photo,dropShadow,**parameters)
270
def import_modules(self):
272
global Image, ImageChops, ImageFilter
273
import Image, ImageChops, ImageFilter
274
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278
Probably looking at the source code of the actions, will teach you the most. You find all the actions in the folder `phatch/actions`
280
[icon="./images/icons/ubuntu.png"]
281
NOTE: If you installed Phatch on Ubuntu, probably the actions are in the folder: `/usr/lib/python2.5/site-packages/phatch/actions`
283
Writing Documentation
284
---------------------
287
The mechanism used for documentation is asciidoc. You can find more information here: http://www.methods.co.nz/asciidoc/[]
289
You can send plain text files which will be translated into pdf an html. The html will be published on the Phatch website, which might include some advertisements. The pdf version will be a present to anyone who donates. If you contribute documentation, you agree with these conditions
295
You need to install these packages:
297
$ sudo apt-get install asciidoc docbook-xml docbook-xsl source-highlight
299
To generate pdfs you will need http://xmlgraphics.apache.org/fop/[FOP], which unfortunately is not available as a package. Also we need an older version, as the current one is not compatible with the Ubuntu packages. Therefore download http://archive.apache.org/dist/xmlgraphics/fop/binaries/fop-0.20.5-bin.zip[fop-0.20.5-bin.zip].
301
Unzip this folder to where you want, for example `/opt/fop`. Make a symbolic link so fop.sh is recognized as a command:
303
$ sudo ln -s /opt/fop/fop.sh /usr/local/bin/fop.sh
305
Add this line to fop.sh so that it can find your java version:
307
JAVA_HOME=/usr/lib/jvm/java-6-sun
309
Of course if you use another java-version, link to that file instead. To add support for PNG images, you need to download the JIMI library from SUN. Because of licensing issues, the JIMI image library is not included in the FOP distribution. First, download http://java.sun.com/products/jimi[JIMI]. Then unzip the folder and copy the file `JimiProClasses.zip` from the archive to {fop-install-dir}/lib/jimi-1.0.jar. Please note that FOP binary distributions are compiled with JIMI support, so there is no need for you to build FOP to add the support. If jimi-1.0.jar is installed in the right place, it will automatically be used by FOP, otherwise it will not.
311
Copy the filter (`./examples/source-highlight-filter/source-highlight-filter.conf`) to one of the standard AsciiDoc filter locations — typically `/etc/asciidoc/filters/` or `~/.asciidoc/filters/`.
313
(C) copyright 2007 http://www.stani.be[www.stani.be]