-
Notifications
You must be signed in to change notification settings - Fork 3
Probems in the Jogsaw class with the temp SVG file #5
Copy link
Copy link
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Below I have a recommend update.
Was getting this error report:
>>> from pyjigsaw import jigsawfactory
>>> imiage_path = "rainforest_1.jpg"; output_folder = 'pieces'; jigsaw_pattern=(4,3)
>>> import os
>>> os.makedirs(output_folder, exist_ok=True)
>>> mycut = jigsawfactory.Cut(jigsaw_pattern[0], jigsaw_pattern[1], image=image_path, use_image=True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'image_path' is not defined. Did you mean: 'imiage_path'?
>>> image_path = "rainforest_1.jpg"; output_folder = 'pieces'; jigsaw_pattern=(4,3)
>>> mycut = jigsawfactory.Cut(jigsaw_pattern[0], jigsaw_pattern[1], image=image_path, use_image=True)
Puzzle template update complete
>>> myjig = jigsawfactory.Jigsaw(mycut, image_path)
>>> myjig.generate_svg_jigsaw(output_folder)
/tmp/tmpdi8ky8hj.SVG:1: parser error : Document is empty
/tmp/tmpdi8ky8hj.SVG:1: parser error : Document is empty
ink_file_open: '/tmp/tmpdi8ky8hj.SVG' cannot be opened!
InkscapeApplication::document_open: Failed to open: /tmp/tmpdi8ky8hj.SVG
ConcreteInkscapeApplication::on_open: failed to create document!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".../.local/lib/python3.10/site-packages/pyjigsaw/jigsawfactory.py", line 254, in generate_svg_jigsaw
paths, _ = svg2paths(fp.name)
File ".../.local/lib/python3.10/site-packages/svgpathtools/svg_to_paths.py", line 183, in svg2paths
doc = parse(svg_file_location)
File "/usr/lib/python3.10/xml/dom/minidom.py", line 1990, in parse
return expatbuilder.parse(file)
File "/usr/lib/python3.10/xml/dom/expatbuilder.py", line 911, in parse
result = builder.parseFile(fp)
File "/usr/lib/python3.10/xml/dom/expatbuilder.py", line 211, in parseFile
parser.Parse(b"", True)
xml.parsers.expat.ExpatError: no element found: line 1, column
Here is a possible fix for your Jigsaw class:
class Jigsaw():
def __init__(self, cut: Cut, image=None):
self.cut = cut
self.image = image
def generate_svg_jigsaw(self, outdirectory):
metadata = self.cut.metadata
fp = tempfile.NamedTemporaryFile(suffix=".SVG", delete=False) # Set delete=False to keep the file
try:
# Write the SVG template to the file
fp.write(self.cut.svg_template.encode('utf-8'))
fp.flush()
fp.close() # Close the file but don't delete it yet
# Call Inkscape to query all elements
try:
bboxes = subprocess.check_output(
["inkscape", "--query-all", "{}".format(fp.name)],
stderr=subprocess.PIPE).decode('utf-8')
bboxes = bboxes.split("\n")[1:-1]
except subprocess.CalledProcessError as e:
print(f"Inkscape error: {e}, stderr: {e.stderr.decode('utf-8')}")
raise Exception(f"Inkscape failed to query SVG elements: {e}")
ext, encoded = image_encode(self.image)
# Parse SVG paths
try:
paths, _ = svg2paths(fp.name)
except Exception as e:
print(f"Failed to parse SVG paths: {e}")
# Save the problematic file for debugging
shutil.copy(fp.name, 'debug_failed_svg.svg')
raise
# Apply bounding box for each path and generate svg from template
for p, path in enumerate(paths):
xmin, ymin, width, height = bboxes[p].split(",")[1:]
# Rest of your existing code for processing paths...
svg = """\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="{} {} {w} {h}" width="{w}" height="{h}">
<defs>
<path id="cropPath" d="{d}" />
<clipPath id="crop">
<use href="#cropPath" />
</clipPath>
</defs>
<image href="data:image/{ext};base64,{encoded}" clip-path="url(#crop)"/>
</svg>
""".format(xmin, ymin, w=width, h=height, d=path.d(), ext=ext, encoded=encoded)
with open(os.path.join(outdirectory, '{}.svg'.format(p)), 'w') as file:
file.write(svg)
self.cut.metadata = metadata
return "Svg puzzle set generated: {} ({} Pieces) Directory: {}".format(self.image, len(paths), outdirectory)
finally:
# Clean up the temporary file
if os.path.exists(fp.name):
os.unlink(fp.name)
These changes may help:
- Use delete=False with NamedTemporaryFile to keep the file after closing
- Close the file after writing, but before using Inkscape
- Use a finally block to clean up the file at the end with os.unlink
- Remove the duplicate fp.close() call
- Handle potential errors when calling Inkscape and parsing paths
This restructuring keeps the file available throughout the entire process, and ensures it's properly cleaned up at the end, even if an error occurs.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working