summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarenhachmann <>2016-05-13 20:04:14 +0000
committerJazzyNico <nicoduf@yahoo.fr>2016-05-13 20:04:14 +0000
commit6409a4a7d4bf0254f162e01bbef9a9d4ba622607 (patch)
tree599fbe2c887995f71af54c6cbeeb25e14abe3c13
parentExtensions. Improving the test launcher. Now works with recent coverage versi... (diff)
downloadinkscape-6409a4a7d4bf0254f162e01bbef9a9d4ba622607.tar.gz
inkscape-6409a4a7d4bf0254f162e01bbef9a9d4ba622607.zip
[Bug #1579939] Ramdom color extension improvements (and new unit test file).
Fixed bugs: - https://launchpad.net/bugs/1579939 Original authors: - marenhachmann - jazzynico <nicoduf@yahoo.fr> (bzr r14884)
-rw-r--r--share/extensions/color_randomize.inx7
-rwxr-xr-x[-rw-r--r--]share/extensions/color_randomize.py105
-rwxr-xr-xshare/extensions/coloreffect.py34
-rw-r--r--share/extensions/test/Makefile.am1
-rwxr-xr-xshare/extensions/test/color_randomize.test.py123
5 files changed, 205 insertions, 65 deletions
diff --git a/share/extensions/color_randomize.inx b/share/extensions/color_randomize.inx
index 0c84227ae..c0c0d9ea2 100644
--- a/share/extensions/color_randomize.inx
+++ b/share/extensions/color_randomize.inx
@@ -7,16 +7,13 @@
<dependency type="executable" location="extensions">simplestyle.py</dependency>
<param name="tab" type="notebook">
<page name="Options" _gui-text="Options">
- <param name="hue" type="boolean" _gui-text="Hue">true</param>
<param name="hue_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Hue range (%)">100</param>
- <param name="saturation" type="boolean" _gui-text="Saturation">true</param>
<param name="saturation_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Saturation range (%)">100</param>
- <param name="lightness" type="boolean" _gui-text="Lightness">true</param>
<param name="lightness_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Lightness range (%)">100</param>
-
+ <param name="opacity_range" type="int" appearance="full" min="0" max="100" indent="0" _gui-text="Opacity range (%)">0</param>
</page>
<page name="Help" _gui-text="Help">
- <_param name="instructions" type="description" xml:space="preserve">Converts to HSL, randomizes hue and/or saturation and/or lightness and converts it back to RGB. Lower the range values to limit the distance between the original color and the randomized one.</_param>
+ <_param name="instructions" type="description" xml:space="preserve">Randomizes hue, saturation, lightness and/or opacity (opacity randomization only for objects and groups). Change the range values to limit the distance between the original color and the randomized one.</_param>
</page>
</param>
<effect>
diff --git a/share/extensions/color_randomize.py b/share/extensions/color_randomize.py
index b8f52cb6b..93abcf174 100644..100755
--- a/share/extensions/color_randomize.py
+++ b/share/extensions/color_randomize.py
@@ -1,85 +1,84 @@
#!/usr/bin/env python
-import coloreffect,random,inkex
+
+import random
+
+import coloreffect
+import inkex
class C(coloreffect.ColorEffect):
def __init__(self):
coloreffect.ColorEffect.__init__(self)
- self.OptionParser.add_option("-x", "--hue",
- action="store", type="inkbool",
- dest="hue", default=True,
- help="Randomize hue")
self.OptionParser.add_option("-y", "--hue_range",
action="store", type="int",
dest="hue_range", default=0,
help="Hue range")
- self.OptionParser.add_option("-s", "--saturation",
- action="store", type="inkbool",
- dest="saturation", default=True,
- help="Randomize saturation")
self.OptionParser.add_option("-t", "--saturation_range",
action="store", type="int",
dest="saturation_range", default=0,
help="Saturation range")
- self.OptionParser.add_option("-l", "--lightness",
- action="store", type="inkbool",
- dest="lightness", default=True,
- help="Randomize lightness")
self.OptionParser.add_option("-m", "--lightness_range",
action="store", type="int",
dest="lightness_range", default=0,
help="Lightness range")
+ self.OptionParser.add_option("-o", "--opacity_range",
+ action="store", type="int",
+ dest="opacity_range", default=0,
+ help="Opacity range")
self.OptionParser.add_option("--tab",
action="store", type="string",
dest="tab",
help="The selected UI-tab when OK was pressed")
+ def randomize_hsl(self, limit, current_value):
+ limit = 255.0 * limit / 100.0
+ limit /= 2
+ max = int((current_value * 255.0) + limit)
+ min = int((current_value * 255.0) - limit)
+ if max > 255:
+ min = min - (max - 255)
+ max = 255
+ if min < 0:
+ max = max - min
+ min = 0
+ return random.randrange(min, max) / 255.0
+
def colmod(self,r,g,b):
hsl = self.rgb_to_hsl(r/255.0, g/255.0, b/255.0)
-
- if(self.options.hue):
- limit = 255.0 * (1 + self.options.hue_range) / 100.0
- limit /= 2
- max = int((hsl[0] * 255.0) + limit)
- min = int((hsl[0] * 255.0) - limit)
- if max > 255:
- min = min - (max - 255)
- max = 255
- if min < 0:
- max = max - min
- min = 0
- hsl[0] = random.randrange(min, max)
- hsl[0] /= 255.0
- if(self.options.saturation):
- limit = 255.0 * (1 + self.options.saturation_range) / 100.0
- limit /= 2
- max = int((hsl[1] * 255.0) + limit)
- min = int((hsl[1] * 255.0) - limit)
- if max > 255:
- min = min - (max - 255)
- max = 255
- if min < 0:
- max = max - min
- min = 0
- hsl[1] = random.randrange(min, max)
- hsl[1] /= 255.0
- if(self.options.lightness):
- limit = 255.0 * (1 + self.options.lightness_range) / 100.0
+ if self.options.hue_range > 0:
+ hsl[0] = self.randomize_hsl(self.options.hue_range, hsl[0])
+ if self.options.saturation_range > 0:
+ hsl[1] = self.randomize_hsl(self.options.saturation_range, hsl[1])
+ if self.options.lightness_range > 0:
+ hsl[2] = self.randomize_hsl(self.options.lightness_range, hsl[2])
+ rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2])
+ return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255)
+
+ def opacmod(self, opacity):
+ if self.options.opacity_range > 0:
+ # maybe not necessary, but better not change things that shouldn't change
+ try:
+ opacity = float(opacity)
+ except ValueError:
+ return opacity
+
+ limit = self.options.opacity_range
limit /= 2
- max = int((hsl[2] * 255.0) + limit)
- min = int((hsl[2] * 255.0) - limit)
- if max > 255:
- min = min - (max - 255)
- max = 255
+ max = opacity*100 + limit
+ min = opacity*100 - limit
+ if max > 100:
+ min = min - (max - 100)
+ max = 100
if min < 0:
max = max - min
min = 0
- hsl[2] = random.randrange(min, max)
- hsl[2] /= 255.0
- rgb = self.hsl_to_rgb(hsl[0], hsl[1], hsl[2])
- return '%02x%02x%02x' % (rgb[0]*255, rgb[1]*255, rgb[2]*255)
+ ret = str(random.uniform(min,max)/100)
+ return ret
+ return opacity
+
-c = C()
-c.affect()
+if __name__ == '__main__':
+ c = C()
+ c.affect()
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
diff --git a/share/extensions/coloreffect.py b/share/extensions/coloreffect.py
index a6b5cfe41..d33ac41fe 100755
--- a/share/extensions/coloreffect.py
+++ b/share/extensions/coloreffect.py
@@ -21,8 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import sys, copy, simplestyle, inkex
import random
-color_props_fill = ('fill', 'stop-color', 'flood-color', 'lighting-color')
+color_props_fill = ('fill', 'stop-color', 'flood-color', 'lighting-color')
color_props_stroke = ('stroke',)
+opacity_props = ('opacity',) #'stop-opacity', 'fill-opacity', 'stroke-opacity' don't work with clones
color_props = color_props_fill + color_props_stroke
@@ -63,13 +64,14 @@ class ColorEffect(inkex.Effect):
#
# The processing here is just something simple that should usually work,
# without trying too hard to get everything right.
- # (Won't work for the pathalogical case that someone escapes a property
+ # (Won't work for the pathological case that someone escapes a property
# name, probably does the wrong thing if colon or semicolon is used inside
# a comment or string value.)
style = node.get('style') # fixme: this will break for presentation attributes!
if style:
#inkex.debug('old style:'+style)
declarations = style.split(';')
+ opacity_in_style = False
for i,decl in enumerate(declarations):
parts = decl.split(':', 2)
if len(parts) == 2:
@@ -80,16 +82,25 @@ class ColorEffect(inkex.Effect):
new_val = self.process_prop(val)
if new_val != val:
declarations[i] = prop + ':' + new_val
+ elif prop in opacity_props:
+ opacity_in_style = True
+ val = val.strip()
+ new_val = self.process_prop(val)
+ if new_val != val:
+ declarations[i] = prop + ':' + new_val
+ if not opacity_in_style:
+ new_val = self.process_prop("1")
+ declarations.append('opacity' + ':' + new_val)
#inkex.debug('new style:'+';'.join(declarations))
node.set('style', ';'.join(declarations))
- def process_prop(self,col):
- #debug('got:'+col)
+ def process_prop(self, col):
+ #inkex.debug('got:'+col+str(type(col)))
if simplestyle.isColor(col):
c=simplestyle.parseColor(col)
- col='#'+self.colmod(c[0],c[1],c[2])
- #debug('made:'+col)
- if col.startswith('url(#'):
+ col='#'+self.colmod(c[0], c[1], c[2])
+ #inkex.debug('made:'+col)
+ elif col.startswith('url(#'):
id = col[len('url(#'):col.find(')')]
newid = '%s-%d' % (id, int(random.random() * 1000))
#inkex.debug('ID:' + id )
@@ -97,6 +108,11 @@ class ColorEffect(inkex.Effect):
for node in self.document.xpath(path, namespaces=inkex.NSS):
self.process_gradient(node, newid)
col = 'url(#%s)' % newid
+ # what remains should be opacity
+ else:
+ col = self.opacmod(col)
+
+ #inkex.debug('col:'+str(col))
return col
def process_gradient(self, node, newid):
@@ -128,6 +144,9 @@ class ColorEffect(inkex.Effect):
def colmod(self,r,g,b):
pass
+
+ def opacmod(self, opacity):
+ return opacity
def rgb_to_hsl(self,r, g, b):
rgb_max = max (max (r, g), b)
@@ -188,4 +207,5 @@ class ColorEffect(inkex.Effect):
rgb[2] = self.hue_2_rgb (v1, v2, h*6 - 2.0)
return rgb
+
# vi: set autoindent shiftwidth=2 tabstop=8 expandtab softtabstop=2 :
diff --git a/share/extensions/test/Makefile.am b/share/extensions/test/Makefile.am
index 7ff68083d..cd1929a7f 100644
--- a/share/extensions/test/Makefile.am
+++ b/share/extensions/test/Makefile.am
@@ -6,6 +6,7 @@
EXTRA_DIST = \
addnodes.test.py \
chardataeffect.test.py \
+ color_randomize_test.py \
coloreffect.test.py \
create_test_from_template.sh \
dots.test.py \
diff --git a/share/extensions/test/color_randomize.test.py b/share/extensions/test/color_randomize.test.py
new file mode 100755
index 000000000..d8549a35a
--- /dev/null
+++ b/share/extensions/test/color_randomize.test.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+'''
+Unit test file for ../color_randomize.py
+--
+If you want to help, read the python unittest documentation:
+http://docs.python.org/library/unittest.html
+'''
+
+import os
+import sys
+import unittest
+
+sys.path.append('..') # this line allows to import the extension code
+from color_randomize import *
+
+def extract_hsl(e,rgb):
+ r = int(rgb[:2], 16)
+ g = int(rgb[2:4], 16)
+ b = int(rgb[4:6], 16)
+ return e.rgb_to_hsl(r/255.0, g/255.0, b/255.0)
+
+
+class ColorRandomizeBasicTest(unittest.TestCase):
+ def setUp(self):
+ self.e=C()
+
+ def test_default_values(self):
+ """ The default ranges are set to 0, and thus the color and opacity should not change. """
+ args = ['svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ col = self.e.colmod(128, 128, 255)
+ self.assertEqual("8080ff", col)
+ opac = self.e.opacmod(5)
+ self.assertEqual(5, opac)
+
+
+class ColorRandomizeColorModificationTest(unittest.TestCase):
+ def setUp(self):
+ self.e=C()
+
+ def test_no_change(self):
+ """ The user selected 0% values, and thus the color should not change. """
+ args = ['-y 0', '-t 0', '-m 0', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ col = self.e.colmod(128, 128, 255)
+ self.assertEqual("8080ff", col)
+
+ def test_random_hue(self):
+ """ Random hue only. Saturation and lightness not changed. """
+ args = ['-y 50','-t 0','-m 0','svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200))
+ self.assertEqual([0.47, 0.59], [round(hsl[1], 2), round(hsl[2], 2)])
+
+ @unittest.skip("Inaccurate convertion")
+ def test_random_lightness(self):
+ """ Random lightness only. Hue and saturation not changed. """
+ args = ['-y 0', '-t 0', '-m 50', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200))
+ # Lightness change also affects hue and saturation...
+ #self.assertEqual(0.75, round(hsl[0], 2))
+ #self.assertEqual(0.48, round(hsl[1], 2))
+
+ def test_random_saturation(self):
+ """ Random saturation only. Hue and lightness not changed. """
+ args = ['-y 0', '-t 50', '-m 0', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ hsl = extract_hsl(self.e, self.e.colmod(150, 100, 200))
+ self.assertEqual([0.75, 0.59], [round(hsl[0], 2), round(hsl[2], 2)])
+
+ def test_range_limits(self):
+ """ The maximum hsl values should be between 0 and 100% of their maximum """
+ args = ['-y 100', '-t 100', '-m 100', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ hsl = extract_hsl(self.e, self.e.colmod(156, 156, 156))
+ self.assertLessEqual([hsl[0], hsl[1], hsl[2]], [1, 1, 1])
+ self.assertGreaterEqual([hsl[0], hsl[1], hsl[2]], [0, 0, 0])
+
+
+class ColorRandomizeOpacityModificationTest(unittest.TestCase):
+ def setUp(self):
+ self.e=C()
+
+ def test_no_change(self):
+ """ The user selected 0% opacity range, and thus the opacity should not change. """
+ args = ['-o 0', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ opac = self.e.opacmod(0.15)
+ self.assertEqual(0.15, opac)
+
+ def test_range_min_limit(self):
+ """ The opacity value should be greater than 0 """
+ args = ['-o 100', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ opac = self.e.opacmod(0)
+ self.assertGreaterEqual(opac, "0")
+
+ def test_range_max_limit(self):
+ """ The opacity value should be lesser than 1 """
+ args = ['-o 100', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ opac = self.e.opacmod(1)
+ self.assertLessEqual(opac, "1")
+
+ def test_non_float_opacity(self):
+ """ Non-float opacity value not changed """
+ args = ['-o 100', 'svg/empty-SVG.svg']
+ self.e.affect(args, False)
+ opac = self.e.opacmod("toto")
+ self.assertLessEqual(opac, "toto")
+
+if __name__ == '__main__':
+ #unittest.main()
+ suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeBasicTest)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeColorModificationTest)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+ suite = unittest.TestLoader().loadTestsFromTestCase(ColorRandomizeOpacityModificationTest)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99