summaryrefslogtreecommitdiffstats
path: root/share/extensions/print_win32_vector.py
diff options
context:
space:
mode:
Diffstat (limited to 'share/extensions/print_win32_vector.py')
-rwxr-xr-xshare/extensions/print_win32_vector.py214
1 files changed, 214 insertions, 0 deletions
diff --git a/share/extensions/print_win32_vector.py b/share/extensions/print_win32_vector.py
new file mode 100755
index 0000000..18db29a
--- /dev/null
+++ b/share/extensions/print_win32_vector.py
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+# coding=utf-8
+#
+# Copyright (C) 2012 Alvin Penner, penner@vaxxine.com
+#
+# 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 will generate vector graphics printout, specifically for Windows GDI32.
+
+This is a modified version of the file dxf_outlines.py by Aaron Spike, aaron@ekips.org
+It will write only to the default printer.
+The printing preferences dialog will be called.
+In order to ensure a pure vector output, use a linewidth < 1 printer pixel
+
+- see http://www.lessanvaezi.com/changing-printer-settings-using-the-windows-api/
+- get GdiPrintSample.zip at http://archive.msdn.microsoft.com/WindowsPrintSample
+
+"""
+
+import sys
+import ctypes
+
+import inkex
+from inkex import PathElement, Rectangle, Group, Use, Transform
+from inkex.paths import Path
+
+if sys.platform.startswith('win'):
+ myspool = ctypes.WinDLL("winspool.drv")
+ mygdi = ctypes.WinDLL("gdi32.dll")
+else:
+ myspool = None
+ mygdi = None
+
+LOGBRUSH = ctypes.c_long * 3
+DM_IN_PROMPT = 4 # call printer property sheet
+DM_OUT_BUFFER = 2 # write to DEVMODE structure
+
+class PrintWin32Vector(inkex.EffectExtension):
+ def __init__(self):
+ super(PrintWin32Vector, self).__init__()
+ self.visibleLayers = True # print only visible layers
+
+ def process_shape(self, node, mat):
+ """Process shape"""
+ rgb = (0, 0, 0) # stroke color
+ fillcolor = None # fill color
+ stroke = 1 # pen width in printer pixels
+ # Very NB : If the pen width is greater than 1 then the output will Not be a vector output !
+ style = node.style
+ if style:
+ if 'stroke' in style:
+ if style['stroke'] and style['stroke'] != 'none' and style['stroke'][0:3] != 'url':
+ rgb = inkex.Color(style['stroke']).to_rgb()
+ if 'stroke-width' in style:
+ stroke = self.svg.unittouu(style['stroke-width'])/self.svg.unittouu('1px')
+ stroke = int(stroke*self.scale)
+ if 'fill' in style:
+ if style['fill'] and style['fill'] != 'none' and style['fill'][0:3] != 'url':
+ fill = inkex.Color(style['fill']).to_rgb()
+ fillcolor = fill[0] + 256*fill[1] + 256*256*fill[2]
+ color = rgb[0] + 256*rgb[1] + 256*256*rgb[2]
+ if isinstance(node, PathElement):
+ p = node.path.to_superpath()
+ if not p:
+ return
+ elif isinstance(node, Rectangle):
+ x = float(node.get('x'))
+ y = float(node.get('y'))
+ width = float(node.get('width'))
+ height = float(node.get('height'))
+ p = [[[x, y],[x, y],[x, y]]]
+ p.append([[x + width, y],[x + width, y],[x + width, y]])
+ p.append([[x + width, y + height],[x + width, y + height],[x + width, y + height]])
+ p.append([[x, y + height],[x, y + height],[x, y + height]])
+ p.append([[x, y],[x, y],[x, y]])
+ p = [p]
+ else:
+ return
+ mat += node.transform
+ p = Path(p).transform(Transform(mat)).to_arrays()
+ hPen = mygdi.CreatePen(0, stroke, color)
+ mygdi.SelectObject(self.hDC, hPen)
+ self.emit_path(p)
+ if fillcolor is not None:
+ brush = LOGBRUSH(0, fillcolor, 0)
+ hBrush = mygdi.CreateBrushIndirect(ctypes.addressof(brush))
+ mygdi.SelectObject(self.hDC, hBrush)
+ mygdi.BeginPath(self.hDC)
+ self.emit_path(p)
+ mygdi.EndPath(self.hDC)
+ mygdi.FillPath(self.hDC)
+ return
+
+ def emit_path(self, p):
+ for sub in p:
+ mygdi.MoveToEx(self.hDC, int(sub[0][1][0]), int(sub[0][1][1]), None)
+ POINTS = ctypes.c_long*(6*(len(sub)-1))
+ points = POINTS()
+ for i in range(len(sub)-1):
+ points[6*i] = int(sub[i][2][0])
+ points[6*i + 1] = int(sub[i][2][1])
+ points[6*i + 2] = int(sub[i + 1][0][0])
+ points[6*i + 3] = int(sub[i + 1][0][1])
+ points[6*i + 4] = int(sub[i + 1][1][0])
+ points[6*i + 5] = int(sub[i + 1][1][1])
+ mygdi.PolyBezierTo(self.hDC, ctypes.addressof(points), 3*(len(sub)-1))
+ return
+
+ def process_clone(self, node):
+ trans = node.get('transform')
+ x = node.get('x')
+ y = node.get('y')
+ mat = Transform([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])
+ if trans:
+ mat *= Transform(trans)
+ if x:
+ mat *= Transform([[1.0, 0.0, float(x)], [0.0, 1.0, 0.0]])
+ if y:
+ mat *= Transform([[1.0, 0.0, 0.0], [0.0, 1.0, float(y)]])
+ # push transform
+ if trans or x or y:
+ self.groupmat.append(Transform(self.groupmat[-1]) * mat)
+ # get referenced node
+ refnode = node.href
+ if refnode is not None:
+ if isinstance(refnode, inkex.Group):
+ self.process_group(refnode)
+ elif refnode.tag == 'svg:use':
+ self.process_clone(refnode)
+ else:
+ self.process_shape(refnode, self.groupmat[-1])
+ # pop transform
+ if trans or x or y:
+ self.groupmat.pop()
+
+ def process_group(self, group):
+ if isinstance(group, inkex.Layer):
+ style = group.style
+ if 'display' in style:
+ if style['display'] == 'none' and self.visibleLayers:
+ return
+ trans = group.get('transform')
+ if trans:
+ self.groupmat.append(Transform(self.groupmat[-1]) * Transform(trans))
+ for node in group:
+ if isinstance(node, Group):
+ self.process_group(node)
+ elif isinstance(node, Use):
+ self.process_clone(node)
+ else:
+ self.process_shape(node, self.groupmat[-1])
+ if trans:
+ self.groupmat.pop()
+
+ def effect(self):
+ pcchBuffer = ctypes.c_long()
+ myspool.GetDefaultPrinterA(None, ctypes.byref(pcchBuffer)) # get length of printer name
+ pname = ctypes.create_string_buffer(pcchBuffer.value)
+ myspool.GetDefaultPrinterA(pname, ctypes.byref(pcchBuffer)) # get printer name
+ hPrinter = ctypes.c_long()
+ if myspool.OpenPrinterA(pname.value, ctypes.byref(hPrinter), None) == 0:
+ return inkex.errormsg(_("Failed to open default printer"))
+
+ # get printer properties dialog
+
+ pcchBuffer = myspool.DocumentPropertiesA(0, hPrinter, pname, None, None, 0)
+ pDevMode = ctypes.create_string_buffer(pcchBuffer + 100) # allocate extra just in case
+ pcchBuffer = myspool.DocumentPropertiesA(0, hPrinter, pname, ctypes.byref(pDevMode), None, DM_IN_PROMPT + DM_OUT_BUFFER)
+ myspool.ClosePrinter(hPrinter)
+ if pcchBuffer != 1: # user clicked Cancel
+ exit()
+
+ # initiallize print document
+
+ docname = self.svg.xpath('@sodipodi:docname')
+ if not docname:
+ docname = ['New document 1']
+ lpszDocName = ctypes.create_string_buffer('Inkscape ' + docname[0].split('\\')[-1])
+ DOCINFO = ctypes.c_long * 5
+ docInfo = DOCINFO(20, ctypes.addressof(lpszDocName), 0, 0, 0)
+ self.hDC = mygdi.CreateDCA(None, pname, None, ctypes.byref(pDevMode))
+ if mygdi.StartDocA(self.hDC, ctypes.byref(docInfo)) < 0:
+ exit() # user clicked Cancel
+
+ self.scale = (ord(pDevMode[58]) + 256.0*ord(pDevMode[59]))/96 # use PrintQuality from DEVMODE
+ self.scale /= self.svg.unittouu('1px')
+ h = self.svg.unittouu(self.svg.xpath('@height')[0])
+ doc = self.document.getroot()
+ # process viewBox height attribute to correct page scaling
+ viewBox = doc.get('viewBox')
+ if viewBox:
+ viewBox2 = viewBox.split(',')
+ if len(viewBox2) < 4:
+ viewBox2 = viewBox.split(' ')
+ self.scale *= h / self.svg.unittouu(self.addDocumentUnit(viewBox2[3]))
+ self.groupmat = [[[self.scale, 0.0, 0.0], [0.0, self.scale, 0.0]]]
+ self.process_group(doc)
+ mygdi.EndDoc(self.hDC)
+
+if __name__ == '__main__':
+ PrintWin32Vector().run()