Commits

Anonymous committed b0b87d8 Merge

Merge in jython support

Comments (0)

Files changed (16)

 
 \.DS_Store$
 \.pyc$
+\.class$

pystacia/api/__init__.py

 import os
 from os import getcwd, chdir
 from os.path import join, exists, dirname
-from ctypes import CDLL
-from ctypes.util import find_library as ctypes_find_library
 from warnings import warn
 import atexit
 from logging import getLogger
 
             c_call(None, 'terminus')
 
+            if jython:
+                from java.lang import System
+                System.exit(0)
+
         logger.debug('Critical section - init MagickWand')
         with __lock:
             if not dll.__inited:
 
 from pystacia import registry
 from pystacia.util import get_osname, PystaciaException
-from pystacia.compat import formattable
+from pystacia.compat import formattable, jython
 from pystacia.common import _cleanup
 from pystacia import magick
 from pystacia.api.func import c_call
+from pystacia.api.compat import CDLL, find_library as ctypes_find_library
 
 
 min_version = (6, 5, 9, 0)

pystacia/api/compat.py

+# coding: utf-8
+
+# pystacia/api/compat.py
+# Copyright (C) 2011-2012 by Paweł Piotr Przeradowski
+
+# This module is part of Pystacia and is released under
+# the MIT License: http://www.opensource.org/licenses/mit-license.php
+
+from ctypes import c_char_p, c_size_t, c_double, c_uint, c_int, byref
+
+from pystacia.compat import jython
+
+
+if jython:
+    from ctypes import c_ssize_t
+    from pystacia.api.jnatypes import c_void_p, POINTER, find_library, string_at, CDLL
+else:
+    from ctypes import c_void_p, POINTER, string_at, CDLL #@UnusedImport
+    from ctypes.util import find_library  # @UnusedImport
+    c_void = None
+
+    try:
+        from ctypes import c_ssize_t  # @UnusedImport
+    except ImportError:
+        # python <=2.6 doesnt have c_ssize_t,
+        # implementation copied from ctypes from 2.7
+        from ctypes import (c_long, c_longlong,
+                                sizeof, c_uint, c_ulong, c_ulonglong)
+
+        if sizeof(c_uint) == sizeof(c_void_p):
+            c_ssize_t = c_int
+        elif sizeof(c_ulong) == sizeof(c_void_p):
+            c_ssize_t = c_long
+        elif sizeof(c_ulonglong) == sizeof(c_void_p):
+            c_ssize_t = c_longlong

pystacia/api/func.py

 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 from threading import Lock
-from ctypes import (c_char_p, c_void_p, POINTER, c_size_t, c_double, c_uint,
-                    string_at)
 
-from six import string_types, b as bytes_
+from six import string_types, b as bytes_, text_type
 
 from pystacia.util import memoized
 from pystacia.compat import pypy
             'symbols': {
                 'read': ((ch,), b),
                 'write': ((ch,), b),
-                ('read', 'blob'): ((v, s), b),
+                ('read', 'blob'): ((ch, s), b),
                 ('get', 'blob'): ((P(s),), v),
 
                 ('set', 'format'): ((ch,), b),
     }
 
 
-def get_c_method(obj, method, throw=True):
-    if hasattr(obj.__class__, '_api_type'):
-        api_type = obj.__class__._api_type
-    else:
-        api_type = obj
-
-    msg = formattable('Translating method {0}.{1}')
-    logger.debug(msg.format(api_type, method))
-
+@memoized
+def get_c_method(api_type, method, throw=True):
     type_data = get_data()[api_type]
     method_name = type_data['format'](method)
 
 
     c_method = getattr(get_dll(False), method_name)
 
-    if c_method.argtypes == None:
-        msg = formattable('Annoting {0}')
-        logger.debug(msg.format(method_name))
-        method_data = type_data['symbols'][method]
+    msg = formattable('Annoting {0}')
+    logger.debug(msg.format(method_name))
+    method_data = type_data['symbols'][method]
 
-        argtypes = method_data[0]
-        if 'arg' in type_data:
-            argtypes = (type_data['arg'],) + argtypes
-        c_method.argtypes = argtypes
+    argtypes = method_data[0]
+    if 'arg' in type_data:
+        argtypes = (type_data['arg'],) + argtypes
+    c_method.argtypes = argtypes
 
-        restype = type_data.get('result')
-        if len(method_data) == 2:
-            restype = method_data[1]
-        c_method.restype = restype
+    restype = type_data.get('result', None)
+    if len(method_data) == 2:
+        restype = method_data[1]
+    c_method.restype = restype
 
     return method_name, c_method
 
 
 
 def c_call(obj, method, *args, **kw):
-    method_name, c_method = get_c_method(obj, method)
+    if hasattr(obj.__class__, '_api_type'):
+        api_type = obj.__class__._api_type
+    else:
+        api_type = obj
+
+    msg = formattable('Translating method {0}.{1}')
+    logger.debug(msg.format(api_type, method))
+
+    method_name, c_method = get_c_method(api_type, method)
 
     try:
         init = kw.pop('__init')
     for arg, type in zip(args, c_method.argtypes):  # @ReservedAssignment
         if type == c_char_p:
             should_lock = True
-            arg = bytes_(arg)
+            if isinstance(arg, text_type):
+                arg = bytes_(arg)
         elif type in (c_size_t, c_ssize_t, c_uint):
             arg = int(arg)
         elif type == PixelWand_p:
         result = native_str(result)
     if c_method.restype in (c_uint, c_ssize_t, c_size_t):
         result = int(result)
-    elif c_method.restype == enum:
+    elif c_method.restype == enum and not jython:
         result = result.value
-    elif c_method.restype == MagickBoolean and not result.value:
+    elif c_method.restype == MagickBoolean and not result:
         exc_type = ExceptionType()
 
         if c_method.argtypes[0] == MagickWand_p:
         elif c_method.argtypes[0] == PixelWand_p:
             class_ = 'pixel'
 
-        description = c_call(class_, 'get_exception', args[0], exc_type)
+        description = c_call(class_, 'get_exception', args[0], byref(exc_type))
         try:
             raise PystaciaException(native_str(string_at(description)))
         finally:
     return result
 
 from pystacia.util import PystaciaException
-from pystacia.compat import native_str, formattable, c_ssize_t
+from pystacia.compat import native_str, formattable, jython
 from pystacia.api import get_dll, logger
 from pystacia.api.type import (
     MagickWand_p, PixelWand_p, MagickBoolean, ExceptionType, enum)
+from pystacia.api.compat import (c_char_p, c_void_p, POINTER, c_size_t,
+                                 c_double, c_uint, string_at, c_ssize_t, byref)
 from pystacia.common import Resource
 from pystacia.color import cast as color_cast

pystacia/api/jnatypes.py

+import ctypes
+
+from java.lang import Void, String, Integer, Double, UnsatisfiedLinkError  # @UnresolvedImport
+from com.sun.jna import NativeLibrary, NativeLong, Pointer  # @UnresolvedImport
+from com.sun.jna import ptr
+
+from pystacia.util import memoized
+
+__ref_mapping = {Integer: ptr.IntByReference,
+                 NativeLong: ptr.NativeLongByReference,
+                 Double: ptr.DoubleByReference}
+
+
+class c_void_p(object):
+    _wrap = True
+    _unwrap = True
+    _jffi_type = ctypes.c_ulong._jffi_type
+
+    def __init__(self, value):
+        self.value = value
+
+    def __long__(self):
+        return self.value
+
+
+class c_char_p_p(object):
+    _wrap = True
+    _jffi_type = ctypes.c_void_p._jffi_type
+
+    def __init__(self, value):
+        self.value = Pointer(value)
+
+    def __getitem__(self, idx):
+        return string_at(self.value.getPointer(idx * Pointer.SIZE))
+
+
+def POINTER(type):  # @ReservedAssignment
+#    class pointer(wrappable):
+#        _j_type = Pointer
+#        _to = type
+#
+#        def __getitem__(self, idx):
+#            deref = self._j_object.getPointer(idx * Pointer.SIZE)
+#
+#            if issubclass(self._to, wrappable):
+#                deref = self._to(deref)
+#
+#            if hasattr(deref, '_after'):
+#                deref = deref._after()
+#
+#            return deref
+    if type == ctypes.c_char_p:
+        return c_char_p_p
+    else:
+        return ctypes.POINTER(type)
+
+
+#class c_char(object):
+#    pass
+
+
+#c_char_p = POINTER(c_char)
+#c_char_p._after = lambda o: str(o._j_object.getString(0))
+
+
+#class c_int(wrappable):
+#    _j_type = Integer
+#
+#
+#class c_uint(wrappable):
+#    _j_type = Integer
+#
+#
+#_after_size = lambda o: o._j_object.toNative()
+#
+#
+#class c_size_t(wrappable):
+#    _j_type = NativeLong
+#    _after = _after_size
+#
+#
+#class c_ssize_t(wrappable):
+#    _j_type = NativeLong
+#    _after = _after_size
+#
+#
+#class c_double(object):
+#    _j_type = Double
+#
+#
+#class Reference(object):
+#    def __init__(self, o):
+#        self._object = o
+#        self._j_object = __ref_mapping[o.__class__._j_type]()
+#
+#    def sync(self):
+#        value = self._j_object.getValue()
+#        if isinstance(value, NativeLong):
+#            value = value.toNative()
+#        self._object.value = value
+#
+#
+#def byref(o):
+#    return Reference(o)
+
+
+def string_at(p, length=None):
+    if isinstance(p, c_void_p):
+        p = Pointer(p.value)
+
+    if length:
+        return p.getByteArray(0, length).tostring()
+
+    return p.getString(0).encode('utf-8')
+
+
+#        args_ = []
+#        to_sync = []
+#        for arg, type_ in zip(args, self.argtypes):
+#            if isinstance(arg, Reference):
+#                to_sync.append(arg)
+#            if hasattr(arg, '_j_object'):
+#                arg = arg._j_object
+#            if type_._j_type == NativeLong:
+#                arg = NativeLong(arg)
+#            args_.append(arg)
+#
+#        result = self._j_function.invoke(self.restype._j_type, args_)
+#
+#        [arg.sync() for arg in to_sync]
+#
+#        if issubclass(self.restype, wrappable):
+#            result = self.restype(result)
+#
+#        if hasattr(result, '_after'):
+#            result = result._after()
+#
+#        return result
+
+
+class Function(object):
+    def __init__(self, func):
+        self.__dict__['_func'] = func
+
+    def __call__(self, *args):
+        func = self._func
+
+        result = func(*args)
+
+        if hasattr(func.restype, '_wrap'):
+            result = func.restype(result)
+
+        return result
+
+    def __getattr__(self, name):
+        return getattr(self._func, name)
+
+    def __setattr__(self, name, value):
+        setattr(self._func, name, value)
+
+
+class Library(object):
+    def __init__(self, path):
+        self._dll = ctypes.CDLL(path)
+        self._name = path
+
+    @memoized
+    def __getattr__(self, name):
+        try:
+            return Function(getattr(self._dll, name))
+        except NameError, e:
+            raise AttributeError(e)
+
+
+@memoized
+def CDLL(path):
+    return Library(path)
+
+
+def find_library(name):
+    # this fallback is good enough ;-)
+    try:
+        library = NativeLibrary.getInstance(name)
+    except UnsatisfiedLinkError:
+        return None
+
+    return library.file.path

pystacia/api/type.py

 # This module is part of Pystacia and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from ctypes import c_void_p, c_int
+from pystacia.api.compat import c_void_p, c_int
 
 
 class enum(c_int):

pystacia/color/_impl.py

 # This module is part of Pystacia and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from ctypes import c_double
 from pystacia.util import PystaciaException
 from six import reraise
 from sys import exc_info
 def get_hsl(color):
     h, s, l = tuple(x() for x in (c_double,) * 3)
 
-    c_call(color, 'get_hsl', h, s, l)
+    c_call(color, 'get_hsl', byref(h), byref(s), byref(l))
 
     return tuple(saturate(x.value) for x in (h, s, l))
 
 
 
 from pystacia.api.func import c_call
+from pystacia.api.compat import c_double, byref

pystacia/compat.py

     dist = platform.dist
 
 
-# python <=2.6 doesnt have c_ssize_t,
-# implementation copied from ctypes from 2.7
-def fallback_c_size_t():
-    from ctypes import (c_void_p, c_int, c_long, c_longlong,
-                        sizeof, c_uint, c_ulong, c_ulonglong)
-
-    if sizeof(c_uint) == sizeof(c_void_p):
-        return c_int
-    elif sizeof(c_ulong) == sizeof(c_void_p):
-        return c_long
-    elif sizeof(c_ulonglong) == sizeof(c_void_p):
-        return c_longlong
-
-import ctypes
-c_ssize_t = getattr(ctypes, 'c_ssize_t', fallback_c_size_t())
-
-
-try:
-    from webbrowser import open as gui_open
-except ImportError:
-    #TODO: implement
-    gui_open = lambda x: None
-
-
 # detect PyPy
 import sys
 pypy = '__pypy__' in sys.builtin_module_names
+
+# detect Jython
+jython = sys.platform.startswith('java')
+
+if jython:
+    from pystacia.jbrowser import open as gui_open
+else:
+    from webbrowser import open as gui_open

pystacia/image/_impl/color.py

 
 from __future__ import division
 
-from ctypes import c_double
-
 
 def brightness(image, factor):
     c_call(image, 'brightness_contrast', factor * 100, 0)
 def get_range(image):
     minimum, maximum = c_double(), c_double()
 
-    c_call(image, ('get', 'range'), minimum, maximum)
+    c_call(image, ('get', 'range'), byref(minimum), byref(maximum))
 
     return tuple(x.value / (2 ** magick.get_depth() - 1)
                  for x in (minimum, maximum))
 from pystacia import color
 from pystacia.api.func import c_call
 from pystacia.api.enum import lookup as enum_lookup
+from pystacia.api.compat import c_double, byref
 from pystacia.image.enum import colorspaces, interpolations, operations

pystacia/image/_impl/io.py

 from __future__ import with_statement
 
 from os.path import splitext
-from ctypes import c_size_t, string_at
 
 
 def read(spec, width=None, height=None, factory=None):
         c_call('magick', 'set_format', image, format)
 
         size = c_size_t()
-        result = c_call(image, ('get', 'blob'), size)
+        result = c_call(image, ('get', 'blob'), byref(size))
+
+        #from nose.tools import set_trace; set_trace()
+
         blob = string_at(result, size.value)
 
         c_call('magick_', 'relinquish_memory', result)
 from pystacia.image import _instantiate
 from pystacia.image.generic import blank
 from pystacia.api.func import c_call
+from pystacia.api.compat import c_size_t, string_at, byref

pystacia/image/_impl/pixel.py

 # This module is part of Pystacia and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from ctypes import c_double
-
 
 def get_pixel(self, x, y, factory):
     color_ = color._instantiate(factory)
 
 
 def set_color(image, fill):
-    if get_c_method(image, ('set', 'color'), throw=False):
+    if get_c_method('image', ('set', 'color'), throw=False):
         c_call(image, ('set', 'color'), fill)
 
         # MagickSetImageColor doesnt copy alpha
     distortion = c_double()
 
     diff = c_call(image, ('compare', None, 'images'), other,
-                  metric, distortion)
+                  metric, byref(distortion))
 
     return(factory(diff), distortion.value)
 
 
 from pystacia.api.func import get_c_method, c_call
 from pystacia.api.enum import lookup as enum_lookup
+from pystacia.api.compat import c_double, byref
 from pystacia.image.enum import metrics, composites
 from pystacia.image import Image
 from pystacia.image.generic import blank

pystacia/image/tests/__init__.py

         for i in (bmp, BytesIO(bmp)):
             img = read_blob(i)
 
-            self.assertEqual(img.size, sample.size)
-            self.assertEqual(img.type, sample.type)
+            self.assertEqual(img.size, sample_size)
+            self.assertEqual(img.type, sample_type)
             self.assertTrue(img.colorspace.name.endswith('rgb'))
             self.assertEqual(img.depth, 8)
 
 
         img = read(tmpname)
 
-        self.assertSequenceEqual(img.size, sample.size)
-        self.assertEqual(img.type, sample.type)
+        self.assertSequenceEqual(img.size, sample_size)
+        self.assertEqual(img.type, sample_type)
         self.assertTrue(img.colorspace.name.endswith('rgb'))
         self.assertEqual(img.depth, 8)
 
         img.write(tmpname)
 
         img = read(tmpname)
-        self.assertEqual(img.size, sample.size)
+        self.assertEqual(img.size, sample_size)
         self.assertTrue(img.colorspace.name.endswith('rgb'))
-        self.assertEqual(img.type, sample.type)
+        self.assertEqual(img.type, sample_type)
         img.close()
 
     def test_rescale(self):
     def test_fit(self):
         img = self.img
 
-        ratio = 320 / sample.size[0]
+        ratio = 320 / sample_size[0]
         img.fit(320)
-        self.assertEqual(img.size, (320, sample.size[1] * ratio))
+        self.assertEqual(img.size, (320, sample_size[1] * ratio))
         img.fit(128, 128)
         self.assertEqual(img.size, (128, 128))
 
         img = self.img
 
         img.wave(10, 100)
-        new_size = (sample.size[0], sample.size[1] + 20)
+        new_size = (sample_size[0], sample_size[1] + 20)
         self.assertEqual(img.size, new_size)
         self.assertEqual(img.get_pixel(25, 10).alpha, 0)
         self.assertEqual(img.get_pixel(128, 128).alpha, 1)
     def test_type(self):
         img = self.img
 
-        self.assertEqual(img.type, sample.type)
+        self.assertEqual(img.type, sample_type)
         img.type = types.bilevel
         self.assertEqual(img.type, types.bilevel)
 
     def test_size(self):
         img = self.img
 
-        self.assertSequenceEqual(img.size, sample.size)
+        self.assertSequenceEqual(img.size, sample_size)
         self.assertSequenceEqual((img.width, img.height), img.size)
 
     def test_depth(self):
 from pystacia.image import (read, read_raw, read_blob, types,
                            colorspaces, blank, axes, checkerboard)
 from pystacia import color, registry, magick
-from pystacia.tests.common import sample
+from pystacia.tests.common import sample, sample_type, sample_size
 from random import randint

pystacia/jbrowser.py

+from java.awt.image import BufferedImage
+from java.io import File
+from java.net import URL
+from javax.imageio import ImageIO
+from javax.swing import JLabel, JFrame, ImageIcon
+
+
+def open(path):
+    label = JLabel(ImageIcon(ImageIO.read(File(URL(path).getFile()))))
+    frame = JFrame()
+    frame.getContentPane().add(label)
+    frame.pack()
+    frame.setLocation(200, 200)
+    frame.setVisible(True)

pystacia/magick/_impl.py

 # This module is part of Pystacia and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from ctypes import c_size_t
-
-from pystacia.compat import native_str
-
 
 def get_options():
     options = {}
 
     size = c_size_t()
-    keys = c_call('magick_', 'query_configure_options', '*', size)
+    keys = c_call('magick_', 'query_configure_options', '*', byref(size))
     for key in (native_str(keys[i]) for i in range(size.value)):
         options[key] = (
         c_call('magick_', 'query_configure_option', key))
 
 def get_formats():
     size = c_size_t()
-    formats = c_call('magick_', 'query_formats', '*', size)
+    formats = c_call('magick_', 'query_formats', '*', byref(size))
 
     return [native_str(formats[i]).lower() for i in range(size.value)]
 
+from pystacia.compat import native_str
 from pystacia.api.func import c_call
+from pystacia.api.compat import c_size_t, byref

pystacia/tests/common.py

 
 if lena_available():
     sample = partial(__weakrefed, image.lena)
-    sample.size = (512, 512)
-    sample.type = types.truecolor
+    sample_size = (512, 512)
+    sample_type = types.truecolor
 else:
     sample = partial(__weakrefed, image.magick_logo)
-    sample.size = (640, 480)
-    sample.type = types.palette
+    sample_size = (640, 480)
+    sample_type = types.palette

pystacia/tests/compat_tests.py

         self.assertIsInstance(native_str(value), str)
         self.assertEqual(native_str(value), 'abc')
 
-        if version_info >= (3, 2) or (2, 7) <= version_info < (2, 8):
-            from ctypes import c_ssize_t as c_ssize_t_
-            self.assertEqual(c_ssize_t, c_ssize_t_)
-
         if version_info < (2, 7):
             from unittest2 import TestCase as TestCase_  # @UnresolvedImport
             self.assertEqual(TestCase, TestCase_)
             from unittest import TestCase as TestCase_py
             self.assertEqual(TestCase, TestCase_py)
 
-from pystacia.compat import formattable, native_str, c_ssize_t
+from pystacia.compat import formattable, native_str