xenogenesi::blog
memento
3d adt android apache2 app apt aria2 build bullet cflags chromium codeigniter debian demoscene dependencies dpkg driver emulator freeglut gcc gfx git glut htaccess javascript json kernel linux make metalink minimal mysql opengl php python raspbian realtime rpi specs template toolchain update-alternatives video wifi wordpress

scripting inkscape with python

I needed a way to create many layers at once in inkscape, it support scripting with any language, the .inx file allow to define input parameters to insert with a GUI, they will be passed to the script as command line arguments

Place the .inx file and the python script in the inkscape directory

$HOME/.config/inkscape/extensions/create_layers.inx
$HOME/.config/inkscape/extensions/create_layers.py

create_layers.inx:

<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
  <_name>Create Layers</_name>
  <id>org.xenogenesi.filter.create_layers</id>
  <dependency type="executable" location="extensions">create_layers.py</dependency>
  <dependency type="executable" location="extensions">inkex.py</dependency>
  <param name="basename" type="string" _gui-text="Base name of the new layer">New Layer {0}</param>
  <param name="count" type="string" _gui-text="Number of layers to create">10</param>
  <effect>
    <object-type>all</object-type>
    <effects-menu>
       <submenu _name="Layers"/>
    </effects-menu>
  </effect>
  <script>
    <command reldir="extensions" interpreter="python">create_layers.py</command>
  </script>
</inkscape-extension>

create_layers.py:

#!/usr/bin/env python

import inkex

class CreateLayersEffect(inkex.Effect):

    def __init__(self):

        inkex.Effect.__init__(self)

        self.OptionParser.add_option('-b', '--basename', action = 'store',
          type = 'string', dest = 'basename', default = 'New Layer {0}',
          help = 'Base name of the new layer')
        self.OptionParser.add_option('-c', '--count', action = 'store',
          type = 'string', dest = 'count', default = '10',
          help = 'Number of layers to create')

    def effect(self):
        basename = self.options.basename
        count = int(self.options.count)

        svg = self.document.getroot()

        for i in range(0, count):
            layer = inkex.etree.SubElement(svg, 'g')
            layer.set(inkex.addNS('label', 'inkscape'), basename.format(i))
            layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')

effect = CreateLayersEffect()
effect.affect()

github.com/xenogenesi/inkscape-pyext (one more extension to create layers for each selected object)

Here some great reference wiki.inkscape/Script_extensions

scripting gimp in python

gimp support being scripted with python (2.7) menu Filters > Python Fu > console, you don’t even need to write a plugin, just type execfile("/some/path/your-script.py") to the console prompt

the python console have a very nice Browse button which allow to find the functions you need from the procedure browser (and their arguments), those may be exported from gimp or plugins

For example, I needed to crop each layer and save it as png file, save the name of the layer and the crop coordinates in a json file, here it is:

savepath="/tmp/slices/"
f=open("{0}images.json".format(savepath),"w")

print >> f, "["

def process_layer(image, layer):
    pdb.gimp_image_set_active_layer(image, layer)
    drawable = pdb.gimp_image_active_drawable(image)
    layer_name = pdb.gimp_item_get_name(drawable)
    if layer_name == "background":
        return

    pdb.gimp_selection_none(image)

    pdb.gimp_context_set_sample_merged(FALSE)
    pdb.gimp_context_set_antialias(FALSE)
    pdb.gimp_context_set_sample_transparent(TRUE)
    pdb.gimp_context_set_feather(FALSE)
    pdb.gimp_context_set_sample_threshold(0)
    pdb.gimp_image_select_contiguous_color(image, 2, drawable, 1, 1)
    pdb.gimp_selection_invert(image)
    non_empty, x1, y1, x2, y2 = pdb.gimp_selection_bounds(image)
    if non_empty:
        pdb.gimp_image_select_rectangle(image, 2, x1, y1, x2-x1, y2-y1)
        non_empty = pdb.gimp_edit_copy(drawable)
        if non_empty:
            image4 = pdb.gimp_edit_paste_as_new()
            active_layer = pdb.gimp_image_get_active_layer(image4)
            pdb.file_png_save2(image4, active_layer, "{0}{1}.png".format(savepath, layer_name), layer_name, TRUE, 9, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE)
            pdb.gimp_image_delete(image4)

            print >> f, "\t{{ \"{0}\": [ {1:d}, {2:d}, {3:d}, {4:d} ] }},".format(layer_name, x1, y1, x2, y2)
        else:
            print("gimp_edit_copy = empty ({0})".format(layer_name))
    else:
        print("gimp_selection_bounds = empty ({0})".format(layer_name))


image = gimp.image_list()[0]

for layer in image.layers:
    process_layer(image, layer)


print >> f, "]"

f.close()

github gist

delete thousands of spam comments from WordPress

A friend with a WordPress website asked for help cleaning up from spam about ~400 thousands comments (about ~200M), he had guests enabled to comment.

I chosen to use python with curses (ncurses) and this pybayesantispam python module.

The curses GUI is a list with an abstract from the comment content and a column with the current spam rating, a cursor to select a comment and some key to tag it as (s)pam or (h)am, the bayesian module require some manual training, (n)ext (p)revious to browse the comments table.

The code is ugly, had a very limited time, but I been impressed how fast got a good result.

The current code include GeoIP and show the country code but isn’t used to filter the spam, in this case was an overhead, but would have been easy to add more weight factors: create a whitelist of emails from manually tagged ham, blacklist from manually tagged spam, guests users have id 0, blacklist/whitelist of ip from manually tagged comments.

py-curses-wp-spam.tgz