summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaalleen <36401965+kaalleen@users.noreply.github.com>2024-07-03 07:09:06 +0200
committerGitHub <noreply@github.com>2024-07-03 07:09:06 +0200
commit2b390b908e93a7f6f529b9db624dd0d2c3ca184a (patch)
tree569a352d3f5de13d6507ce89938d087a1f9d6ec0
parent6c166dca61e17efbb3173dcf5ef484e3aa739a50 (diff)
Raster output (#3036)
* stitch plan preview png: 300, 600 dpi * add png export dpi option
-rw-r--r--lib/extensions/png_realistic.py8
-rw-r--r--lib/extensions/png_simple.py21
-rw-r--r--lib/extensions/stitch_plan_preview.py33
-rw-r--r--lib/extensions/zip.py18
-rw-r--r--templates/png_realistic.xml14
-rw-r--r--templates/png_simple.xml3
-rw-r--r--templates/stitch_plan_preview.xml4
-rw-r--r--templates/zip.xml40
8 files changed, 92 insertions, 49 deletions
diff --git a/lib/extensions/png_realistic.py b/lib/extensions/png_realistic.py
index 24ebce55..e3216efd 100644
--- a/lib/extensions/png_realistic.py
+++ b/lib/extensions/png_realistic.py
@@ -13,6 +13,12 @@ from .png_simple import write_png_output
class PngRealistic(InkstitchExtension):
+ def __init__(self, *args, **kwargs):
+ InkstitchExtension.__init__(self)
+
+ self.arg_parser.add_argument('--notebook')
+ self.arg_parser.add_argument('--dpi', type=int, default=300, dest='dpi')
+
def effect(self):
if not self.get_elements():
return
@@ -26,7 +32,7 @@ class PngRealistic(InkstitchExtension):
layer = render_stitch_plan(self.svg, stitch_plan, True, visual_commands=False, render_jumps=False)
- write_png_output(self.svg, layer)
+ write_png_output(self.svg, layer, self.options.dpi)
# don't let inkex output the SVG!
sys.exit(0)
diff --git a/lib/extensions/png_simple.py b/lib/extensions/png_simple.py
index 7902b43b..dd7748d9 100644
--- a/lib/extensions/png_simple.py
+++ b/lib/extensions/png_simple.py
@@ -20,8 +20,9 @@ class PngSimple(InkstitchExtension):
def __init__(self, *args, **kwargs):
InkstitchExtension.__init__(self)
- self.arg_parser.add_argument('--notebook', type=str, default='')
- self.arg_parser.add_argument('--line_width', type=str, default='', dest='line_width')
+ self.arg_parser.add_argument('--notebook')
+ self.arg_parser.add_argument('--line_width', type=float, default=0.3, dest='line_width')
+ self.arg_parser.add_argument('--dpi', type=int, default=300, dest='dpi')
def effect(self):
if not self.get_elements():
@@ -38,13 +39,13 @@ class PngSimple(InkstitchExtension):
layer = render_stitch_plan(self.svg, stitch_plan, False, visual_commands=False,
render_jumps=False, line_width=line_width)
- write_png_output(self.svg, layer)
+ write_png_output(self.svg, layer, self.options.dpi)
# don't let inkex output the SVG!
sys.exit(0)
-def write_png_output(svg, layer):
+def write_png_output(svg, layer, dpi):
with TemporaryDirectory() as tempdir:
# Inkex's command functionality also writes files to temp directories like this.
temp_svg_path = f"{tempdir}/temp.svg"
@@ -52,7 +53,7 @@ def write_png_output(svg, layer):
with open(temp_svg_path, "wb") as f:
f.write(svg.tostring())
- generate_png(svg, layer, temp_svg_path, temp_png_path)
+ generate_png(svg, layer, temp_svg_path, temp_png_path, dpi)
# inkscape will read the file contents from stdout and copy
# to the destination file that the user chose
@@ -60,13 +61,13 @@ def write_png_output(svg, layer):
sys.stdout.buffer.write(output_file.read())
-def generate_png(svg, layer, input_path, output_path):
+def generate_png(svg, layer, input_path, output_path, dpi):
inkscape(input_path, actions="; ".join([
- f"export-id:{layer.get_id()}",
+ f"export-id: {layer.get_id()}",
"export-id-only",
"export-type:png",
- f"export-dpi:{96*8}",
- f"export-filename:{output_path}",
- f"export-background:{get_pagecolor(svg.namedview)}",
+ f"export-dpi: {dpi}",
+ f"export-filename: {output_path}",
+ f"export-background: {get_pagecolor(svg.namedview)}",
"export-do" # Inkscape docs say this should be implicit at the end, but it doesn't seem to be.
]))
diff --git a/lib/extensions/stitch_plan_preview.py b/lib/extensions/stitch_plan_preview.py
index 464e4200..8f76a447 100644
--- a/lib/extensions/stitch_plan_preview.py
+++ b/lib/extensions/stitch_plan_preview.py
@@ -38,7 +38,7 @@ class StitchPlanPreview(InkstitchExtension):
self.arg_parser.add_argument("-o", "--overwrite", type=Boolean, default=True, dest="overwrite")
def effect(self):
- realistic, raster_mult = self.parse_mode()
+ realistic, dpi = self.parse_mode()
# delete old stitch plan
self.remove_old()
@@ -58,7 +58,7 @@ class StitchPlanPreview(InkstitchExtension):
layer = render_stitch_plan(svg, stitch_plan, realistic, visual_commands, render_jumps=self.options.render_jumps)
if self.options.ignore_layer and not self.options.mode[-1].isdigit():
add_layer_commands(layer, ["ignore_layer"])
- layer = self.rasterize(svg, layer, raster_mult)
+ layer = self.rasterize(svg, layer, dpi)
# update layer visibility (unchanged, hidden, lower opacity)
groups = self.document.getroot().findall(SVG_GROUP_TAG)
@@ -72,27 +72,27 @@ class StitchPlanPreview(InkstitchExtension):
def parse_mode(self) -> Tuple[bool, Optional[int]]:
"""
Parse the "mode" option and return a tuple of a bool indicating if realistic rendering should be used,
- and an optional int indicating the resolution multiplier to use for rasterization, or None if rasterization should not be used.
+ and an optional int indicating the dpi value to use for rasterization, or None if rasterization should not be used.
"""
realistic = False
- raster_mult: Optional[int] = None
+ dpi: Optional[int] = None
render_mode = self.options.mode
if render_mode == "simple":
pass
elif render_mode.startswith("realistic-"):
realistic = True
- raster_option = render_mode.split('-')[1]
- if raster_option != "vector":
+ dpi_option = render_mode.split('-')[1]
+ if dpi_option != "vector":
try:
- raster_mult = int(raster_option)
+ dpi = int(dpi_option)
except ValueError:
- errormsg(f"Invalid raster mode {raster_option}")
+ errormsg(f"Invalid raster mode {dpi_option}")
sys.exit(1)
else:
errormsg(f"Invalid render mode {render_mode}")
sys.exit(1)
- return (realistic, raster_mult)
+ return (realistic, dpi)
def remove_old(self):
svg = self.document.getroot()
@@ -104,8 +104,8 @@ class StitchPlanPreview(InkstitchExtension):
if layer is not None:
layer.set('id', svg.get_unique_id('inkstitch_stitch_plan_'))
- def rasterize(self, svg: BaseElement, layer: BaseElement, raster_mult: Optional[int]) -> BaseElement:
- if raster_mult is None:
+ def rasterize(self, svg: BaseElement, layer: BaseElement, dpi: Optional[int]) -> BaseElement:
+ if dpi is None:
# Don't rasterize if there's no reason to.
return layer
else:
@@ -121,16 +121,17 @@ class StitchPlanPreview(InkstitchExtension):
# Instead, especially because we need to invoke Inkscape anyway to perform the rasterization, we get
# the bounding box with query commands before we perform the export. This is quite cheap.
out = inkscape(temp_svg_path, actions="; ".join([
- f"select-by-id:{layer.get_id()}",
+ f"select-by-id: {layer.get_id()}",
"query-x",
"query-y",
"query-width",
"query-height",
- f"export-id:{layer.get_id()}",
+ f"export-id: {layer.get_id()}",
"export-id-only",
- "export-type:png",
- f"export-dpi:{96*raster_mult}",
- f"export-filename:{temp_png_path}",
+ "export-type: png",
+ f"export-dpi: {dpi}",
+ "export-png-color-mode: RGBA_16",
+ f"export-filename: {temp_png_path}",
"export-do" # Inkscape docs say this should be implicit at the end, but it doesn't seem to be.
]))
diff --git a/lib/extensions/zip.py b/lib/extensions/zip.py
index 1c33c080..c2385886 100644
--- a/lib/extensions/zip.py
+++ b/lib/extensions/zip.py
@@ -30,7 +30,7 @@ class Zip(InkstitchExtension):
def __init__(self, *args, **kwargs):
InkstitchExtension.__init__(self)
- self.arg_parser.add_argument('--notebook', type=str, default='')
+ self.arg_parser.add_argument('--notebook')
self.arg_parser.add_argument('--custom-file-name', type=str, default='', dest='custom_file_name')
# it's kind of obnoxious that I have to do this...
@@ -44,10 +44,12 @@ class Zip(InkstitchExtension):
self.formats.append('svg')
self.arg_parser.add_argument('--format-threadlist', type=Boolean, default=False, dest='threadlist')
self.formats.append('threadlist')
- self.arg_parser.add_argument('--format-png_realistic', type=Boolean, default=False, dest='png_realistic')
+ self.arg_parser.add_argument('--format-png-realistic', type=Boolean, default=False, dest='png_realistic')
+ self.arg_parser.add_argument('--dpi-realistic', type=int, default='', dest='dpi_realistic')
self.formats.append('png_realistic')
- self.arg_parser.add_argument('--format-png_simple', type=Boolean, default=False, dest='png_simple')
- self.arg_parser.add_argument('--png_simple_line_width', type=float, default=0.3, dest='line_width')
+ self.arg_parser.add_argument('--format-png-simple', type=Boolean, default=False, dest='png_simple')
+ self.arg_parser.add_argument('--png-simple-line-width', type=float, default=0.3, dest='line_width')
+ self.arg_parser.add_argument('--dpi-simple', type=int, default='', dest='dpi_simple')
self.formats.append('png_simple')
self.arg_parser.add_argument('--x-repeats', type=int, default=1, dest='x_repeats', )
@@ -131,21 +133,21 @@ class Zip(InkstitchExtension):
elif format == 'png_realistic':
output_file = os.path.join(path, f"{base_file_name}_realistic.png")
layer = render_stitch_plan(self.svg, stitch_plan, True, visual_commands=False, render_jumps=False)
- self.generate_png_output(output_file, layer)
+ self.generate_png_output(output_file, layer, self.options.dpi_realistic)
elif format == 'png_simple':
output_file = os.path.join(path, f"{base_file_name}_simple.png")
line_width = convert_unit(f"{self.options.line_width}mm", self.svg.document_unit)
layer = render_stitch_plan(self.svg, stitch_plan, False, visual_commands=False,
render_jumps=False, line_width=line_width)
- self.generate_png_output(output_file, layer)
+ self.generate_png_output(output_file, layer, self.options.dpi_simple)
else:
write_embroidery_file(output_file, stitch_plan, self.document.getroot())
files.append(output_file)
return files
- def generate_png_output(self, output_file, layer):
+ def generate_png_output(self, output_file, layer, dpi):
with tempfile.TemporaryDirectory() as tempdir:
temp_svg_path = f"{tempdir}/temp.svg"
with open(temp_svg_path, "wb") as f:
f.write(self.svg.tostring())
- generate_png(self.svg, layer, temp_svg_path, output_file)
+ generate_png(self.svg, layer, temp_svg_path, output_file, dpi)
diff --git a/templates/png_realistic.xml b/templates/png_realistic.xml
index 93f0ee2b..7aae6696 100644
--- a/templates/png_realistic.xml
+++ b/templates/png_realistic.xml
@@ -10,6 +10,20 @@
<dataloss>true</dataloss>
</output>
<param name="extension" type="string" gui-hidden="true">png_realistic</param>
+ <param name="notebook" type="notebook">
+ <page name="settings" gui-text="Settings">
+ <param name="dpi" type="int" min="100" max="2000" gui-text="DPI">300</param>
+ </page>
+ <page name="info" gui-text="Help">
+ <label appearance="header">PNG file export</label>
+ <label>Export embroidery design to PNG</label>
+ <spacer />
+ <separator />
+ <spacer />
+ <label>Read more on our website</label>
+ <label appearance="url">https://inkstitch.org/docs/import-export/</label>
+ </page>
+ </param>
<script>
{{ command_tag | safe }}
</script>
diff --git a/templates/png_simple.xml b/templates/png_simple.xml
index be12e784..e42a8819 100644
--- a/templates/png_simple.xml
+++ b/templates/png_simple.xml
@@ -13,6 +13,7 @@
<param name="notebook" type="notebook">
<page name="settings" gui-text="Settings">
<param name="line_width" type="float" precision="2" min="0.01" max="5" gui-text="Line width (mm)">0.3</param>
+ <param name="dpi" type="int" min="100" max="2000" gui-text="DPI">300</param>
</page>
<page name="info" gui-text="Help">
<label appearance="header">PNG file export</label>
@@ -20,7 +21,7 @@
<spacer />
<separator />
<spacer />
- <label>Read more on our webiste</label>
+ <label>Read more on our website</label>
<label appearance="url">https://inkstitch.org/docs/import-export/</label>
</page>
</param>
diff --git a/templates/stitch_plan_preview.xml b/templates/stitch_plan_preview.xml
index f7180915..a3385ed3 100644
--- a/templates/stitch_plan_preview.xml
+++ b/templates/stitch_plan_preview.xml
@@ -14,8 +14,8 @@
<param name="render-mode" type="optiongroup" appearance="combo" gui-text="Render Mode"
gui-description="Realistic modes will render to a raster image for performance reasons. Realistic Vector may cause Inkscape to slow down for complex designs.">
<option value="simple">Simple</option>
- <option value="realistic-8">Realistic</option>
- <option value="realistic-16">Realistic High Quality</option>
+ <option value="realistic-300">Realistic</option>
+ <option value="realistic-600">Realistic High Quality</option>
<option value="realistic-vector">Realistic Vector (slow)</option>
</param>
<spacer />
diff --git a/templates/zip.xml b/templates/zip.xml
index c34027eb..277bbae9 100644
--- a/templates/zip.xml
+++ b/templates/zip.xml
@@ -9,23 +9,41 @@
<filetypetooltip>Create a ZIP with multiple embroidery file formats using Ink/Stitch</filetypetooltip>
<dataloss>true</dataloss>
</output>
+ <param name="extension" type="string" gui-hidden="true">zip</param>
<param name="custom-file-name" type="string" gui-text="Custom file name"
gui-description="Defines the file names inside the zip archive. Leave empty for default file name."></param>
<spacer />
<param name="notebook" type="notebook">
<page name="file-formats" gui-text="File Formats">
<label>Output formats:</label>
- {%- for format, description, mimetype, category in formats %}
- {%- if category != "vector" and category != "debug" %}
- <param name="format-{{ format }}" type="boolean" gui-text=".{{ format | upper }}: {{ description }}">false</param>
- {%- endif %}
- {%- endfor %}
- <param name="format-threadlist" type="boolean" gui-text=".TXT: Threadlist [COLOR]">false</param>
- <param name="format-png_realistic" type="boolean" gui-text=".PNG: Portable Network Graphics (Realistic) [IMAGE]">false</param>
- <param name="format-png_simple" type="boolean" gui-text=".PNG: Portable Network Graphics (Simple) [IMAGE]">false</param>
- <param name="png_simple_line_width" type="float" precision="2" min="0.01" max="5" gui-text="Line width (mm)" indent="4">0.3</param>
- <param name="format-svg" type="boolean" gui-text=".SVG: Scalable Vector Graphic">false</param>
- <param name="extension" type="string" gui-hidden="true">zip</param>
+ <hbox>
+ <vbox>
+ {%- for format, description, mimetype, category in formats %}
+ {%- if category != "vector" and category != "debug" %}
+ <param name="format-{{ format }}" type="boolean" gui-text=".{{ format | upper }}: {{ description }}">false</param>
+ {%- endif %}
+ {%- if loop.index == 13 %}
+ </vbox>
+ <spacer />
+ <separator />
+ <spacer />
+ <vbox>
+ {%- endif %}
+ {%- endfor %}
+ <param name="format-threadlist" type="boolean" gui-text=".TXT: Threadlist [COLOR]">false</param>
+ </vbox>
+ <spacer />
+ <separator />
+ <spacer />
+ <vbox>
+ <param name="format-svg" type="boolean" gui-text=".SVG: Scalable Vector Graphic">false</param>
+ <param name="format-png-realistic" type="boolean" gui-text=".PNG: Portable Network Graphics (Realistic) [IMAGE]">false</param>
+ <param name="dpi-realistic" type="int" min="100" max="2000" gui-text="DPI" indent="4">300</param>
+ <param name="format-png-simple" type="boolean" gui-text=".PNG: Portable Network Graphics (Simple) [IMAGE]">false</param>
+ <param name="png-simple-line-width" type="float" precision="2" min="0.01" max="5" gui-text="Line width (mm)" indent="4">0.3</param>
+ <param name="dpi-simple" type="int" min="100" max="2000" gui-text="DPI" indent="4">300</param>
+ </vbox>
+ </hbox>
</page>
<page name="panelization" gui-text="Panelization Options">
<label>For single design set horizontal and vertical repeats to 1</label>