meerk40t / svgelements

SVG Parsing for Elements, Paths, and other SVG Objects.
MIT License
132 stars 29 forks source link

AttributeError: 'NoneType' object has no attribute '__imatmul__' #107

Closed 1Ghasthunter1 closed 3 years ago

1Ghasthunter1 commented 3 years ago

First off, thanks for all of the documentation; it's apparent to me you guys have put hours in to write that. So, before reading, if I made a usage error, I apologize beforehand, but I've been stuck trying to translate the entire contents of an SVG file.

Before I go into the issue, keep in mind my main goal is to apply a series of transformations, like translations or rotations, to the entire SVG file. I start by importing the package as from svgelements import *

Then, I import my svg file with svg = SVG.parse("path.svg")

Upon typing svg in the python command line, I get the full object which confirms (at least I think) my file was imported successfully:

[<svgelements.svgelements.SVGElement object at 0x000001CEB74FC850>, <svgelements.svgelements.SVGElement object at 0x000001CEB74FC880>, <svgelements.svgelements.SVGElement object at 0x000001CEB7571040>, <svgelements.svgelements.SVGElement object at 0x000001CEB75710A0>, <svgelements.svgelements.SVGElement object at 0x000001CEB7571100>, <svgelements.svgelements.SVGElement object at 0x000001CEB7571160>, <svgelements.svgelements.SVGElement object at 0x000001CEB75711C0>, [[[Path(Move(end=Point(188.96403423932,95.769176033337)), Line(start=Point(188.96403423932,95.769176033337), end=Point(6.206547011063,95.580306893558)), Line(start=Point(6.206547011063,95.580306893558), end=Point(6.206547011063,95.580306893558)), Line(start=Point(6.206547011063,95.580306893558), end=Point(5.310881181429,95.510402105241)), Line(start=Point(5.310881181429,95.510402105241), end=Point(4.438482391093,95.296616407249)), Line(start=Point(4.438482391093,95.296616407249), end=Point(3.600945765251,94.951245225368)), Line(start=Point(3.600945765251,94.951245225368), end=Point(2.825492971994,94.474304844927)), Line(start=Point(2.825492971994,94.474304844927), end=Point(2.127558581944,93.882239380082)), Line(start=Point(2.127558581944,93.882239380082), end=Point(1.514936669322,93.187384969946)), Line(start=Point(1.514936669322,93.187384969946), end=Point(1.010855878973,92.402077753635)), Line(start=Point(1.010855878973,92.402077753635), end=Point(0.623148679571,91.542761845302)), Line(start=Point(0.623148679571,91.542761845302), end=Point(0.359378778611,90.634105451843)), Line(start=Point(0.359378778611,90.634105451843), end=Point(0.223846354974,89.696672876449)), Line(start=Point(0.223846354974,89.696672876449), end=Point(0.223846354974,88.746900090607)), Line(start=Point(0.223846354974,88.746900090607), end=Point(0.359378778611,87.805355468841)), Line(start=Point(0.359378778611,87.805355468841), end=Point(0.623148679571,86.896699075382)), Line(start=Point(0.623148679571,86.896699075382), end=Point(1.010855878973,86.04149521342)), Line(start=Point(1.010855878973,86.04149521342), end=Point(45.996217373596,3.415615100191)), stroke='#ff0000', fill='None', stroke_width='0.46103578438652576', id='path907'), Path(Move(end=Point(45.996217373596,3.415615100191)), Line(start=Point(45.996217373596,3.415615100191), end=Point(46.500298163945,2.63030788388)), Line(start=Point(46.500298163945,2.63030788388), end=Point(47.112920076567,1.935453473744)), Line(start=Point(47.112920076567,1.935453473744), end=Point(47.810854466617,1.343388008899)), Line(start=Point(47.810854466617,1.343388008899), end=Point(48.590185099758,0.866447628459)), Line(start=Point(48.590185099758,0.866447628459), end=Point(49.423843885716,0.521076446577)), Line(start=Point(49.423843885716,0.521076446577), end=Point(50.296242676052,0.307290748585)), Line(start=Point(50.296242676052,0.307290748585), end=Point(51.191908505686,0.237385960268)), Line(start=Point(51.191908505686,0.237385960268), end=Point(188.96940946292,0.346904819076)), stroke='#ff0000', fill='None', stroke_width='0.46103578438652576', id='polyline30')]]]]

It only made sense for me to do something like Group(svg[-1]), which worked, and I would get:

[[[Path(Move(end=Point(188.96403423932,95.769176033337)), Line(start=Point(188.96403423932,95.769176033337), end=Point(6.206547011063,95.580306893558)), Line(start=Point(6.206547011063,95.580306893558), end=Point(6.206547011063,95.580306893558)), Line(start=Point(6.206547011063,95.580306893558), end=Point(5.310881181429,95.510402105241)), Line(start=Point(5.310881181429,95.510402105241), end=Point(4.438482391093,95.296616407249)), Line(start=Point(4.438482391093,95.296616407249), end=Point(3.600945765251,94.951245225368)), Line(start=Point(3.600945765251,94.951245225368), end=Point(2.825492971994,94.474304844927)), Line(start=Point(2.825492971994,94.474304844927), end=Point(2.127558581944,93.882239380082)), Line(start=Point(2.127558581944,93.882239380082), end=Point(1.514936669322,93.187384969946)), Line(start=Point(1.514936669322,93.187384969946), end=Point(1.010855878973,92.402077753635)), Line(start=Point(1.010855878973,92.402077753635), end=Point(0.623148679571,91.542761845302)), Line(start=Point(0.623148679571,91.542761845302), end=Point(0.359378778611,90.634105451843)), Line(start=Point(0.359378778611,90.634105451843), end=Point(0.223846354974,89.696672876449)), Line(start=Point(0.223846354974,89.696672876449), end=Point(0.223846354974,88.746900090607)), Line(start=Point(0.223846354974,88.746900090607), end=Point(0.359378778611,87.805355468841)), Line(start=Point(0.359378778611,87.805355468841), end=Point(0.623148679571,86.896699075382)), Line(start=Point(0.623148679571,86.896699075382), end=Point(1.010855878973,86.04149521342)), Line(start=Point(1.010855878973,86.04149521342), end=Point(45.996217373596,3.415615100191)), stroke='#ff0000', fill='None', stroke_width='0.46103578438652576', id='path907'), Path(Move(end=Point(45.996217373596,3.415615100191)), Line(start=Point(45.996217373596,3.415615100191), end=Point(46.500298163945,2.63030788388)), Line(start=Point(46.500298163945,2.63030788388), end=Point(47.112920076567,1.935453473744)), Line(start=Point(47.112920076567,1.935453473744), end=Point(47.810854466617,1.343388008899)), Line(start=Point(47.810854466617,1.343388008899), end=Point(48.590185099758,0.866447628459)), Line(start=Point(48.590185099758,0.866447628459), end=Point(49.423843885716,0.521076446577)), Line(start=Point(49.423843885716,0.521076446577), end=Point(50.296242676052,0.307290748585)), Line(start=Point(50.296242676052,0.307290748585), end=Point(51.191908505686,0.237385960268)), Line(start=Point(51.191908505686,0.237385960268), end=Point(188.96940946292,0.346904819076)), stroke='#ff0000', fill='None', stroke_width='0.46103578438652576', id='polyline30')]]]

Then, I would attempt to translate this svg: Group(svg[-1]) * Matrix.translate(100, 100)

And the exception comes back as AttributeError: 'NoneType' object has no attribute '__imatmul__'

Any help would be greatly appreciated, and thanks for all of the work you guys have done!

tatarize commented 3 years ago

Yeah, that's a weird bug. You can totally just multiply it with imul but it crashes in the other form.

svg[-1] *= "translate(100,100)"

I think I always short handed added those values that I never bothered to check the create a new object form of the multiplication there.

tatarize commented 3 years ago

At issue is that the copy() for Group objects of which SVG is a type thereof, does not properly initialize itself fully. It exits that code with a return without calling the SVGElement init which calls the by property and by value initializations for the subclasses. Of specific importance it sets the group's transform value which is really helpful when you want to multiply it out. Without it set it tries to multiply by None, which is notably fails in that error.

It's a genuine bug, I'll have it fixed shortly. Just need to make sure I'm doing everything right and crossing all ts and dotting the js, so as to not introduce additional bugs.

1Ghasthunter1 commented 3 years ago

Ah, that makes a lot of sense. Take your time; no rush. It's not worth messing anything else up.

tatarize commented 3 years ago

It's just checking through some code and making sure it's not going anywhere weird, and writing a test case and making sure it passes all the current test cases. It makes it fairly safe. 1.4.12 is done. Publishing soon.

tatarize commented 3 years ago

Fixed and published.

The code is in maintenance mode so bug fixes are a priority and usually rather small and dealt with rapidly.

Likely any big future changes would be in #87 rewrite, since that would be able to capture a lot of things this library misses. So, it's kinda a priority to fix things well and fast. Just took some double checking and authoring some test code.