645 lines
21 KiB
Python
Executable file
645 lines
21 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# coding=utf-8
|
|
#
|
|
# Authors:
|
|
# Nicolas Dufour - Association Inkscape-fr
|
|
# Aurelio A. Heckert <aurium(a)gmail.com>
|
|
#
|
|
# Copyright (C) 2008 Authors
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
#
|
|
"""
|
|
This extension allows you to draw crop, registration and other
|
|
printing marks in Inkscape.
|
|
"""
|
|
|
|
import math
|
|
import inkex
|
|
from inkex import Circle, Rectangle, TextElement
|
|
|
|
|
|
class PrintingMarks(inkex.EffectExtension):
|
|
# Default parameters
|
|
stroke_width = 0.25
|
|
|
|
def add_arguments(self, pars):
|
|
pars.add_argument("--where", help="Apply crop marks to...", default="canvas")
|
|
pars.add_argument(
|
|
"--crop_marks", type=inkex.Boolean, default=True, help="Draw crop Marks"
|
|
)
|
|
pars.add_argument("--bleed_marks", type=inkex.Boolean, help="Draw Bleed Marks")
|
|
pars.add_argument(
|
|
"--registration_marks",
|
|
type=inkex.Boolean,
|
|
dest="reg_marks",
|
|
default=True,
|
|
help="Draw Registration Marks?",
|
|
)
|
|
pars.add_argument("--star_target", type=inkex.Boolean, help="Draw Star Target?")
|
|
pars.add_argument(
|
|
"--colour_bars", type=inkex.Boolean, help="Draw Colour Bars?", default=True
|
|
)
|
|
pars.add_argument(
|
|
"--page_info", type=inkex.Boolean, help="Draw Page Information?"
|
|
)
|
|
pars.add_argument("--unit", default="px", help="Draw measurement")
|
|
pars.add_argument("--crop_offset", type=float, default=5.0, help="Offset")
|
|
pars.add_argument("--bleed_top", type=float, default=5.0, help="Bleed Top Size")
|
|
pars.add_argument(
|
|
"--bleed_bottom", type=float, default=5.0, help="Bleed Bottom Size"
|
|
)
|
|
pars.add_argument(
|
|
"--bleed_left", type=float, default=5.0, help="Bleed Left Size"
|
|
)
|
|
pars.add_argument(
|
|
"--bleed_right", type=float, default=5.0, help="Bleed Right Size"
|
|
)
|
|
pars.add_argument("--tab", help="The selected UI-tab when OK was pressed")
|
|
|
|
def draw_crop_line(self, x1, y1, x2, y2, name, parent):
|
|
style = {
|
|
"stroke": "#000000",
|
|
"stroke-width": str(self.stroke_width),
|
|
"fill": "none",
|
|
}
|
|
line_attribs = {
|
|
"style": str(inkex.Style(style)),
|
|
"id": name,
|
|
"d": "M " + str(x1) + "," + str(y1) + " L " + str(x2) + "," + str(y2),
|
|
}
|
|
parent.add(inkex.PathElement(**line_attribs))
|
|
|
|
def draw_bleed_line(self, x1, y1, x2, y2, name, parent):
|
|
style = {
|
|
"stroke": "#000000",
|
|
"stroke-width": str(self.stroke_width),
|
|
"fill": "none",
|
|
"stroke-miterlimit": "4",
|
|
"stroke-dasharray": "4, 2, 1, 2",
|
|
"stroke-dashoffset": "0",
|
|
}
|
|
line_attribs = {
|
|
"style": str(inkex.Style(style)),
|
|
"id": name,
|
|
"d": "M " + str(x1) + "," + str(y1) + " L " + str(x2) + "," + str(y2),
|
|
}
|
|
parent.add(inkex.PathElement(**line_attribs))
|
|
|
|
def draw_reg_circles(self, cx, cy, r, name, colours, parent):
|
|
for i in range(len(colours)):
|
|
style = {
|
|
"stroke": colours[i],
|
|
"stroke-width": str(r / len(colours)),
|
|
"fill": "none",
|
|
}
|
|
circle_attribs = {
|
|
"style": str(inkex.Style(style)),
|
|
"inkscape:label": name,
|
|
"cx": str(cx),
|
|
"cy": str(cy),
|
|
"r": str((r / len(colours)) * (i + 0.5)),
|
|
}
|
|
parent.add(Circle(**circle_attribs))
|
|
|
|
def draw_reg_marks(self, cx, cy, rotate, name, parent):
|
|
colours = ["#000000", "#00ffff", "#ff00ff", "#ffff00", "#000000"]
|
|
g = parent.add(inkex.Group(id=name))
|
|
for i in range(len(colours)):
|
|
style = {"fill": colours[i], "fill-opacity": "1", "stroke": "none"}
|
|
r = self.mark_size / 2
|
|
step = r
|
|
stroke = r / len(colours)
|
|
regoffset = stroke * i
|
|
regmark_attribs = {
|
|
"style": str(inkex.Style(style)),
|
|
"d": "m"
|
|
+ " "
|
|
+ str(-regoffset)
|
|
+ ","
|
|
+ str(r)
|
|
+ " "
|
|
+ str(-stroke)
|
|
+ ",0"
|
|
+ " "
|
|
+ str(step)
|
|
+ ","
|
|
+ str(-r)
|
|
+ " "
|
|
+ str(-step)
|
|
+ ","
|
|
+ str(-r)
|
|
+ " "
|
|
+ str(stroke)
|
|
+ ",0"
|
|
+ " "
|
|
+ str(step)
|
|
+ ","
|
|
+ str(r)
|
|
+ " "
|
|
+ str(-step)
|
|
+ ","
|
|
+ str(r)
|
|
+ " z",
|
|
"transform": "translate("
|
|
+ str(cx)
|
|
+ ","
|
|
+ str(cy)
|
|
+ ") rotate("
|
|
+ str(rotate)
|
|
+ ")",
|
|
}
|
|
g.add(inkex.PathElement(**regmark_attribs))
|
|
|
|
def draw_star_target(self, cx, cy, name, parent):
|
|
r = self.mark_size / 2
|
|
style = {
|
|
"fill": "#000 device-cmyk(1,1,1,1)",
|
|
"fill-opacity": "1",
|
|
"stroke": "none",
|
|
}
|
|
d = " M 0,0"
|
|
i = 0
|
|
while i < (2 * math.pi):
|
|
i += math.pi / 16
|
|
d += (
|
|
" L 0,0 "
|
|
+ " L "
|
|
+ str(math.sin(i) * r)
|
|
+ ","
|
|
+ str(math.cos(i) * r)
|
|
+ " L "
|
|
+ str(math.sin(i + 0.09) * r)
|
|
+ ","
|
|
+ str(math.cos(i + 0.09) * r)
|
|
)
|
|
elem = parent.add(inkex.PathElement())
|
|
elem.label = name
|
|
elem.transform.add_translate(cx, cy)
|
|
elem.path = d
|
|
elem.style = inkex.Style(style)
|
|
|
|
def draw_coluor_bars(self, cx, cy, rotate, name, parent, bbox):
|
|
group = parent.add(inkex.Group(id=name))
|
|
group.transform = inkex.Transform(translate=(cx, cy)) @ inkex.Transform(
|
|
rotate=rotate
|
|
)
|
|
loc = 0
|
|
if bbox:
|
|
loc = min(self.mark_size / 3, max(bbox.width, bbox.height) / 45)
|
|
for bar in [
|
|
{"c": "*", "stroke": "#000", "x": 0, "y": -(loc + 1)},
|
|
{"c": "r", "stroke": "#0FF", "x": 0, "y": 0},
|
|
{"c": "g", "stroke": "#F0F", "x": (loc * 11) + 1, "y": -(loc + 1)},
|
|
{"c": "b", "stroke": "#FF0", "x": (loc * 11) + 1, "y": 0},
|
|
]:
|
|
i = 0
|
|
while i <= 1:
|
|
color = inkex.Color("white")
|
|
if bar["c"] == "r" or bar["c"] == "*":
|
|
color.red = 255 * i
|
|
if bar["c"] == "g" or bar["c"] == "*":
|
|
color.green = 255 * i
|
|
if bar["c"] == "b" or bar["c"] == "*":
|
|
color.blue = 255 * i
|
|
r_att = {
|
|
"fill": str(color),
|
|
"stroke": bar["stroke"],
|
|
"stroke-width": loc / 8,
|
|
"x": str((loc * i * 10) + bar["x"]),
|
|
"y": str(bar["y"]),
|
|
"width": loc,
|
|
"height": loc,
|
|
}
|
|
rect = Rectangle()
|
|
for att, value in r_att.items():
|
|
rect.set(att, value)
|
|
group.add(rect)
|
|
i += 0.1
|
|
|
|
def draw_effect(self, bbox, name=""):
|
|
# Get SVG document dimensions
|
|
# self.width must be replaced by bbox.right. same to others.
|
|
svg = self.document.getroot()
|
|
|
|
# Convert parameters to user unit
|
|
offset = self.svg.viewport_to_unit(
|
|
str(self.options.crop_offset) + self.options.unit
|
|
)
|
|
bt = self.svg.viewport_to_unit(str(self.options.bleed_top) + self.options.unit)
|
|
bb = self.svg.viewport_to_unit(
|
|
str(self.options.bleed_bottom) + self.options.unit
|
|
)
|
|
bl = self.svg.viewport_to_unit(str(self.options.bleed_left) + self.options.unit)
|
|
br = self.svg.viewport_to_unit(
|
|
str(self.options.bleed_right) + self.options.unit
|
|
)
|
|
# Bleed margin
|
|
if bt < offset:
|
|
bmt = 0
|
|
else:
|
|
bmt = bt - offset
|
|
if bb < offset:
|
|
bmb = 0
|
|
else:
|
|
bmb = bb - offset
|
|
if bl < offset:
|
|
bml = 0
|
|
else:
|
|
bml = bl - offset
|
|
if br < offset:
|
|
bmr = 0
|
|
else:
|
|
bmr = br - offset
|
|
|
|
# Define the new document limits
|
|
offset_left = bbox.left - offset
|
|
offset_right = bbox.right + offset
|
|
offset_top = bbox.top - offset
|
|
offset_bottom = bbox.bottom + offset
|
|
|
|
# Get middle positions
|
|
middle_vertical = bbox.top + (bbox.height / 2)
|
|
middle_horizontal = bbox.left + (bbox.width / 2)
|
|
|
|
# Construct layer id and layer name
|
|
layer_id = "printing-marks"
|
|
layer_name = "Printing Marks"
|
|
if name != "":
|
|
layer_id += "-" + name
|
|
layer_name += " " + name
|
|
|
|
# Create a new layer
|
|
layer = svg.add(inkex.Layer.new(layer_name))
|
|
layer.set("id", layer_id)
|
|
layer.set("sodipodi:insensitive", "true")
|
|
|
|
# Crop Mark
|
|
if self.options.crop_marks:
|
|
# Create a group for Crop Mark
|
|
g_crops = layer.add(inkex.Group())
|
|
g_crops.label = "CropMarks"
|
|
g_crops.set("id", "CropMarks" + name)
|
|
|
|
# Top left Mark
|
|
self.draw_crop_line(
|
|
bbox.left,
|
|
offset_top,
|
|
bbox.left,
|
|
offset_top - self.mark_size,
|
|
"cropTL1",
|
|
g_crops,
|
|
)
|
|
self.draw_crop_line(
|
|
offset_left,
|
|
bbox.top,
|
|
offset_left - self.mark_size,
|
|
bbox.top,
|
|
"cropTL2",
|
|
g_crops,
|
|
)
|
|
|
|
# Top right Mark
|
|
self.draw_crop_line(
|
|
bbox.right,
|
|
offset_top,
|
|
bbox.right,
|
|
offset_top - self.mark_size,
|
|
"cropTR1",
|
|
g_crops,
|
|
)
|
|
self.draw_crop_line(
|
|
offset_right,
|
|
bbox.top,
|
|
offset_right + self.mark_size,
|
|
bbox.top,
|
|
"cropTR2",
|
|
g_crops,
|
|
)
|
|
|
|
# Bottom left Mark
|
|
self.draw_crop_line(
|
|
bbox.left,
|
|
offset_bottom,
|
|
bbox.left,
|
|
offset_bottom + self.mark_size,
|
|
"cropBL1",
|
|
g_crops,
|
|
)
|
|
self.draw_crop_line(
|
|
offset_left,
|
|
bbox.bottom,
|
|
offset_left - self.mark_size,
|
|
bbox.bottom,
|
|
"cropBL2",
|
|
g_crops,
|
|
)
|
|
|
|
# Bottom right Mark
|
|
self.draw_crop_line(
|
|
bbox.right,
|
|
offset_bottom,
|
|
bbox.right,
|
|
offset_bottom + self.mark_size,
|
|
"cropBR1",
|
|
g_crops,
|
|
)
|
|
self.draw_crop_line(
|
|
offset_right,
|
|
bbox.bottom,
|
|
offset_right + self.mark_size,
|
|
bbox.bottom,
|
|
"cropBR2",
|
|
g_crops,
|
|
)
|
|
|
|
# Bleed Mark
|
|
if self.options.bleed_marks:
|
|
# Create a group for Bleed Mark
|
|
g_bleed = layer.add(inkex.Group())
|
|
g_bleed.label = "BleedMarks"
|
|
g_bleed.set("id", "BleedMarks" + name)
|
|
|
|
# Top left Mark
|
|
self.draw_bleed_line(
|
|
bbox.left - bl,
|
|
offset_top - bmt,
|
|
bbox.left - bl,
|
|
offset_top - bmt - self.mark_size,
|
|
"bleedTL1",
|
|
g_bleed,
|
|
)
|
|
self.draw_bleed_line(
|
|
offset_left - bml,
|
|
bbox.top - bt,
|
|
offset_left - bml - self.mark_size,
|
|
bbox.top - bt,
|
|
"bleedTL2",
|
|
g_bleed,
|
|
)
|
|
|
|
# Top right Mark
|
|
self.draw_bleed_line(
|
|
bbox.right + br,
|
|
offset_top - bmt,
|
|
bbox.right + br,
|
|
offset_top - bmt - self.mark_size,
|
|
"bleedTR1",
|
|
g_bleed,
|
|
)
|
|
self.draw_bleed_line(
|
|
offset_right + bmr,
|
|
bbox.top - bt,
|
|
offset_right + bmr + self.mark_size,
|
|
bbox.top - bt,
|
|
"bleedTR2",
|
|
g_bleed,
|
|
)
|
|
|
|
# Bottom left Mark
|
|
self.draw_bleed_line(
|
|
bbox.left - bl,
|
|
offset_bottom + bmb,
|
|
bbox.left - bl,
|
|
offset_bottom + bmb + self.mark_size,
|
|
"bleedBL1",
|
|
g_bleed,
|
|
)
|
|
self.draw_bleed_line(
|
|
offset_left - bml,
|
|
bbox.bottom + bb,
|
|
offset_left - bml - self.mark_size,
|
|
bbox.bottom + bb,
|
|
"bleedBL2",
|
|
g_bleed,
|
|
)
|
|
|
|
# Bottom right Mark
|
|
self.draw_bleed_line(
|
|
bbox.right + br,
|
|
offset_bottom + bmb,
|
|
bbox.right + br,
|
|
offset_bottom + bmb + self.mark_size,
|
|
"bleedBR1",
|
|
g_bleed,
|
|
)
|
|
self.draw_bleed_line(
|
|
offset_right + bmr,
|
|
bbox.bottom + bb,
|
|
offset_right + bmr + self.mark_size,
|
|
bbox.bottom + bb,
|
|
"bleedBR2",
|
|
g_bleed,
|
|
)
|
|
|
|
# Registration Mark
|
|
if self.options.reg_marks:
|
|
# Create a group for Registration Mark
|
|
g_center = layer.add(inkex.Group())
|
|
g_center.label = "RegistrationMarks"
|
|
g_center.set("id", "RegistrationMarks" + name)
|
|
# Left Mark
|
|
cx = max(bml + offset, self.min_mark_margin)
|
|
self.draw_reg_marks(
|
|
bbox.left - cx - (self.mark_size / 2),
|
|
middle_vertical - self.mark_size * 1.5,
|
|
"0",
|
|
"regMarkL",
|
|
g_center,
|
|
)
|
|
|
|
# Right Mark
|
|
cx = max(bmr + offset, self.min_mark_margin)
|
|
self.draw_reg_marks(
|
|
bbox.right + cx + (self.mark_size / 2),
|
|
middle_vertical - self.mark_size * 1.5,
|
|
"180",
|
|
"regMarkR",
|
|
g_center,
|
|
)
|
|
|
|
# Top Mark
|
|
cy = max(bmt + offset, self.min_mark_margin)
|
|
self.draw_reg_marks(
|
|
middle_horizontal,
|
|
bbox.top - cy - (self.mark_size / 2),
|
|
"90",
|
|
"regMarkT",
|
|
g_center,
|
|
)
|
|
|
|
# Bottom Mark
|
|
cy = max(bmb + offset, self.min_mark_margin)
|
|
self.draw_reg_marks(
|
|
middle_horizontal,
|
|
bbox.bottom + cy + (self.mark_size / 2),
|
|
"-90",
|
|
"regMarkB",
|
|
g_center,
|
|
)
|
|
|
|
# Star Target
|
|
if self.options.star_target:
|
|
# Create a group for Star Target
|
|
g_center = layer.add(inkex.Group())
|
|
g_center.label = "StarTarget"
|
|
g_center.set("id", "StarTarget" + name)
|
|
|
|
if bbox.height < bbox.width:
|
|
# Left Star
|
|
cx = max(bml + offset, self.min_mark_margin)
|
|
self.draw_star_target(
|
|
bbox.left - cx - (self.mark_size / 2),
|
|
middle_vertical,
|
|
"starTargetL",
|
|
g_center,
|
|
)
|
|
# Right Star
|
|
cx = max(bmr + offset, self.min_mark_margin)
|
|
self.draw_star_target(
|
|
bbox.right + cx + (self.mark_size / 2),
|
|
middle_vertical,
|
|
"starTargetR",
|
|
g_center,
|
|
)
|
|
else:
|
|
# Top Star
|
|
cy = max(bmt + offset, self.min_mark_margin)
|
|
self.draw_star_target(
|
|
middle_horizontal - self.mark_size * 1.5,
|
|
bbox.top - cy - (self.mark_size / 2),
|
|
"starTargetT",
|
|
g_center,
|
|
)
|
|
# Bottom Star
|
|
cy = max(bmb + offset, self.min_mark_margin)
|
|
self.draw_star_target(
|
|
middle_horizontal - self.mark_size * 1.5,
|
|
bbox.bottom + cy + (self.mark_size / 2),
|
|
"starTargetB",
|
|
g_center,
|
|
)
|
|
|
|
# Colour Bars
|
|
if self.options.colour_bars:
|
|
# Create a group for Colour Bars
|
|
g_center = layer.add(inkex.Group())
|
|
g_center.label = "ColourBars"
|
|
g_center.set("id", "PrintingColourBars" + name)
|
|
|
|
if bbox.height > bbox.width:
|
|
# Left Bars
|
|
cx = max(bml + offset, self.min_mark_margin)
|
|
self.draw_coluor_bars(
|
|
bbox.left - cx - (self.mark_size / 2),
|
|
middle_vertical + self.mark_size,
|
|
90,
|
|
"PrintingColourBarsL",
|
|
g_center,
|
|
bbox,
|
|
)
|
|
# Right Bars
|
|
cx = max(bmr + offset, self.min_mark_margin)
|
|
self.draw_coluor_bars(
|
|
bbox.right + cx + (self.mark_size / 2),
|
|
middle_vertical + self.mark_size,
|
|
90,
|
|
"PrintingColourBarsR",
|
|
g_center,
|
|
bbox,
|
|
)
|
|
else:
|
|
# Top Bars
|
|
cy = max(bmt + offset, self.min_mark_margin)
|
|
self.draw_coluor_bars(
|
|
middle_horizontal + self.mark_size,
|
|
bbox.top - cy - (self.mark_size / 2),
|
|
0,
|
|
"PrintingColourBarsT",
|
|
g_center,
|
|
bbox,
|
|
)
|
|
# Bottom Bars
|
|
cy = max(bmb + offset, self.min_mark_margin)
|
|
self.draw_coluor_bars(
|
|
middle_horizontal + self.mark_size,
|
|
bbox.bottom + cy + (self.mark_size / 2),
|
|
0,
|
|
"PrintingColourBarsB",
|
|
g_center,
|
|
bbox,
|
|
)
|
|
|
|
# Page Information
|
|
if self.options.page_info:
|
|
# Create a group for Page Information
|
|
g_pag_info = layer.add(inkex.Group())
|
|
g_pag_info.label = "PageInformation"
|
|
g_pag_info.set("id", "PageInformation" + name)
|
|
y_margin = max(bmb + offset, self.min_mark_margin)
|
|
font_size = self.svg.viewport_to_unit("9pt")
|
|
txt_attribs = {
|
|
"style": f"font-size:{font_size}px;font-style:normal;font-weight:normal;fill:#000000;font-family:Bitstream Vera Sans,sans-serif;text-anchor:middle;text-align:center",
|
|
"x": str(middle_horizontal),
|
|
"y": str(bbox.bottom + y_margin + self.mark_size + 20),
|
|
}
|
|
txt = g_pag_info.add(TextElement(**txt_attribs))
|
|
txt.text = (
|
|
"Page size: "
|
|
+ str(
|
|
round(self.svg.unit_to_viewport(bbox.width, self.options.unit), 2)
|
|
)
|
|
+ "x"
|
|
+ str(
|
|
round(self.svg.unit_to_viewport(bbox.height, self.options.unit), 2)
|
|
)
|
|
+ " "
|
|
+ self.options.unit
|
|
)
|
|
|
|
def remove_layers(self):
|
|
# Find layers with id starting with "printing-marks" and remove them
|
|
layers = self.svg.xpath(
|
|
'//*[starts-with(@id, "printing-marks") and @inkscape:groupmode="layer"]'
|
|
)
|
|
for layer in layers:
|
|
self.document.getroot().remove(layer)
|
|
|
|
def effect(self):
|
|
self.mark_size = self.svg.viewport_to_unit("1cm")
|
|
self.min_mark_margin = self.svg.viewport_to_unit("3mm")
|
|
|
|
if self.options.where == "selection":
|
|
bbox = self.svg.selection.bounding_box()
|
|
if bbox is None:
|
|
raise inkex.AbortExtension(_("Selection is empty"))
|
|
|
|
self.remove_layers()
|
|
self.draw_effect(bbox)
|
|
else:
|
|
pages = self.svg.namedview.get_pages()
|
|
|
|
self.remove_layers()
|
|
|
|
# Handle single-page document
|
|
if len(pages) < 2:
|
|
self.draw_effect(self.svg.get_page_bbox(), "0")
|
|
else:
|
|
for p, page in enumerate(pages):
|
|
self.draw_effect(page.bounding_box, str(p))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
PrintingMarks().run()
|