Code

Prune initial timer work.
[inkscape.git] / share / extensions / printing-marks.py
1 #!/usr/bin/env python
2 '''
3 This extension allows you to draw crop, registration and other
4 printing marks in Inkscape.
6 Authors:
7   Nicolas Dufour - Association Inkscape-fr
8   Aurelio A. Heckert <aurium(a)gmail.com>
10 Copyright (C) 2008 Authors
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 '''
27 import inkex, simplestyle, math
28 from subprocess import Popen, PIPE, STDOUT
30 class Printing_Marks (inkex.Effect):
32     # Default parameters
33     stroke_width = 0.25
34     mark_size = inkex.unittouu('1cm')
35     min_mark_margin = inkex.unittouu('3mm')
37     def __init__(self):
38         inkex.Effect.__init__(self)
39         self.OptionParser.add_option("--where",
40                                      action="store", type="string",
41                                      dest="where_to_crop", default=True,
42                                      help="Apply crop marks to...")
43         self.OptionParser.add_option("--crop_marks",
44                                      action="store", type="inkbool",
45                                      dest="crop_marks", default=True,
46                                      help="Draw crop Marks?")
47         self.OptionParser.add_option("--bleed_marks",
48                                      action="store", type="inkbool",
49                                      dest="bleed_marks", default=False,
50                                      help="Draw Bleed Marks?")
51         self.OptionParser.add_option("--registration_marks",
52                                      action="store", type="inkbool",
53                                      dest="reg_marks", default=False,
54                                      help="Draw Registration Marks?")
55         self.OptionParser.add_option("--star_target",
56                                      action="store", type="inkbool",
57                                      dest="star_target", default=False,
58                                      help="Draw Star Target?")
59         self.OptionParser.add_option("--colour_bars",
60                                      action="store", type="inkbool",
61                                      dest="colour_bars", default=False,
62                                      help="Draw Colour Bars?")
63         self.OptionParser.add_option("--page_info",
64                                      action="store", type="inkbool",
65                                      dest="page_info", default=False,
66                                      help="Draw Page Information?")
67         self.OptionParser.add_option("--unit",
68                                      action="store", type="string",
69                                      dest="unit", default=100.0,
70                                      help="Draw measurment")
71         self.OptionParser.add_option("--crop_offset",
72                                      action="store", type="float",
73                                      dest="crop_offset", default=0,
74                                      help="Offset")
75         self.OptionParser.add_option("--bleed_top",
76                                      action="store", type="float",
77                                      dest="bleed_top", default=0,
78                                      help="Bleed Top Size")
79         self.OptionParser.add_option("--bleed_bottom",
80                                      action="store", type="float",
81                                      dest="bleed_bottom", default=0,
82                                      help="Bleed Bottom Size")
83         self.OptionParser.add_option("--bleed_left",
84                                      action="store", type="float",
85                                      dest="bleed_left", default=0,
86                                      help="Bleed Left Size")
87         self.OptionParser.add_option("--bleed_right",
88                                      action="store", type="float",
89                                      dest="bleed_right", default=0,
90                                      help="Bleed Right Size")
91         self.OptionParser.add_option("--tab",
92                                      action="store", type="string",
93                                      dest="tab",
94                                      help="The selected UI-tab when OK was pressed")
96     def draw_crop_line(self, x1, y1, x2, y2, name, parent):
97         style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width),
98                   'fill': 'none'}
99         line_attribs = {'style': simplestyle.formatStyle(style),
100                         'id': name,
101                         'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
102         inkex.etree.SubElement(parent, 'path', line_attribs)
104     def draw_bleed_line(self, x1, y1, x2, y2, name, parent):
105         style = { 'stroke': '#000000', 'stroke-width': str(self.stroke_width),
106                   'fill': 'none',
107                   'stroke-miterlimit': '4', 'stroke-dasharray': '4, 2, 1, 2',
108                   'stroke-dashoffset': '0' }
109         line_attribs = {'style': simplestyle.formatStyle(style),
110                         'id': name,
111                         'd': 'M '+str(x1)+','+str(y1)+' L '+str(x2)+','+str(y2)}
112         inkex.etree.SubElement(parent, 'path', line_attribs)
114     def draw_reg_circles(self, cx, cy, r, name, colours, parent):
115         for i in range(len(colours)):
116             style = {'stroke':colours[i], 'stroke-width':str(r / len(colours)),
117                      'fill':'none'}
118             circle_attribs = {'style':simplestyle.formatStyle(style),
119                               inkex.addNS('label','inkscape'):name,
120                               'cx':str(cx), 'cy':str(cy),
121                               'r':str((r / len(colours)) * (i + 0.5))}
122             inkex.etree.SubElement(parent, inkex.addNS('circle','svg'),
123                                    circle_attribs)
125     def draw_reg_marks(self, cx, cy, rotate, name, parent):
126         colours = ['#000000','#00ffff','#ff00ff','#ffff00','#000000']
127         g = inkex.etree.SubElement(parent, 'g', { 'id': name })
128         for i in range(len(colours)):
129             style = {'fill':colours[i], 'fill-opacity':'1', 'stroke':'none'}
130             r = (self.mark_size/2)
131             step = r
132             stroke = r / len(colours)
133             regoffset = stroke * i
134             regmark_attribs = {'style': simplestyle.formatStyle(style),
135                                'd': 'm' +\
136                                ' '+str(-regoffset)+','+str(r)  +\
137                                ' '+str(-stroke)   +',0'        +\
138                                ' '+str(step)      +','+str(-r) +\
139                                ' '+str(-step)     +','+str(-r) +\
140                                ' '+str(stroke)    +',0'        +\
141                                ' '+str(step)      +','+str(r)  +\
142                                ' '+str(-step)     +','+str(r)  +\
143                                ' z',
144                                'transform': 'translate('+str(cx)+','+str(cy)+ \
145                                             ') rotate('+str(rotate)+')'}
146             inkex.etree.SubElement(g, 'path', regmark_attribs)
148     def draw_star_target(self, cx, cy, name, parent):
149         r = (self.mark_size/2)
150         style = {'fill':'#000 device-cmyk(1,1,1,1)', 'fill-opacity':'1', 'stroke':'none'}
151         d = ' M 0,0'
152         i = 0
153         while i < ( 2 * math.pi ):
154             i += math.pi / 16
155             d += ' L 0,0 ' +\
156                  ' L '+ str(math.sin(i)*r) +','+ str(math.cos(i)*r) +\
157                  ' L '+ str(math.sin(i+0.09)*r) +','+ str(math.cos(i+0.09)*r)
158         regmark_attribs = {'style':simplestyle.formatStyle(style),
159                           inkex.addNS('label','inkscape'):name,
160                           'transform':'translate('+str(cx)+','+str(cy)+')',
161                           'd':d}
162         inkex.etree.SubElement(parent, inkex.addNS('path','svg'),
163                                regmark_attribs)
165     def draw_coluor_bars(self, cx, cy, rotate, name, parent):
166         g = inkex.etree.SubElement(parent, 'g', {
167                 'id':name,
168                 'transform':'translate('+str(cx)+','+str(cy)+\
169                             ') rotate('+str(rotate)+')' })
170         l = min( self.mark_size / 3, max(self.area_w,self.area_h) / 45 )
171         for bar in [{'c':'*', 'stroke':'#000', 'x':0,        'y':-(l+1)},
172                     {'c':'r', 'stroke':'#0FF', 'x':0,        'y':0},
173                     {'c':'g', 'stroke':'#F0F', 'x':(l*11)+1, 'y':-(l+1)},
174                     {'c':'b', 'stroke':'#FF0', 'x':(l*11)+1, 'y':0}
175                    ]:
176             i = 0
177             while i <= 1:
178                 cr = '255'
179                 cg = '255'
180                 cb = '255'
181                 if bar['c'] == 'r' or bar['c'] == '*' : cr = str(255*i)
182                 if bar['c'] == 'g' or bar['c'] == '*' : cg = str(255*i)
183                 if bar['c'] == 'b' or bar['c'] == '*' : cb = str(255*i)
184                 r_att = {'fill':'rgb('+cr+','+cg+','+cb+')',
185                          'stroke':bar['stroke'],
186                          'stroke-width':'0.5',
187                          'x':str((l*i*10)+bar['x']), 'y':str(bar['y']),
188                          'width':str(l), 'height':str(l)}
189                 r = inkex.etree.SubElement(g, 'rect', r_att)
190                 i += 0.1
192     def get_selection_area(self):
193         sel_area = {}
194         min_x, min_y, max_x, max_y = False, False, False, False
195         for id in self.options.ids:
196             sel_area[id] = {}
197             for att in [ "x", "y", "width", "height" ]:
198                 args = [ "inkscape", "-I", id, "--query-"+att, self.svg_file ]
199                 sel_area[id][att] = \
200                     Popen(args, stdout=PIPE, stderr=PIPE).communicate()[0]
201             current_min_x = float( sel_area[id]["x"] )
202             current_min_y = float( sel_area[id]["y"] )
203             current_max_x = float( sel_area[id]["x"] ) + \
204                             float( sel_area[id]["width"] )
205             current_max_y = float( sel_area[id]["y"] ) + \
206                             float( sel_area[id]["height"] )
207             if not min_x: min_x = current_min_x
208             if not min_y: min_y = current_min_y
209             if not max_x: max_x = current_max_x
210             if not max_y: max_y = current_max_y
211             if current_min_x < min_x: min_x = current_min_x
212             if current_min_y < min_y: min_y = current_min_y
213             if current_max_x > max_x: max_x = current_max_x
214             if current_max_y > max_y: max_y = current_max_y
215             #inkex.errormsg( '>> '+ id +
216             #                ' min_x:'+ str(min_x) +
217             #                ' min_y:'+ str(min_y) +
218             #                ' max_x:'+ str(max_x) +
219             #                ' max_y:'+ str(max_y) )
220         self.area_x1 = min_x
221         self.area_y1 = min_y
222         self.area_x2 = max_x
223         self.area_y2 = max_y
224         self.area_w = max_x - min_x
225         self.area_h = max_y - min_y
227     def effect(self):
229         if self.options.where_to_crop == 'selection' :
230             self.get_selection_area()
231             #inkex.errormsg('Sory, the crop to selection is a TODO feature')
232             #exit(1)
233         else :
234             svg = self.document.getroot()
235             self.area_w  = inkex.unittouu(svg.get('width'))
236             self.area_h  = inkex.unittouu(svg.attrib['height'])
237             self.area_x1 = 0
238             self.area_y1 = 0
239             self.area_x2 = self.area_w
240             self.area_y2 = self.area_h
242         # Get SVG document dimensions
243         # self.width must be replaced by self.area_x2. same to others.
244         svg = self.document.getroot()
245         #self.width  = width  = inkex.unittouu(svg.get('width'))
246         #self.height = height = inkex.unittouu(svg.attrib['height'])
248         # Convert parameters to user unit
249         offset = inkex.unittouu(str(self.options.crop_offset) + \
250                                 self.options.unit)
251         bt = inkex.unittouu(str(self.options.bleed_top)    + self.options.unit)
252         bb = inkex.unittouu(str(self.options.bleed_bottom) + self.options.unit)
253         bl = inkex.unittouu(str(self.options.bleed_left)   + self.options.unit)
254         br = inkex.unittouu(str(self.options.bleed_right)  + self.options.unit)
255         # Bleed margin
256         if bt < offset : bmt = 0
257         else :           bmt = bt - offset
258         if bb < offset : bmb = 0
259         else :           bmb = bb - offset
260         if bl < offset : bml = 0
261         else :           bml = bl - offset
262         if br < offset : bmr = 0
263         else :           bmr = br - offset
265         # Define the new document limits
266         offset_left   = self.area_x1 - offset
267         offset_right  = self.area_x2 + offset
268         offset_top    = self.area_y1 - offset
269         offset_bottom = self.area_y2 + offset
271         # Get middle positions
272         middle_vertical   = self.area_y1 + ( self.area_h / 2 )
273         middle_horizontal = self.area_x1 + ( self.area_w / 2 )
275         # Test if printing-marks layer existis
276         layer = self.document.xpath(
277                      '//*[@id="printing-marks" and @inkscape:groupmode="layer"]',
278                      namespaces=inkex.NSS)
279         if layer: svg.remove(layer[0]) # remove if it existis
280         # Create a new layer
281         layer = inkex.etree.SubElement(svg, 'g')
282         layer.set('id', 'printing-marks')
283         layer.set(inkex.addNS('label', 'inkscape'), 'Printing Marks')
284         layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
285         layer.set(inkex.addNS('insensitive', 'sodipodi'), 'true')
287         # Crop Mark
288         if self.options.crop_marks == True:
289             # Create a group for Crop Mark
290             g_attribs = {inkex.addNS('label','inkscape'):'CropMarks',
291                                                     'id':'CropMarks'}
292             g_crops = inkex.etree.SubElement(layer, 'g', g_attribs)
294             # Top left Mark
295             self.draw_crop_line(self.area_x1, offset_top,
296                                 self.area_x1, offset_top - self.mark_size,
297                                 'cropTL1', g_crops)
298             self.draw_crop_line(offset_left, self.area_y1,
299                                 offset_left - self.mark_size, self.area_y1,
300                                 'cropTL2', g_crops)
302             # Top right Mark
303             self.draw_crop_line(self.area_x2, offset_top,
304                                 self.area_x2, offset_top - self.mark_size,
305                                 'cropTR1', g_crops)
306             self.draw_crop_line(offset_right, self.area_y1,
307                                 offset_right + self.mark_size, self.area_y1,
308                                 'cropTR2', g_crops)
310             # Bottom left Mark
311             self.draw_crop_line(self.area_x1, offset_bottom,
312                                 self.area_x1, offset_bottom + self.mark_size,
313                                 'cropBL1', g_crops)
314             self.draw_crop_line(offset_left, self.area_y2,
315                                 offset_left - self.mark_size, self.area_y2,
316                                 'cropBL2', g_crops)
318             # Bottom right Mark
319             self.draw_crop_line(self.area_x2, offset_bottom,
320                                 self.area_x2, offset_bottom + self.mark_size,
321                                 'cropBR1', g_crops)
322             self.draw_crop_line(offset_right, self.area_y2,
323                                 offset_right + self.mark_size, self.area_y2,
324                                 'cropBR2', g_crops)
326         # Bleed Mark
327         if self.options.bleed_marks == True:
328             # Create a group for Bleed Mark
329             g_attribs = {inkex.addNS('label','inkscape'):'BleedMarks',
330                                                     'id':'BleedMarks'}
331             g_bleed = inkex.etree.SubElement(layer, 'g', g_attribs)
333             # Top left Mark
334             self.draw_bleed_line(self.area_x1 - bl, offset_top - bmt,
335                                  self.area_x1 - bl, offset_top - bmt - self.mark_size,
336                                  'bleedTL1', g_bleed)
337             self.draw_bleed_line(offset_left - bml, self.area_y1 - bt,
338                                  offset_left - bml - self.mark_size, self.area_y1 - bt,
339                                  'bleedTL2', g_bleed)
341             # Top right Mark
342             self.draw_bleed_line(self.area_x2 + br, offset_top - bmt,
343                                  self.area_x2 + br, offset_top - bmt - self.mark_size,
344                                  'bleedTR1', g_bleed)
345             self.draw_bleed_line(offset_right + bmr, self.area_y1 - bt,
346                                  offset_right + bmr + self.mark_size, self.area_y1 - bt,
347                                  'bleedTR2', g_bleed)
349             # Bottom left Mark
350             self.draw_bleed_line(self.area_x1 - bl, offset_bottom + bmb,
351                                  self.area_x1 - bl, offset_bottom + bmb + self.mark_size,
352                                  'bleedBL1', g_bleed)
353             self.draw_bleed_line(offset_left - bml, self.area_y2 + bb,
354                                  offset_left - bml - self.mark_size, self.area_y2 + bb,
355                                  'bleedBL2', g_bleed)
357             # Bottom right Mark
358             self.draw_bleed_line(self.area_x2 + br, offset_bottom + bmb,
359                                  self.area_x2 + br, offset_bottom + bmb + self.mark_size,
360                                  'bleedBR1', g_bleed)
361             self.draw_bleed_line(offset_right + bmr, self.area_y2 + bb,
362                                  offset_right + bmr + self.mark_size, self.area_y2 + bb,
363                                  'bleedBR2', g_bleed)
365         # Registration Mark
366         if self.options.reg_marks == True:
367             # Create a group for Registration Mark
368             g_attribs = {inkex.addNS('label','inkscape'):'RegistrationMarks',
369                                                     'id':'RegistrationMarks'}
370             g_center = inkex.etree.SubElement(layer, 'g', g_attribs)
372             # Left Mark
373             cx = max( bml + offset, self.min_mark_margin )
374             self.draw_reg_marks(self.area_x1 - cx - (self.mark_size/2),
375                                 middle_vertical - self.mark_size*1.5,
376                                 '0', 'regMarkL', g_center)
378             # Right Mark
379             cx = max( bmr + offset, self.min_mark_margin )
380             self.draw_reg_marks(self.area_x2 + cx + (self.mark_size/2),
381                                 middle_vertical - self.mark_size*1.5,
382                                 '180', 'regMarkR', g_center)
384             # Top Mark
385             cy = max( bmt + offset, self.min_mark_margin )
386             self.draw_reg_marks(middle_horizontal,
387                                 self.area_y1 - cy - (self.mark_size/2),
388                                 '90', 'regMarkT', g_center)
390             # Bottom Mark
391             cy = max( bmb + offset, self.min_mark_margin )
392             self.draw_reg_marks(middle_horizontal,
393                                 self.area_y2 + cy + (self.mark_size/2),
394                                 '-90', 'regMarkB', g_center)
396         # Star Target
397         if self.options.star_target == True:
398             # Create a group for Star Target
399             g_attribs = {inkex.addNS('label','inkscape'):'StarTarget',
400                                                     'id':'StarTarget'}
401             g_center = inkex.etree.SubElement(layer, 'g', g_attribs)
403             if self.area_h < self.area_w :
404                 # Left Star
405                 cx = max( bml + offset, self.min_mark_margin )
406                 self.draw_star_target(self.area_x1 - cx - (self.mark_size/2),
407                                       middle_vertical,
408                                       'starTargetL', g_center)
409                 # Right Star
410                 cx = max( bmr + offset, self.min_mark_margin )
411                 self.draw_star_target(self.area_x2 + cx + (self.mark_size/2),
412                                       middle_vertical,
413                                       'starTargetR', g_center)
414             else :
415                 # Top Star
416                 cy = max( bmt + offset, self.min_mark_margin )
417                 self.draw_star_target(middle_horizontal - self.mark_size*1.5,
418                                       self.area_y1 - cy - (self.mark_size/2),
419                                       'starTargetT', g_center)
420                 # Bottom Star
421                 cy = max( bmb + offset, self.min_mark_margin )
422                 self.draw_star_target(middle_horizontal - self.mark_size*1.5,
423                                       self.area_y2 + cy + (self.mark_size/2),
424                                       'starTargetB', g_center)
427         # Colour Bars
428         if self.options.colour_bars == True:
429             # Create a group for Colour Bars
430             g_attribs = {inkex.addNS('label','inkscape'):'ColourBars',
431                                                     'id':'PrintingColourBars'}
432             g_center = inkex.etree.SubElement(layer, 'g', g_attribs)
434             if self.area_h > self.area_w :
435                 # Left Bars
436                 cx = max( bml + offset, self.min_mark_margin )
437                 self.draw_coluor_bars(self.area_x1 - cx - (self.mark_size/2),
438                                       middle_vertical + self.mark_size,
439                                       90,
440                                       'PrintingColourBarsL', g_center)
441                 # Right Bars
442                 cx = max( bmr + offset, self.min_mark_margin )
443                 self.draw_coluor_bars(self.area_x2 + cx + (self.mark_size/2),
444                                       middle_vertical + self.mark_size,
445                                       90,
446                                       'PrintingColourBarsR', g_center)
447             else :
448                 # Top Bars
449                 cy = max( bmt + offset, self.min_mark_margin )
450                 self.draw_coluor_bars(middle_horizontal + self.mark_size,
451                                       self.area_y1 - cy - (self.mark_size/2),
452                                       0,
453                                       'PrintingColourBarsT', g_center)
454                 # Bottom Bars
455                 cy = max( bmb + offset, self.min_mark_margin )
456                 self.draw_coluor_bars(middle_horizontal + self.mark_size,
457                                       self.area_y2 + cy + (self.mark_size/2),
458                                       0,
459                                       'PrintingColourBarsB', g_center)
462         # Page Information
463         if self.options.page_info == True:
464             # Create a group for Page Information
465             g_attribs = {inkex.addNS('label','inkscape'):'PageInformation',
466                                                     'id':'PageInformation'}
467             g_pag_info = inkex.etree.SubElement(layer, 'g', g_attribs)
468             y_margin = max( bmb + offset, self.min_mark_margin )
469             txt_attribs = {
470                     'style': 'font-size:12px;font-style:normal;font-weight:normal;fill:#000000;font-family:Bitstream Vera Sans,sans-serif;text-anchor:middle;text-align:center',
471                     'x': str(middle_horizontal),
472                     'y': str(self.area_y2+y_margin+self.mark_size+20)
473                 }
474             txt = inkex.etree.SubElement(g_pag_info, 'text', txt_attribs)
475             txt.text = 'Page size: ' +\
476                        str(round(inkex.uutounit(self.area_w,self.options.unit),2)) +\
477                        'x' +\
478                        str(round(inkex.uutounit(self.area_h,self.options.unit),2)) +\
479                        ' ' + self.options.unit
482 if __name__ == '__main__':
483     e = Printing_Marks()
484     e.affect()