From 64147b59feee1c9091deec4f5c909da7d401a4f3 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Tue, 24 May 2016 19:26:59 +0200 Subject: [PATCH 1/5] removed ImageCreate[] in favour of Image[] alone. adds width and height tags to . --- mathics/builtin/__init__.py | 15 --------------- mathics/builtin/base.py | 10 ++++++++++ mathics/builtin/image.py | 37 +++++++++++++++++++++---------------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/mathics/builtin/__init__.py b/mathics/builtin/__init__.py index 594b3d2eba..3d605df166 100755 --- a/mathics/builtin/__init__.py +++ b/mathics/builtin/__init__.py @@ -125,18 +125,3 @@ def contribute(definitions): if not definitions.have_definition(ensure_context(operator)): op = ensure_context(operator) definitions.builtin[op] = Definition(name=op) - - # Special case for Image[]: Image[] is an atom, and so Image[...] - # will not usually evaluate to anything, since there are no rules - # attached to it. we're adding one special rule here, that allows - # to construct Image atoms by using Image[] (using the helper - # builin ImageCreate). - from mathics.core.rules import Rule - from mathics.builtin.image import Image - from mathics.core.parser import parse_builtin_rule - - definition = Definition( - name='System`Image', rules=[ - Rule(parse_builtin_rule('Image[x_]'), - parse_builtin_rule('ImageCreate[x]'), system=True)]) - definitions.builtin['System`Image'] = definition diff --git a/mathics/builtin/base.py b/mathics/builtin/base.py index f56c7afca7..1f9693957b 100644 --- a/mathics/builtin/base.py +++ b/mathics/builtin/base.py @@ -217,6 +217,16 @@ def init(self, *args, **kwargs): pass +class AtomBuiltin(Builtin): + # allows us to define apply functions, rules, messages, etc. for Atoms + # which are by default not in the definitions' contribution pipeline. + # see Image[] for an example of this. + + def get_name(self): + name = super(AtomBuiltin, self).get_name() + return re.sub(r"Atom$", "", name) + + class Operator(Builtin): operator = None precedence = None diff --git a/mathics/builtin/image.py b/mathics/builtin/image.py index 0ce4f500eb..47bfb805d5 100644 --- a/mathics/builtin/image.py +++ b/mathics/builtin/image.py @@ -12,7 +12,7 @@ from __future__ import division from mathics.builtin.base import ( - Builtin, Test, BoxConstruct, String) + Builtin, AtomBuiltin, Test, BoxConstruct, String) from mathics.core.expression import ( Atom, Expression, Integer, Rational, Real, Symbol, from_python) from mathics.core.evaluation import Evaluation @@ -1134,25 +1134,14 @@ def _image_pixels(matrix): return None -class ImageCreate(Builtin): - def apply(self, array, evaluation): - '''ImageCreate[array_]''' - pixels = _image_pixels(array.to_python()) - if pixels is not None: - shape = pixels.shape - is_rgb = (len(shape) == 3 and shape[2] == 3) - return Image(pixels.clip(0, 1), 'RGB' if is_rgb else 'Grayscale') - else: - return Symbol('$Aborted') - - class ImageBox(BoxConstruct): def boxes_to_text(self, leaves, **options): return '-Image-' def boxes_to_xml(self, leaves, **options): # see https://tools.ietf.org/html/rfc2397 - img = '' % (leaves[0].get_string_value()) + img = '' % ( + leaves[0].get_string_value(), leaves[1].get_int_value(), leaves[2].get_int_value()) # see https://github.com/mathjax/MathJax/issues/896 xml = '%s' % img @@ -1198,12 +1187,16 @@ def make_boxes(self, form): width = shape[1] height = shape[0] + scaled_width = width + scaled_height = height # if the image is very small, scale it up using nearest neighbour. min_size = 128 if width < min_size and height < min_size: scale = min_size / max(width, height) - pixels = skimage.transform.resize(pixels, (int(scale * height), int(scale * width)), order=0) + scaled_width = int(scale * width) + scaled_height = int(scale * height) + pixels = skimage.transform.resize(pixels, (scaled_height, scaled_width), order=0) stream = BytesIO() skimage.io.imsave(stream, pixels, 'pil', format_str='png') @@ -1215,7 +1208,7 @@ def make_boxes(self, form): if not six.PY2: encoded = encoded.decode('utf8') - return Expression('ImageBox', String(encoded), Integer(width), Integer(height)) + return Expression('ImageBox', String(encoded), Integer(scaled_width), Integer(scaled_height)) except: return Symbol("$Failed") @@ -1268,3 +1261,15 @@ def storage_type(self): return 'Bit' else: return str(dtype) + + +class ImageAtom(AtomBuiltin): + def apply_create(self, array, evaluation): + 'Image[array_]' + pixels = _image_pixels(array.to_python()) + if pixels is not None: + shape = pixels.shape + is_rgb = (len(shape) == 3 and shape[2] == 3) + return Image(pixels.clip(0, 1), 'RGB' if is_rgb else 'Grayscale') + else: + return Expression('Image', array) From f2e83d828c54502cda7c644c4ba054f35cfd4a9f Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Tue, 24 May 2016 19:30:41 +0200 Subject: [PATCH 2/5] adds support for classic Mathics branch --- mathics/builtin/image.py | 13 ++++++++++--- mathics/web/media/js/mathics.js | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/mathics/builtin/image.py b/mathics/builtin/image.py index 47bfb805d5..39544e99f8 100644 --- a/mathics/builtin/image.py +++ b/mathics/builtin/image.py @@ -1143,9 +1143,16 @@ def boxes_to_xml(self, leaves, **options): img = '' % ( leaves[0].get_string_value(), leaves[1].get_int_value(), leaves[2].get_int_value()) - # see https://github.com/mathjax/MathJax/issues/896 - xml = '%s' % img - return xml + # if we have Mathics JavaScript frontend processing that rewrites MathML tags using + # , we must not embed our tag in here. + uses_mathics_frontend_processing = False + + if not uses_mathics_frontend_processing: + # see https://github.com/mathjax/MathJax/issues/896 + xml = '%s' % img + return xml + else: + return img def boxes_to_tex(self, leaves, **options): return '-Image-' diff --git a/mathics/web/media/js/mathics.js b/mathics/web/media/js/mathics.js index 2ea9d0d8e8..3feed392b2 100644 --- a/mathics/web/media/js/mathics.js +++ b/mathics/web/media/js/mathics.js @@ -202,11 +202,11 @@ function translateDOMElement(element, svg) { drawGraphics3D(div, data); dom = div; } - if (nodeName == 'svg' || nodeName == 'graphics3d') { + if (nodeName == 'svg' || nodeName == 'graphics3d' || nodeName.toLowerCase() == 'img') { // create that will contain the graphics object = createMathNode('mspace'); var width, height; - if (nodeName == 'svg') { + if (nodeName == 'svg' || nodeName.toLowerCase() == 'img') { width = dom.getAttribute('width'); height = dom.getAttribute('height'); } else { From 4e444095218cf99c9120677060e0c61fd40bc356 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Tue, 24 May 2016 19:36:17 +0200 Subject: [PATCH 3/5] adds ImageQ --- mathics/builtin/image.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mathics/builtin/image.py b/mathics/builtin/image.py index 39544e99f8..95457c2b49 100644 --- a/mathics/builtin/image.py +++ b/mathics/builtin/image.py @@ -1134,6 +1134,16 @@ def _image_pixels(matrix): return None +class ImageQ(Builtin): + def apply_image(self, image, evaluation): + 'ImageQ[image_Image]' + return Symbol('True') + + def apply_no_image(self, array, evaluation): + 'ImageQ[Image[array_]]' + return Symbol('False') + + class ImageBox(BoxConstruct): def boxes_to_text(self, leaves, **options): return '-Image-' From 8fe3c5dff941a670eac4098a414c6efc3a3554ac Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Wed, 25 May 2016 07:22:23 +0200 Subject: [PATCH 4/5] changed ImageQ to Test, fixed BinaryImageQ (was Test, but did not define test()) --- mathics/builtin/image.py | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/mathics/builtin/image.py b/mathics/builtin/image.py index 95457c2b49..7a221e97e2 100644 --- a/mathics/builtin/image.py +++ b/mathics/builtin/image.py @@ -1114,9 +1114,15 @@ def apply(self, image, evaluation): class BinaryImageQ(Test): - def apply(self, image, evaluation): - 'BinaryImageQ[image_Image]' - return Symbol('True') if image.storage_type() == 'Bit' else Symbol('False') + ''' +
+
'BinaryImageQ[$image]' +
returns True if the pixels of $image are binary bit values, and False otherwise. +
+ ''' + + def test(self, expr): + return isinstance(expr, Image) and expr.storage_type() == 'Bit' # Image core classes @@ -1134,14 +1140,28 @@ def _image_pixels(matrix): return None -class ImageQ(Builtin): - def apply_image(self, image, evaluation): - 'ImageQ[image_Image]' - return Symbol('True') +class ImageQ(Test): + ''' +
+
'ImageQ[Image[$pixels]]' +
returns True if $pixels has dimensions from which an Image can be constructed, and False otherwise. +
+ + >> ImageQ[Image[{{0, 1}, {1, 0}}]] + = True + + >> ImageQ[Image[{{{0, 0, 0}, {0, 1, 0}}, {{0, 1, 0}, {0, 1, 1}}}]] + = True + + >> ImageQ[Image[{{{0, 0, 0}, {0, 1}}, {{0, 1, 0}, {0, 1, 1}}}]] + = False + + >> ImageQ[Image[{1, 0, 1}]] + = False + ''' - def apply_no_image(self, array, evaluation): - 'ImageQ[Image[array_]]' - return Symbol('False') + def test(self, expr): + return isinstance(expr, Image) class ImageBox(BoxConstruct): From 898216bf4a6870a1ce19c644883bd9bd18ef8634 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Wed, 25 May 2016 07:29:06 +0200 Subject: [PATCH 5/5] one more test case for ImageQ --- mathics/builtin/image.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mathics/builtin/image.py b/mathics/builtin/image.py index 7a221e97e2..b0ab9612bc 100644 --- a/mathics/builtin/image.py +++ b/mathics/builtin/image.py @@ -1158,6 +1158,9 @@ class ImageQ(Test): >> ImageQ[Image[{1, 0, 1}]] = False + + >> ImageQ["abc"] + = False ''' def test(self, expr):