[gimp] Bug 605366 - OpenRaster support



commit bd8af017f5f50ad30201875f9ecc0a2cac8a4f16
Author: Jon Nordby <jononor gmail com>
Date:   Sun Jan 24 08:59:55 2010 +0100

    Bug 605366 - OpenRaster support
    
    Add basic OpenRaster support. At the very least, this allows
    multi-layered .ora files to be shared between MyPaint and GIMP.

 plug-ins/pygimp/plug-ins/Makefile.am        |    1 +
 plug-ins/pygimp/plug-ins/file-openraster.py |  252 +++++++++++++++++++++++++++
 2 files changed, 253 insertions(+), 0 deletions(-)
---
diff --git a/plug-ins/pygimp/plug-ins/Makefile.am b/plug-ins/pygimp/plug-ins/Makefile.am
index faa640a..35549f4 100644
--- a/plug-ins/pygimp/plug-ins/Makefile.am
+++ b/plug-ins/pygimp/plug-ins/Makefile.am
@@ -4,6 +4,7 @@ pluginexecdir = $(gimpplugindir)/plug-ins
 
 scripts = \
 	colorxhtml.py		\
+	file-openraster.py	\
 	foggify.py		\
 	palette-offset.py	\
 	palette-sort.py		\
diff --git a/plug-ins/pygimp/plug-ins/file-openraster.py b/plug-ins/pygimp/plug-ins/file-openraster.py
new file mode 100755
index 0000000..2016c2b
--- /dev/null
+++ b/plug-ins/pygimp/plug-ins/file-openraster.py
@@ -0,0 +1,252 @@
+#!/usr/bin/env python
+
+# GIMP Plug-in for the OpenRaster file format
+# http://create.freedesktop.org/wiki/OpenRaster
+
+# Copyright (C) 2009 by Jon Nordby <jononor gmail com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# Based on MyPaint source code by Martin Renold
+# http://gitorious.org/mypaint/mypaint/blobs/edd84bcc1e091d0d56aa6d26637aa8a925987b6a/lib/document.py
+
+from gimpfu import *
+
+import tempfile, zipfile, os
+import xml.etree.ElementTree as ET
+
+
+def get_image_attributes(orafile):
+    xml = orafile.read('stack.xml')
+    image = ET.fromstring(xml)
+    stack = image.find('stack')
+    w = int(image.attrib.get('w', ''))
+    h = int(image.attrib.get('h', ''))
+
+    return stack, w, h
+
+def get_layer_attributes(layer):
+    a = layer.attrib
+    path = a.get('src', '')
+    name = a.get('name', '')
+    x = int(a.get('x', '0'))
+    y = int(a.get('y', '0'))
+    opac = float(a.get('opacity', '1.0'))
+
+    return path, name, x, y, opac
+
+
+def thumbnail_ora(filename, thumb_size):
+    # FIXME: Untested. Does not seem to be used at all? should be run
+    # when registered and there is no thumbnail in cache
+
+    tempdir = tempfile.mkdtemp('gimp-plugin-file-openraster')
+    orafile = zipfile.ZipFile(filename)
+    stack, w, h = get_image_attributes(orafile)
+
+    # create temp file
+    tmp = os.path.join(tempdir, 'tmp.png')
+    f = open(tmp, 'wb')
+    f.write(orafile.read('Thumbnails/thumbnail.png'))
+    f.close()
+
+    img = pdb['file-png-load'](tmp)
+    # TODO: scaling
+    os.remove(tmp)
+    os.rmdir(tempdir)
+
+    return (img, w, h)
+
+def save_ora(img, drawable, filename, raw_filename):
+    def write_file_str(zfile, fname, data):
+        # work around a permission bug in the zipfile library:
+        # http://bugs.python.org/issue3394
+        zi = zipfile.ZipInfo(fname)
+        zi.external_attr = 0100644 << 16
+        zfile.writestr(zi, data)
+
+    tempdir = tempfile.mkdtemp('gimp-plugin-file-openraster')
+
+    # use .tmpsave extension, so we don't overwrite a valid file if
+    # there is an exception
+    orafile = zipfile.ZipFile(filename + '.tmpsave', 'w', compression=zipfile.ZIP_STORED)
+
+    write_file_str(orafile, 'mimetype', 'image/openraster') # must be the first file written
+
+    # build image attributes
+    image = ET.Element('image')
+    stack = ET.SubElement(image, 'stack')
+    a = image.attrib
+    a['w'] = str(img.width)
+    a['h'] = str(img.height)
+
+    def store_layer(img, drawable, path):
+        tmp = os.path.join(tempdir, 'tmp.png')
+        pdb['file-png-save-defaults'](img, drawable, tmp, 'tmp.png')
+        orafile.write(tmp, path)
+        os.remove(tmp)
+
+    def add_layer(x, y, opac, gimp_layer, path):
+        store_layer(img, gimp_layer, path)
+        # create layer attributes
+        layer = ET.Element('layer')
+        stack.append(layer)
+        a = layer.attrib
+        a['src'] = path
+        a['name'] = gimp_layer.name
+        a['x'] = str(x)
+        a['y'] = str(y)
+        a['opacity'] = str(opac)
+        return layer
+
+    # save layers
+    for lay in img.layers:
+        x, y = lay.offsets
+        opac = lay.opacity / 100.0 # needs to be between 0.0 and 1.0
+        add_layer(x, y, opac, lay, 'data/%s.png' % lay.name)
+
+    # save thumbnail
+    w, h = img.width, img.height
+    # should be at most 256x256, without changing aspect ratio
+    if w > h:
+        w, h = 256, max(h*256/w, 1)
+    else:
+        w, h = max(w*256/h, 1), 256
+    thumb = pdb['gimp-image-duplicate'](img)
+    thumb_layer = thumb.flatten()
+    thumb_layer.scale(w, h)
+    store_layer(thumb, thumb_layer, 'Thumbnails/thumbnail.png')
+    gimp.delete(thumb)
+
+    # write stack.xml
+    xml = ET.tostring(image, encoding='UTF-8')
+    write_file_str(orafile, 'stack.xml', xml)
+
+    # finish up
+    orafile.close()
+    os.rmdir(tempdir)
+    if os.path.exists(filename):
+        os.remove(filename) # win32 needs that
+    os.rename(filename + '.tmpsave', filename)
+
+def load_ora(filename, raw_filename):
+    tempdir = tempfile.mkdtemp('gimp-plugin-file-openraster')
+    orafile = zipfile.ZipFile(filename)
+    stack, w, h = get_image_attributes(orafile)
+
+    img = gimp.Image(w, h, RGB)
+    img.filename = filename
+
+    def get_layers(root):
+        """returns a flattened list of all layers under root"""
+        res = []
+        for item in root:
+            if item.tag == 'layer':
+                res.append(item)
+            elif item.tag == 'stack':
+                res += get_layers(item)
+        return res
+
+    for layer_no, layer in enumerate(get_layers(stack)):
+        path, name, x, y, opac = get_layer_attributes(layer)
+
+        if not path.lower().endswith('.png'):
+            continue
+        if not name:
+            # use the filename without extention as name
+            n = os.path.basename(path)
+            name = os.path.splitext(n)[0]
+
+        # create temp file. Needed because gimp cannot load files from inside a zip file
+        tmp = os.path.join(tempdir, 'tmp.png')
+        f = open(tmp, 'wb')
+        f.write(orafile.read(path))
+        f.close()
+
+        # import layer, set attributes and add to image
+        gimp_layer = pdb['gimp-file-load-layer'](img, tmp)
+        gimp_layer.name = name
+        gimp_layer.translate(x, y)  # move to correct position
+        gimp_layer.opacity = opac * 100  # a float between 0 and 100
+        img.add_layer(gimp_layer, layer_no)
+
+        os.remove(tmp)
+    os.rmdir(tempdir)
+
+    return img
+
+
+def register_load_handlers():
+    gimp.register_load_handler('file-openraster-load', 'ora', '')
+    pdb['gimp-register-file-handler-mime']('file-openraster-load', 'image/openraster')
+    pdb['gimp-register-thumbnail-loader']('file-openraster-load', 'file-openraster-load-thumb')
+
+def register_save_handlers():
+    gimp.register_save_handler('file-openraster-save', 'ora', '')
+
+register(
+    'file-openraster-load-thumb', #name
+    'loads a thumbnail from an OpenRaster (.ora) file', #description
+    'loads a thumbnail from an OpenRaster (.ora) file',
+    'Jon Nordby', #author
+    'Jon Nordby', #copyright
+    '2009', #year
+    None,
+    None, #image type
+    [   #input args. Format (type, name, description, default [, extra])
+        (PF_STRING, 'filename', 'The name of the file to load', None),
+        (PF_INT, 'thumb-size', 'Preferred thumbnail size', None),
+    ],
+    [   #results. Format (type, name, description)
+        (PF_IMAGE, 'image', 'Thumbnail image'),
+        (PF_INT, 'image-width', 'Width of full-sized image'),
+        (PF_INT, 'image-height', 'Height of full-sized image')
+    ],
+    thumbnail_ora, #callback
+)
+
+register(
+    'file-openraster-save', #name
+    'save an OpenRaster (.ora) file', #description
+    'save an OpenRaster (.ora) file',
+    'Jon Nordby', #author
+    'Jon Nordby', #copyright
+    '2009', #year
+    'OpenRaster',
+    '*',
+    [   #input args. Format (type, name, description, default [, extra])
+        (PF_IMAGE, "image", "Input image", None),
+        (PF_DRAWABLE, "drawable", "Input drawable", None),
+        (PF_STRING, "filename", "The name of the file", None),
+        (PF_STRING, "raw-filename", "The name of the file", None),
+    ],
+    [], #results. Format (type, name, description)
+    save_ora, #callback
+    on_query = register_save_handlers,
+    menu = '<Save>'
+)
+
+register(
+    'file-openraster-load', #name
+    'load an OpenRaster (.ora) file', #description
+    'load an OpenRaster (.ora) file',
+    'Jon Nordby', #author
+    'Jon Nordby', #copyright
+    '2009', #year
+    'OpenRaster',
+    None, #image type
+    [   #input args. Format (type, name, description, default [, extra])
+        (PF_STRING, 'filename', 'The name of the file to load', None),
+        (PF_STRING, 'raw-filename', 'The name entered', None),
+    ],
+    [(PF_IMAGE, 'image', 'Output image')], #results. Format (type, name, description)
+    load_ora, #callback
+    on_query = register_load_handlers,
+    menu = "<Load>",
+)
+
+
+main()



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]