From 5cf5ebf8ef5cef77e0b491f52ac37e317b06279d Mon Sep 17 00:00:00 2001 From: Richard White Date: Fri, 26 Feb 2016 20:18:49 -0500 Subject: Added frame extension. (bzr r14668.1.1) --- share/extensions/frame.inx | 32 ++++++ share/extensions/frame.py | 175 +++++++++++++++++++++++++++++++ share/extensions/test/frame_test.py | 109 +++++++++++++++++++ share/extensions/test/svg/single_box.svg | 62 +++++++++++ 4 files changed, 378 insertions(+) create mode 100644 share/extensions/frame.inx create mode 100644 share/extensions/frame.py create mode 100755 share/extensions/test/frame_test.py create mode 100644 share/extensions/test/svg/single_box.svg diff --git a/share/extensions/frame.inx b/share/extensions/frame.inx new file mode 100644 index 000000000..a2b011430 --- /dev/null +++ b/share/extensions/frame.inx @@ -0,0 +1,32 @@ + + + <_name>Frame + frame + frame.py + inkex.py + + + 000000FF + + + 00000000 + + + + + + + + + 2 + 0 + + all + + + + + + \ No newline at end of file diff --git a/share/extensions/frame.py b/share/extensions/frame.py new file mode 100644 index 000000000..c63be52e5 --- /dev/null +++ b/share/extensions/frame.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python +""" +An Inkscape extension that creates a frame around a selected object. + +Copyright (C) 2016 Richard White, rwhite8282@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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +# These two lines are only needed if you don't put the script directly into +# the installation directory +import sys +sys.path.append('/usr/share/inkscape/extensions') + +import inkex +import simplestyle +from simpletransform import * +from simplestyle import * + + +def get_picker_data(value): + """ Returns color data in style string format. + value -- The value returned from the color picker. + Returns an object with color and opacity properties. + """ + v = hex(value & 0xFFFFFFFF)[2:-1].rjust(8, '0').upper() + color = '#' + v[0:-2].rjust(6, '0') + opacity = '%1.2f' % (float(int(v[6:].rjust(2, '0'), 16))/255) + return type('', (object,), {'color':color, 'opacity':opacity})() + + +def size_box(box, delta): + """ Returns a box with an altered size. + delta -- The amount the box should grow. + Returns a box with an altered size. + """ + return ((box[0]-delta), (box[1]+delta), (box[2]-delta), (box[3]+delta)) + + +# Frame maker Inkscape effect extension +class Frame(inkex.Effect): + """ An Inkscape extension that creates a frame around a selected object. + """ + def __init__(self): + inkex.Effect.__init__(self) + self.defs = None + + # Parse the options. + self.OptionParser.add_option('--clip', + action='store', type='inkbool', + dest='clip', default=False) + self.OptionParser.add_option('--corner_radius', + action='store', type='int', + dest='corner_radius', default=0) + self.OptionParser.add_option('--fill_color', + action='store', type='int', + dest='fill_color', default='00000000') + self.OptionParser.add_option('--group', + action='store', type='inkbool', + dest='group', default=False) + self.OptionParser.add_option('--position', + action='store', type='string', + dest='position', default='outside') + self.OptionParser.add_option('--stroke_color', + action='store', type='int', + dest='stroke_color', default='00000000') + self.OptionParser.add_option('--tab', + action='store', type='string', + dest='tab', default='object') + self.OptionParser.add_option('--width', + action='store', type='float', + dest='width', default=2) + + + def add_clip(self, node, clip_path): + """ Adds a new clip path node to the defs and sets + the clip-path on the node. + node -- The node that will be clipped. + clip_path -- The clip path object. + """ + if self.defs is None: + defs_nodes = self.document.getroot().xpath('//svg:defs', namespaces=inkex.NSS) + if defs_nodes: + self.defs = defs_nodes[0] + else: + inkex.errormsg('Could not locate defs node for clip.') + return + clip = inkex.etree.SubElement(self.defs, inkex.addNS('clipPath','svg')) + clip.append(copy.deepcopy(clip_path)) + clip_id = self.uniqueId('clipPath') + clip.set('id', clip_id) + node.set('clip-path', 'url(#%s)' % str(clip_id)) + + + def add_frame(self, parent, name, box, style, radius=0): + """ Adds a new frame to the parent object. + parent -- The parent that the frame will be added to. + name -- The name of the new frame object. + box -- The boundary box of the node. + style -- The style used to draw the path. + radius -- The corner radius of the frame. + returns a new frame node. + """ + r = min([radius, (abs(box[1]-box[0])/2), (abs(box[3]-box[2])/2)]) + if (radius > 0): + d = ' '.join(str(x) for x in + ['M', box[0], (box[2]+r) + ,'A', r, r, '0 0 1', (box[0]+r), box[2] + ,'L', (box[1]-r), box[2] + ,'A', r, r, '0 0 1', box[1], (box[2]+r) + ,'L', box[1], (box[3]-r) + ,'A', r, r, '0 0 1', (box[1]-r), box[3] + ,'L', (box[0]+r), box[3] + ,'A', r, r, '0 0 1', box[0], (box[3]-r), 'Z']) + else: + d = ' '.join(str(x) for x in + ['M', box[0], box[2] + ,'L', box[1], box[2] + ,'L', box[1], box[3] + ,'L', box[0], box[3], 'Z']) + + attributes = {'style':style, inkex.addNS('label','inkscape'):name, 'd':d} + return inkex.etree.SubElement(parent, inkex.addNS('path','svg'), attributes ) + + + def effect(self): + """ Performs the effect. + """ + # Get the style values. + corner_radius = self.options.corner_radius + stroke_data = get_picker_data(self.options.stroke_color) + fill_data = get_picker_data(self.options.fill_color) + + # Determine common properties. + parent = self.current_layer + position = self.options.position + width = self.options.width + style = simplestyle.formatStyle({'stroke':stroke_data.color + , 'stroke-opacity':stroke_data.opacity + , 'stroke-width':str(width) + , 'fill':(fill_data.color if (fill_data.opacity > 0) else 'none') + , 'fill-opacity':fill_data.opacity}) + + for id, node in self.selected.iteritems(): + box = computeBBox([node]) + if 'outside' == position: + box = size_box(box, (3.5 + (width/2))) + else: + box = size_box(box, (3.5 - (width/2))) + name = 'Frame' + frame = self.add_frame(parent, name, box, style, corner_radius) + if self.options.clip: + self.add_clip(node, frame) + if self.options.group: + group = inkex.etree.SubElement(node.getparent(),inkex.addNS('g','svg')) + group.append(node) + group.append(frame) + + +if __name__ == '__main__': #pragma: no cover + # Create effect instance and apply it. + effect = Frame() + effect.affect() \ No newline at end of file diff --git a/share/extensions/test/frame_test.py b/share/extensions/test/frame_test.py new file mode 100755 index 000000000..72c5b66e8 --- /dev/null +++ b/share/extensions/test/frame_test.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +""" +An Inkscape frame extension test class. + +Copyright (C) 2016 Richard White, rwhite8282@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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +""" + +import sys +sys.path.append('/usr/share/inkscape/extensions') +sys.path.append('..') # this line allows to import the extension code + +import unittest +import inkex +from frame import * + + +class Frame_Test(unittest.TestCase): + + + def get_frame(self, document): + return document.xpath('//svg:g[@id="layer1"]//svg:path[@inkscape:label="Frame"]' + , namespaces=inkex.NSS)[0] + + + def test_empty_no_parameters(self): + args = [ 'svg/empty-SVG.svg' ] + uut = Frame() + uut.affect( args, False ) + + + def test_single_frame(self): + args = [ + '--corner_radius=20' + , '--fill_color=-16777124' + , '--id=rect3006' + , '--position=inside' + , '--stroke_color=255' + , '--tab="stroke"' + , '--width=10' + , 'svg/single_box.svg'] + uut = Frame() + uut.affect( args, False ) + new_frame = self.get_frame(uut.document) + self.assertIsNotNone(new_frame) + self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) + + + def test_single_frame_grouped(self): + args = [ + '--corner_radius=20' + , '--fill_color=-16777124' + , '--group=True' + , '--id=rect3006' + , '--position=inside' + , '--stroke_color=255' + , '--tab="stroke"' + , '--width=10' + , 'svg/single_box.svg'] + uut = Frame() + uut.affect( args, False ) + new_frame = self.get_frame(uut.document) + self.assertIsNotNone(new_frame) + self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) + group = new_frame.getparent() + self.assertEqual('{http://www.w3.org/2000/svg}g', group.tag) + self.assertEqual('{http://www.w3.org/2000/svg}rect', group[0].tag) + self.assertEqual('{http://www.w3.org/2000/svg}path', group[1].tag) + self.assertEqual("Frame", group[1].xpath('@inkscape:label', namespaces=inkex.NSS)[0]) + + + def test_single_frame_clipped(self): + args = [ + '--clip=True' + , '--corner_radius=20' + , '--fill_color=-16777124' + , '--id=rect3006' + , '--position=inside' + , '--stroke_color=255' + , '--tab="stroke"' + , '--width=10' + , 'svg/single_box.svg'] + uut = Frame() + uut.affect( args, False ) + new_frame = self.get_frame(uut.document) + self.assertIsNotNone(new_frame) + self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) + group = new_frame.getparent() + self.assertEqual('url(#clipPath)', group[0].get('clip-path')) + clip_path = uut.document.xpath('//svg:defs/svg:clipPath', namespaces=inkex.NSS)[0] + self.assertEqual('{http://www.w3.org/2000/svg}clipPath', clip_path.tag) + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/share/extensions/test/svg/single_box.svg b/share/extensions/test/svg/single_box.svg new file mode 100644 index 000000000..094233d15 --- /dev/null +++ b/share/extensions/test/svg/single_box.svg @@ -0,0 +1,62 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + -- cgit v1.2.3 From 1c7b77f8b1c6a5f59384b54884229e88966fc1d4 Mon Sep 17 00:00:00 2001 From: Richard White Date: Wed, 18 May 2016 19:35:10 -0400 Subject: Corrected frame extension stroke and fill values on 64 bit machine. The lack of L suffix in the represented hex value caused an improper interpretation. (bzr r14668.1.2) --- share/extensions/frame.py | 6 +++--- share/extensions/test/frame_test.py | 13 ++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/share/extensions/frame.py b/share/extensions/frame.py index c63be52e5..d0cafc37b 100644 --- a/share/extensions/frame.py +++ b/share/extensions/frame.py @@ -35,7 +35,7 @@ def get_picker_data(value): value -- The value returned from the color picker. Returns an object with color and opacity properties. """ - v = hex(value & 0xFFFFFFFF)[2:-1].rjust(8, '0').upper() + v = '%08X' % (value & 0xFFFFFFFF) color = '#' + v[0:-2].rjust(6, '0') opacity = '%1.2f' % (float(int(v[6:].rjust(2, '0'), 16))/255) return type('', (object,), {'color':color, 'opacity':opacity})() @@ -156,9 +156,9 @@ class Frame(inkex.Effect): for id, node in self.selected.iteritems(): box = computeBBox([node]) if 'outside' == position: - box = size_box(box, (3.5 + (width/2))) + box = size_box(box, (width/2)) else: - box = size_box(box, (3.5 - (width/2))) + box = size_box(box, (width/2)) name = 'Frame' frame = self.add_frame(parent, name, box, style, corner_radius) if self.options.clip: diff --git a/share/extensions/test/frame_test.py b/share/extensions/test/frame_test.py index 72c5b66e8..3d686ab25 100755 --- a/share/extensions/test/frame_test.py +++ b/share/extensions/test/frame_test.py @@ -58,7 +58,18 @@ class Frame_Test(unittest.TestCase): new_frame = self.get_frame(uut.document) self.assertIsNotNone(new_frame) self.assertEqual('{http://www.w3.org/2000/svg}path', new_frame.tag) - + new_frame_style = new_frame.attrib['style'].lower() + self.assertTrue('fill-opacity:0.36' in new_frame_style + , 'Invalid fill-opacity in "' + new_frame_style + '".') + self.assertTrue('stroke:#000000' in new_frame_style + , 'Invalid stroke in "' + new_frame_style + '".') + self.assertTrue('stroke-width:10.0' in new_frame_style + , 'Invalid stroke-width in "' + new_frame_style + '".') + self.assertTrue('stroke-opacity:1.00' in new_frame_style + , 'Invalid stroke-opacity in "' + new_frame_style + '".') + self.assertTrue('fill:#ff0000' in new_frame_style + , 'Invalid fill in "' + new_frame_style + '".') + def test_single_frame_grouped(self): args = [ -- cgit v1.2.3 From cf6e3cf5b4728951fafe742167e483d71fd0dba7 Mon Sep 17 00:00:00 2001 From: Richard White Date: Wed, 18 May 2016 22:06:38 -0400 Subject: Corrected frame extension inside option box size. (bzr r14668.1.4) --- share/extensions/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/extensions/frame.py b/share/extensions/frame.py index d0cafc37b..f6d54e180 100644 --- a/share/extensions/frame.py +++ b/share/extensions/frame.py @@ -158,7 +158,7 @@ class Frame(inkex.Effect): if 'outside' == position: box = size_box(box, (width/2)) else: - box = size_box(box, (width/2)) + box = size_box(box, -(width/2)) name = 'Frame' frame = self.add_frame(parent, name, box, style, corner_radius) if self.options.clip: -- cgit v1.2.3 From 814731e7a894b2ce17695c60a0b15b2a3202511a Mon Sep 17 00:00:00 2001 From: "dmitry.zhulanov@gmail.com" <> Date: Thu, 1 Jun 2017 09:28:12 +0700 Subject: improve open .yaml error message and exit with error Fixed bugs: - https://launchpad.net/bugs/1692707 (bzr r15700.1.1) --- src/main-cmdlinexact.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main-cmdlinexact.cpp b/src/main-cmdlinexact.cpp index fc9e84dc4..2806e5b5f 100644 --- a/src/main-cmdlinexact.cpp +++ b/src/main-cmdlinexact.cpp @@ -293,9 +293,11 @@ parseVerbsYAMLFile(gchar const *yaml_filename) FILE *fh = fopen(yaml_filename, "r"); if(fh == NULL) { - printf("Failed to open file!\n"); + printf("Failed to open file %s\n", yaml_filename); fflush(stdout); - return verbs_list; + + // exit with error + exit(1); } yaml_parser_t parser; -- cgit v1.2.3 From 77da39a702d151a26b7f3a85a08d79e5d7828274 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 1 Jun 2017 10:34:08 +0200 Subject: Explicitly mark input/output via UniConvertor. Helps keep track of which input/output method is being used when multiple options are available. (bzr r15703.1.19) --- share/extensions/ai_input.inx | 2 +- share/extensions/cgm_input.inx | 2 +- share/extensions/plt_input.inx | 2 +- share/extensions/plt_output.inx | 2 +- share/extensions/sk1_input.inx | 2 +- share/extensions/sk1_output.inx | 2 +- share/extensions/wmf_input.inx | 2 +- share/extensions/wmf_output.inx | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/share/extensions/ai_input.inx b/share/extensions/ai_input.inx index a48825840..bc4919500 100644 --- a/share/extensions/ai_input.inx +++ b/share/extensions/ai_input.inx @@ -6,7 +6,7 @@ .ai image/x-adobe-illustrator - <_filetypename>Adobe Illustrator 8.0 and below (*.ai) + <_filetypename>Adobe Illustrator 8.0 and below (UC) (*.ai) <_filetypetooltip>Open files saved with Adobe Illustrator 8.0 or older diff --git a/share/extensions/cgm_input.inx b/share/extensions/cgm_input.inx index e6fee4860..5c1ccd937 100644 --- a/share/extensions/cgm_input.inx +++ b/share/extensions/cgm_input.inx @@ -6,7 +6,7 @@ .cgm application/x-xcgm - <_filetypename>Computer Graphics Metafile files (*.cgm) + <_filetypename>Computer Graphics Metafile files (UC) (*.cgm) <_filetypetooltip>Open Computer Graphics Metafile files