SaveAs Optimized SVG error "AttributeError: 'SVGLength' object has no attribute 'units'"

Bug #541889 reported by Matt Sarjent
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Inkscape
Fix Released
Low
jazzynico
Scour
Fix Released
Undecided
Unassigned

Bug Description

Hi, love Inkscape, especially using python :-) although i'm post-processing/parsing svg with beautifulSoup.

I have been trying to save a file with the fill attributes separate to the style attributes so i tried to save using the "Optimized SVG" file type option. Unfortunately i keep on getting the error

Traceback (most recent call last):
  File "C:\Program Files\Inkscape\share\extensions\scour.inkscape.py", line 6, in <module>
    sys.stdout.write(scourString(input.read()).encode("UTF-8"))
  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 2245, in scourString
    cleanPolygon(polygon)
  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 1803, in cleanPolygon
    pts = parseListOfPoints(elem.getAttribute('points'))
  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 1790, in parseListOfPoints
    if x.units != Unit.NONE or y.units != Unit.NONE: return []
AttributeError: 'SVGLength' object has no attribute 'units'

so i traced it through to the scour.py where the SVGLength doesn't set the self.units in all cases after a ValueError in thrown.

so i added in the extra case giving the new code

class SVGLength(object):
 def __init__(self, str):
  try: # simple unitless and no scientific notation
   self.value = float(str)
   if int(self.value) == self.value:
    self.value = int(self.value)
   self.units = Unit.NONE
  except ValueError:
   # we know that the length string has an exponent, a unit, both or is invalid

   # parse out number, exponent and unit
   self.value = 0
   unitBegin = 0
   scinum = scinumber.match(str)
   if scinum != None:
    # this will always match, no need to check it
    numMatch = number.match(str)
    expMatch = sciExponent.search(str, numMatch.start(0))
    self.value = (float(numMatch.group(0)) *
     10 ** float(expMatch.group(1)))
    unitBegin = expMatch.end(1)
   else:
    # unit or invalid
    numMatch = number.match(str)
    if numMatch != None:
     self.value = float(numMatch.group(0))
     unitBegin = numMatch.end(0)

   if int(self.value) == self.value:
    self.value = int(self.value)

   if unitBegin != 0 :
    unitMatch = unit.search(str, unitBegin)
    if unitMatch != None :
     self.units = Unit.get(unitMatch.group(0))
    else: # new added code
     self.units = Unit.INVALID # new added code

   # invalid
   else:
    # TODO: this needs to set the default for the given attribute (how?)
    self.value = 0
    self.units = Unit.INVALID

Unfortunately i am not allowed to give you the original file until after 6th May. After that, give me an email if you need the file.

Related branches

Revision history for this message
jazzynico (jazzynico) wrote :

Hi,

Which inkscape version do you use?
Could you please try to extract the part of your file which produces this bug, so that we can try to reproduce it?

tags: added: exporting extensions-plugins
Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

The Inkscape build is: Inkscape 0.47 r22583, built Nov 21 2009
I will try and get a cutdown version of the file to you aswell.

Revision history for this message
codedread (codedread) wrote :

Hi Matt,

Perhaps can you just give me the points="....." attribute value that's causing the trouble?

Thanks,
Jeff

Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

Hi, i've attached a cut-down version of the file, also added here the diff of my fix

$ diff scour.py scourOriginal.py
359,360c359,360
< else: # new added code
< self.units = Unit.INVALID # new added code
---
> else:
> self.units = Unit.INVALID

Hope this helps

Revision history for this message
codedread (codedread) wrote :

Hi Matt,

I reduced the test further to the following:

<?xml version='1.0' encoding='utf-8'?>
<svg xmlns="http://www.w3.org/2000/svg">
 <polygon fill="red transform="translate(100,100)" points="0,0,100,0,100,-100,0,-100" />
 <polygon fill="green" transform="translate(100,100)" points="0,0,100,0,100-100,0-100" />
</svg>

You will notice that Opera, Safari and IE9 show the green polygon but Firefox does not.

I am investigating into the SVG spec, where the syntax of the @points attribute is discussed. Question has been asked here: http://lists.w3.org/Archives/Public/www-svg/2010Mar/0050.html

Once I get confirmation from the SVG WG that 100-100 is valid in polygon points, I can update scour.

Until then, can you tell me what tool is producing those polygons for you? Is it possible to fix the tool so that it emits commas between all polygon/polyline point values?

Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

Hi,

In your xml is the first polygon fill missing a closing quote? <polygon fill="red" trans ...

Didn't do it myself but i think the original svg was done in Adobe Illustrator. I doubt they'll change.

Am I right in thinking that the only way to maintain the 'fill' attribute when changing that node and then saving to SVG file, is to save using the optimizedSVG type option.

Cos when I update a node (change the id attribute) inkscape merges the fill, stoke, etc into the style attribute. I just want to change the id attribute and save the file with only those changes (so i can diff later to double check changes).

Revision history for this message
sas (sas-sas) wrote :

100-100 isn't a valid coordinate pair in a polygon (or polyline) 'points' attribute, though it is in a path 'd' attribute. The difference can be seen in the BNF grammars: the 'points' attribute has

coordinate-pair:
    coordinate comma-wsp coordinate

but the 'd' attribute has

coordinate-pair:
    coordinate comma-wsp? coordinate

The question mark in the 'd' attribute case indicates that the comma-wsp (a non-empty sequence of commas and whitespace characters, containing at most one comma) is optional. But in the 'points' case it is required.

Ideally, scour should give an error message along the lines of "invalid 'points' attribute" or "invalid 'polygon' element", rather than just a traceback.

Revision history for this message
codedread (codedread) wrote :

@Matt - yeah I forgot a quote there after red, sorry :)

@sas - Note that Opera, WebKit and IE9 all support points="100-100" but Firefox does not.

Because Illustrator apparently outputs polygons in this syntax, I believe it's a good opportunity for scour to massage the syntax so that all browsers/editor can understand it. My plan at the moment is to parse the polygon/polyline points value and ensure it's a comma-separate list.

Revision history for this message
codedread (codedread) wrote :

And by "ensure it's a comma-separate list" I mean scour will actually rewrite the points attribute into a comma-separated list

Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

That's good for me. When fixed, is it possible for me to get it? Do you have an idea when it would be fixed?

Revision history for this message
codedread (codedread) wrote : Re: [Bug 541889] Re: SaveAs Optimized SVG error "AttributeError: 'SVGLength' object has no attribute 'units'"
Download full text (4.3 KiB)

Matt,

Sorry, but I won't be able to work on this until Thursday-ish or the
weekend. I will update the bug once I get something working in the
script.

Jeff

On Tue, Mar 23, 2010 at 9:37 AM, Matt Sarjent <email address hidden> wrote:
> That's good for me. When fixed, is it possible for me to get it? Do you
> have an idea when it would be fixed?
>
> --
> SaveAs Optimized SVG error "AttributeError: 'SVGLength' object has no attribute 'units'"
> https://bugs.launchpad.net/bugs/541889
> You received this bug notification because you are the registrant for
> Scour.
>
> Status in Inkscape: A Vector Drawing Tool: New
> Status in Scour - Cleaning SVG Files: New
>
> Bug description:
> Hi, love Inkscape, especially using python :-) although i'm post-processing/parsing svg with beautifulSoup.
>
> I have been trying to save a file with the fill attributes separate to the style attributes so i tried to save using the "Optimized SVG" file type option. Unfortunately i keep on getting the error
>
> Traceback (most recent call last):
>  File "C:\Program Files\Inkscape\share\extensions\scour.inkscape.py", line 6, in <module>
>    sys.stdout.write(scourString(input.read()).encode("UTF-8"))
>  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 2245, in scourString
>    cleanPolygon(polygon)
>  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 1803, in cleanPolygon
>    pts = parseListOfPoints(elem.getAttribute('points'))
>  File "C:\Program Files\Inkscape\share\extensions\scour.py", line 1790, in parseListOfPoints
>    if x.units != Unit.NONE or y.units != Unit.NONE: return []
> AttributeError: 'SVGLength' object has no attribute 'units'
>
> so i traced it through to the scour.py where the SVGLength doesn't set the self.units in all cases after a ValueError in thrown.
>
> so i added in the extra case giving the new code
>
> class SVGLength(object):
>        def __init__(self, str):
>                try: # simple unitless and no scientific notation
>                        self.value = float(str)
>                        if int(self.value) == self.value:
>                                self.value = int(self.value)
>                        self.units = Unit.NONE
>                except ValueError:
>                        # we know that the length string has an exponent, a unit, both or is invalid
>
>                        # parse out number, exponent and unit
>                        self.value = 0
>                        unitBegin = 0
>                        scinum = scinumber.match(str)
>                        if scinum != None:
>                                # this will always match, no need to check it
>                                numMatch = number.match(str)
>                                expMatch = sciExponent.search(str, numMatch.start(0))
>                                self.value = (float(numMatch.group(0)) *
>                                        10 ** float(expMatch.group(1)))
>                                unitBegin = expMatch.end(1)
>                        else:
>                                # unit or invalid
>                                numMatch = number.match(str)
>                       ...

Read more...

Revision history for this message
codedread (codedread) wrote :

Matt,

Revision 165 should have fixes for this bug now. Can you get the latest from Bazaar and confirm?

I won't close the bug or officially release version 0.25 of the script until I get some confirmation.

Thanks,
Jeff

Changed in scour:
status: New → Fix Committed
Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

I'll try and test the changes but the comment looks wrong.
http://bazaar.launchpad.net/~codedread/scour/trunk/revision/165

Comment says "Fix Bug 541889: Properly parse polygon/polyline points missing whitespace/comma for negative attributes" so the right bug number but the wrong comment.

Revision history for this message
codedread (codedread) wrote :

Matt, the comment is correct - this was the bug. See Comment #5 - the root of the problem was two coordinate values where the second one is negative and sandwiched together:

points="100-100"

Now scour converts this to

points="100,-100"

so that we do not get the SVGLength error anymore.

Revision history for this message
Matt Sarjent (matt-sarjent) wrote :

Sorry for the wait, I've tested the fixed in revision 165 on a many different files including the original file. All tests passed.
Cheers

Revision history for this message
jazzynico (jazzynico) wrote :

About to commit Scour rev 171 in Inkscape before 0.48 code freeze.

Changed in inkscape:
assignee: nobody → JazzyNico (jazzynico)
importance: Undecided → Low
milestone: none → 0.48
status: New → In Progress
Revision history for this message
jazzynico (jazzynico) wrote :

Fix committed in Inkscape revision 9434.

Changed in inkscape:
status: In Progress → Fix Committed
codedread (codedread)
Changed in scour:
status: Fix Committed → Fix Released
jazzynico (jazzynico)
Changed in inkscape:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Bug attachments

Remote bug watches

Bug watches keep track of this bug in other bug trackers.