5656# 2018-08-31 jw, V0.8 -- MacOS instructions updated and MacOS path added for autotrace 0.40.0 from
5757# https://github.com/jnweiger/autotrace/releases
5858# 2018-09-01 jw, V0.8a -- Windows Path added
59- # 2018-09-03 jw, V0.8b -- New option: cliprect, hairline, at_filter_iterations, at_error_threshold added.
59+ # 2018-09-03 jw, V0.8b -- New option: cliprect, hairline, at_filter_iterations, at_error_threshold added.
6060# Fixed stroke_width of scaled images.
61+ # 2018-09-04 jw, V0.8c -- Fixed https://github.com/fablabnbg/inkscape-centerline-trace/issues/28
62+ # Hints for https://github.com/fablabnbg/inkscape-centerline-trace/issues/27 added.
6163
6264
63- __version__ = '0.8b ' # Keep in sync with centerline-trace.inx ca. line 3 and 24
65+ __version__ = '0.8c ' # Keep in sync with centerline-trace.inx ca. line 3 and 24
6466__author__ = 'Juergen Weigert <[email protected] >' 6567
6668import sys , os , re , math , tempfile , subprocess , base64 , time
7577 sys .exit (1 )
7678
7779
78- # debug = True
7980debug = False
81+ # debug = True
8082
8183autotrace_exe = 'autotrace'
8284
@@ -139,13 +141,14 @@ def __init__(self):
139141
140142 p = subprocess .Popen (command , shell = True , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
141143 return_code = p .wait ()
142- f = p .stdout
143- err = p .stderr
144144
145- out = p .communicate ()[ 0 ]
145+ out , err = p .communicate ()
146146
147147 found = out .find ('AutoTrace' )
148148 if found == - 1 :
149+ print >> sys .stderr , err
150+ if err .find ('cannot open shared object file' ):
151+ print >> sys .stderr , "NOTE: This build of autotrace is incompatible with your system, try a different build.\n "
149152 print >> sys .stderr , "You need to install autotrace for this extension to work. Try https://github.com/jnweiger/autotrace/releases or search for autotrace version 0.40.0 or later."
150153 exit ()
151154
@@ -198,7 +201,7 @@ def svg_centerline_trace(self, image_file, cliprect=None):
198201 Then we run several iterations of autotrace and find the optimal black white threshold by evaluating
199202 all outputs. The output with the longest total path and the least path elements wins.
200203
201- A cliprect dict with the keys x, y, w, h can be specified. All 4 are expected in the
204+ A cliprect dict with the keys x, y, w, h can be specified. All 4 are expected in the
202205 range 0..1 and are mapped to the image width and height.
203206 """
204207 num_attempts = self .candidates # 15 is great. min 1, max 255, beware it gets much slower with more attempts.
@@ -252,7 +255,8 @@ def svg_centerline_trace(self, image_file, cliprect=None):
252255 if self .filter_median > 0 :
253256 if self .filter_median % 2 == 0 : self .filter_median = self .filter_median + 1 # need odd values.
254257 im = im .filter (ImageFilter .MedianFilter (size = self .filter_median )) # feeble denoise attempt. FIXME: try ROF instead.
255- im = ImageOps .autocontrast (im , cutoff = 2 ) # linear expand histogram (an alternative to equalize)
258+ im = ImageOps .autocontrast (im , cutoff = 0 ) # linear expand histogram (an alternative to equalize)
259+ ## cutoff=2 destroys some images, see https://github.com/fablabnbg/inkscape-centerline-trace/issues/28
256260
257261 # not needed here:
258262 # im = im.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)) # parameters depend on size of image!
@@ -324,7 +328,7 @@ def svg_pathstats(path_d):
324328 if debug : print >> self .tty , "bw from lut done: threshold=%d" % threshold
325329 if self .options .debug : bw .show (command = "/usr/bin/display -title=bw:threshold=%d" % threshold )
326330 cand = { 'threshold' :threshold , 'img_width' :bw .size [0 ], 'img_height' :bw .size [1 ], 'mean' : ImageStat .Stat (im ).mean [0 ] }
327- fp = tempfile .NamedTemporaryFile (prefix = "certerlinetrace " , suffix = '.pbm' , delete = False )
331+ fp = tempfile .NamedTemporaryFile (prefix = "centerlinetrace " , suffix = '.pbm' , delete = False )
328332 fp .write ("P4\n %d %d\n " % (bw .size [0 ], bw .size [1 ]))
329333 fp .write (bw .tobytes ())
330334 fp .close ()
@@ -347,6 +351,7 @@ def svg_pathstats(path_d):
347351 cand ['svg' ] = '<svg/>' # empty dummy
348352 else :
349353 os .unlink (fp .name )
354+
350355 # <?xml version="1.0" standalone="yes"?>\n<svg width="86" height="83">\n<path style="stroke:#000000; fill:none;" d="M36 15C37.9219 18.1496 41.7926 19.6686 43.2585 23.1042C47.9556 34.1128 39.524 32.0995 35.179 37.6034C32.6296 40.8328 34 48.1105 34 52M36 17C32.075 22.4565 31.8375 30.074 35 36M74 42L46 38C45.9991 46.1415 46.7299 56.0825 45.6319 64C44.1349 74.7955 23.7094 77.5566 16.044 72.3966C7.27363 66.4928 8.04426 45.0047 16.2276 38.7384C20.6362 35.3626 27.7809 36.0006 33 36M44 37L45 37"/>\n</svg>
351356 try :
352357 xml = inkex .etree .fromstring (cand ['svg' ])
@@ -418,6 +423,7 @@ def effect(self):
418423 if self .options .hairline is not None : self .hairline = self .options .hairline
419424 if self .options .hairline_width is not None : self .hairline_width = self .options .hairline_width
420425 # if self.options.debug is not None: debug = self.options.debug
426+ # self.options.debug = True
421427
422428 self .calc_unit_factor ()
423429
@@ -465,12 +471,13 @@ def effect(self):
465471 cliprect ['x' ] = cliprect ['x' ] - svg_x_off
466472 cliprect ['y' ] = cliprect ['y' ] - svg_y_off
467473 cliprect ['x' ] = cliprect ['x' ] / svg_img_w
468- cliprect ['y' ] = cliprect ['y' ] / svg_img_h
474+ cliprect ['y' ] = cliprect ['y' ] / svg_img_h
469475 cliprect ['w' ] = cliprect ['w' ] / svg_img_w
470- cliprect ['h' ] = cliprect ['h' ] / svg_img_h
476+ cliprect ['h' ] = cliprect ['h' ] / svg_img_h
471477
472478 # handle two cases. Embedded and linked images
473479 # <image .. xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAT8AA ..." preserveAspectRatio="none" height="432" width="425" transform="matrix(1,0,-0.52013328,0.85408511,0,0)"/>
480+ # <image .. xlink:href="xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgAB..."
474481 # <image .. xlink:href="file:///home/jw/schaf.png"
475482
476483 href = str (node .get (inkex .addNS ('href' ,'xlink' )))
@@ -496,12 +503,12 @@ def effect(self):
496503 type = href [11 :11 + l ] # 'png' 'jpeg'
497504 if debug : print >> self .tty , "embedded image: " + href [:11 + l ]
498505 img = base64 .decodestring (href [11 + l + 8 :])
499- f = tempfile .NamedTemporaryFile (mode = "wb" , suffix = "." + type , delete = False )
506+ f = tempfile .NamedTemporaryFile (mode = "wb" , prefix = 'centerlinetrace' , suffix = "." + type , delete = False )
500507 f .write (img )
501508 filename = f .name
502509 f .close ()
503510 else :
504- inkex .errormsg (_ ("Neither file:// nor data:image/png ; prefix. Cannot parse PNG image href " + href ))
511+ inkex .errormsg (_ ("Neither file:// nor data:image/; prefix. Cannot parse PNG/JPEG image href " + href [: 200 ] + "..." ))
505512 sys .exit (1 )
506513 if debug : print >> self .tty , "filename=" + filename
507514 #
@@ -540,7 +547,7 @@ def effect(self):
540547 ## insert the new path object
541548 inkex .etree .SubElement (self .current_layer , inkex .addNS ('path' , 'svg' ), path_attr )
542549 ## delete the old image object
543- if self .replace_image :
550+ if self .replace_image :
544551 node .getparent ().remove (node )
545552 if cliprect is not None : # and its cliprect ...
546553 cliprect ['node' ].getparent ().remove (cliprect ['node' ])
0 commit comments