#!/usr/bin/env python # coding=utf-8 # # Authors: # Nicolas Dufour - Association Inkscape-fr # Aurelio A. Heckert # # 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 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")) else: bbox = self.svg.get_page_bbox() # 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) # Test if printing-marks layer existis layer = self.svg.xpath( '//*[@id="printing-marks" and @inkscape:groupmode="layer"]' ) if layer: svg.remove(layer[0]) # remove if it existis # Create a new layer layer = svg.add(inkex.Layer.new("Printing Marks")) layer.set("id", "printing-marks") layer.set("sodipodi:insensitive", "true") # Crop Mark if self.options.crop_marks: # Create a group for Crop Mark g_crops = layer.add(inkex.Group(id="CropMarks")) g_crops.label = "CropMarks" # 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") # 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") # 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") 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") 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") 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 ) if __name__ == "__main__": PrintingMarks().run()