2012-01-23 11:36:49 +00:00
|
|
|
# This file is part of the Printrun suite.
|
2012-08-08 06:39:50 +00:00
|
|
|
#
|
2012-01-23 11:36:49 +00:00
|
|
|
# Printrun 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 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
2012-08-08 06:39:50 +00:00
|
|
|
#
|
2012-01-23 11:36:49 +00:00
|
|
|
# Printrun 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.
|
2012-08-08 06:39:50 +00:00
|
|
|
#
|
2012-01-23 11:36:49 +00:00
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
import xml.etree.ElementTree
|
|
|
|
import wx
|
2012-05-27 12:10:35 +00:00
|
|
|
import os
|
|
|
|
import zipfile
|
|
|
|
import tempfile
|
|
|
|
import shutil
|
2012-05-21 20:38:49 +00:00
|
|
|
import svg.document as wxpsvgdocument
|
2012-05-27 17:12:38 +00:00
|
|
|
import imghdr
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
class dispframe(wx.Frame):
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, parent, title, res = (800, 600), printer = None):
|
|
|
|
wx.Frame.__init__(self, parent = parent, title = title)
|
2012-05-27 12:10:35 +00:00
|
|
|
self.p = printer
|
|
|
|
self.pic = wx.StaticBitmap(self)
|
|
|
|
self.bitmap = wx.EmptyBitmap(*res)
|
|
|
|
self.bbitmap = wx.EmptyBitmap(*res)
|
|
|
|
self.slicer = 'Skeinforge'
|
|
|
|
dc = wx.MemoryDC()
|
2012-03-04 18:02:28 +00:00
|
|
|
dc.SelectObject(self.bbitmap)
|
|
|
|
dc.SetBackground(wx.Brush("black"))
|
|
|
|
dc.Clear()
|
|
|
|
dc.SelectObject(wx.NullBitmap)
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
self.SetBackgroundColour("black")
|
|
|
|
self.pic.Hide()
|
2012-05-27 12:10:35 +00:00
|
|
|
self.pen = wx.Pen("white")
|
|
|
|
self.brush = wx.Brush("white")
|
2012-01-10 14:05:56 +00:00
|
|
|
self.SetDoubleBuffered(True)
|
|
|
|
self.Show()
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def drawlayer(self, image):
|
2012-01-10 14:05:56 +00:00
|
|
|
try:
|
2012-05-27 12:10:35 +00:00
|
|
|
dc = wx.MemoryDC()
|
2012-01-10 14:05:56 +00:00
|
|
|
dc.SelectObject(self.bitmap)
|
|
|
|
dc.SetBackground(wx.Brush("black"))
|
|
|
|
dc.Clear()
|
|
|
|
dc.SetPen(self.pen)
|
|
|
|
dc.SetBrush(self.brush)
|
2012-05-21 20:38:49 +00:00
|
|
|
|
|
|
|
if self.slicer == 'Skeinforge':
|
2012-05-27 12:10:35 +00:00
|
|
|
for i in image:
|
2012-05-21 20:38:49 +00:00
|
|
|
#print i
|
2012-05-27 12:10:35 +00:00
|
|
|
points = [wx.Point(*map(lambda x:int(round(float(x) * self.scale)), j.strip().split())) for j in i.strip().split("M")[1].split("L")]
|
|
|
|
dc.DrawPolygon(points, self.size[0] / 2, self.size[1] / 2)
|
|
|
|
elif self.slicer == 'Slic3r':
|
2012-08-08 06:39:50 +00:00
|
|
|
gc = wx.GraphicsContext_Create(dc)
|
2012-05-21 20:38:49 +00:00
|
|
|
gc.Translate(*self.offset)
|
|
|
|
gc.Scale(self.scale, self.scale)
|
2012-05-27 12:10:35 +00:00
|
|
|
wxpsvgdocument.SVGDocument(image).render(gc)
|
2012-05-27 17:12:38 +00:00
|
|
|
elif self.slicer == 'bitmap':
|
2012-05-27 12:10:35 +00:00
|
|
|
dc.DrawBitmap(image, self.offset[0], -self.offset[1], True)
|
|
|
|
else:
|
|
|
|
raise Exception(self.slicer + " is an unknown method.")
|
2012-01-10 14:05:56 +00:00
|
|
|
self.pic.SetBitmap(self.bitmap)
|
|
|
|
self.pic.Show()
|
|
|
|
self.Refresh()
|
2012-08-08 06:39:50 +00:00
|
|
|
|
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
except:
|
2012-03-04 18:02:28 +00:00
|
|
|
raise
|
2012-01-10 14:05:56 +00:00
|
|
|
pass
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def showimgdelay(self, image):
|
2012-03-04 18:02:28 +00:00
|
|
|
self.drawlayer(image)
|
|
|
|
self.pic.Show()
|
|
|
|
self.Refresh()
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-03-04 18:02:28 +00:00
|
|
|
self.Refresh()
|
2012-05-21 20:38:49 +00:00
|
|
|
if self.p != None and self.p.online:
|
2012-08-08 06:39:50 +00:00
|
|
|
self.p.send_now("G91")
|
|
|
|
self.p.send_now("G1 Z%f F300" % (self.thickness,))
|
|
|
|
self.p.send_now("G90")
|
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def nextimg(self, event):
|
|
|
|
if self.index < len(self.layers):
|
|
|
|
i = self.index
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
print i
|
2012-05-27 12:10:35 +00:00
|
|
|
wx.CallAfter(self.showimgdelay, self.layers[i])
|
|
|
|
wx.FutureCall(1000 * self.interval, self.pic.Hide)
|
|
|
|
self.index += 1
|
2012-01-10 14:05:56 +00:00
|
|
|
else:
|
|
|
|
print "end"
|
|
|
|
wx.CallAfter(self.pic.Hide)
|
|
|
|
wx.CallAfter(self.Refresh)
|
2012-05-27 12:10:35 +00:00
|
|
|
wx.CallAfter(self.ShowFullScreen, 0)
|
2012-08-08 06:39:50 +00:00
|
|
|
wx.CallAfter(self.timer.Stop)
|
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def present(self, layers, interval = 0.5, pause = 0.2, thickness = 0.4, scale = 20, size = (800, 600), offset = (0, 0)):
|
2012-01-10 14:05:56 +00:00
|
|
|
wx.CallAfter(self.pic.Hide)
|
|
|
|
wx.CallAfter(self.Refresh)
|
2012-05-27 12:10:35 +00:00
|
|
|
self.layers = layers
|
|
|
|
self.scale = scale
|
|
|
|
self.thickness = thickness
|
|
|
|
self.index = 0
|
2012-05-27 17:12:38 +00:00
|
|
|
self.size = (size[0] + offset[0], size[1] + offset[1])
|
2012-05-27 12:10:35 +00:00
|
|
|
self.interval = interval
|
|
|
|
self.offset = offset
|
|
|
|
self.timer = wx.Timer(self, 1)
|
|
|
|
self.timer.Bind(wx.EVT_TIMER, self.nextimg)
|
|
|
|
self.Bind(wx.EVT_TIMER, self.nextimg)
|
|
|
|
self.timer.Start(1000 * interval + 1000 * pause)
|
2012-01-10 14:05:56 +00:00
|
|
|
|
|
|
|
class setframe(wx.Frame):
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
def __init__(self, parent, printer = None):
|
|
|
|
wx.Frame.__init__(self, parent, title = "Projector setup")
|
|
|
|
self.f = dispframe(None, "", printer = printer)
|
2012-05-27 12:10:35 +00:00
|
|
|
self.panel = wx.Panel(self)
|
2012-01-10 14:05:56 +00:00
|
|
|
self.panel.SetBackgroundColour("orange")
|
2012-08-08 07:38:48 +00:00
|
|
|
self.bload = wx.Button(self.panel, -1, "Load", pos = (0, 0))
|
2012-05-27 12:10:35 +00:00
|
|
|
self.bload.Bind(wx.EVT_BUTTON, self.loadfile)
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Layer:", pos = (0, 30))
|
|
|
|
wx.StaticText(self.panel, -1, "mm", pos = (130, 30))
|
|
|
|
self.thickness = wx.TextCtrl(self.panel, -1, "0.5", pos = (50, 30))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Exposure:", pos = (0, 60))
|
|
|
|
wx.StaticText(self.panel, -1, "s", pos = (130, 60))
|
|
|
|
self.interval = wx.TextCtrl(self.panel, -1, "0.5", pos = (50, 60))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Blank:", pos = (0, 90))
|
|
|
|
wx.StaticText(self.panel, -1, "s", pos = (130, 90))
|
|
|
|
self.delay = wx.TextCtrl(self.panel, -1, "0.5", pos = (50, 90))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Scale:", pos = (0, 120))
|
|
|
|
wx.StaticText(self.panel, -1, "x", pos = (130, 120))
|
|
|
|
self.scale = wx.TextCtrl(self.panel, -1, "5", pos = (50, 120))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "X:", pos = (160, 30))
|
|
|
|
self.X = wx.TextCtrl(self.panel, -1, "1024", pos = (210, 30))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Y:", pos = (160, 60))
|
|
|
|
self.Y = wx.TextCtrl(self.panel, -1, "768", pos = (210, 60))
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "OffsetX:", pos = (160, 90))
|
|
|
|
self.offsetX = wx.TextCtrl(self.panel, -1, "50", pos = (210, 90))
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "OffsetY:", pos = (160, 120))
|
|
|
|
self.offsetY = wx.TextCtrl(self.panel, -1, "50", pos = (210, 120))
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
self.bload = wx.Button(self.panel, -1, "Present", pos = (0, 150))
|
2012-05-27 12:10:35 +00:00
|
|
|
self.bload.Bind(wx.EVT_BUTTON, self.startdisplay)
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-08-08 07:38:48 +00:00
|
|
|
wx.StaticText(self.panel, -1, "Fullscreen:", pos = (160, 150))
|
|
|
|
self.fullscreen = wx.CheckBox(self.panel, -1, pos = (220, 150))
|
2012-05-27 12:10:35 +00:00
|
|
|
self.fullscreen.SetValue(True)
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-01-10 14:05:56 +00:00
|
|
|
self.Show()
|
2012-05-21 20:38:49 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def __del__(self):
|
|
|
|
if hasattr(self, 'image_dir') and self.image_dir != '':
|
|
|
|
shutil.rmtree(self.image_dir)
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def parsesvg(self, name):
|
2012-08-08 07:38:48 +00:00
|
|
|
et = xml.etree.ElementTree.ElementTree(file = name)
|
2012-05-27 12:10:35 +00:00
|
|
|
#xml.etree.ElementTree.dump(et)
|
|
|
|
slicer = 'Slic3r' if et.getroot().find('{http://www.w3.org/2000/svg}metadata') == None else 'Skeinforge'
|
|
|
|
zlast = 0
|
|
|
|
zdiff = 0
|
|
|
|
ol = []
|
|
|
|
if (slicer == 'Slic3r'):
|
|
|
|
height = et.getroot().get('height')
|
|
|
|
width = et.getroot().get('width')
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
for i in et.findall("{http://www.w3.org/2000/svg}g"):
|
|
|
|
z = float(i.get('{http://slic3r.org/namespaces/slic3r}z'))
|
|
|
|
zdiff = z - zlast
|
|
|
|
zlast = z
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
svgSnippet = xml.etree.ElementTree.Element('{http://www.w3.org/2000/svg}svg')
|
|
|
|
svgSnippet.set('height', height + 'mm')
|
|
|
|
svgSnippet.set('width', width + 'mm')
|
|
|
|
svgSnippet.set('viewBox', '0 0 ' + height + ' ' + width)
|
|
|
|
svgSnippet.append(i)
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
ol += [svgSnippet]
|
|
|
|
else :
|
|
|
|
for i in et.findall("{http://www.w3.org/2000/svg}g")[0].findall("{http://www.w3.org/2000/svg}g"):
|
|
|
|
z = float(i.get('id').split("z:")[-1])
|
|
|
|
zdiff = z - zlast
|
|
|
|
zlast = z
|
|
|
|
path = i.find('{http://www.w3.org/2000/svg}path')
|
|
|
|
ol += [(path.get("d").split("z"))[:-1]]
|
|
|
|
return ol, zdiff, slicer
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def parse3DLPzip(self, name):
|
|
|
|
if not zipfile.is_zipfile(name):
|
|
|
|
raise Exception(name + " is not a zip file!")
|
2012-05-27 17:12:38 +00:00
|
|
|
acceptedImageTypes = ['gif','tiff','jpg','jpeg','bmp','png']
|
2012-05-27 12:10:35 +00:00
|
|
|
zipFile = zipfile.ZipFile(name, 'r')
|
|
|
|
self.image_dir = tempfile.mkdtemp()
|
|
|
|
zipFile.extractall(self.image_dir)
|
|
|
|
ol = []
|
|
|
|
for f in os.listdir(self.image_dir):
|
|
|
|
path = os.path.join(self.image_dir, f)
|
2012-05-27 17:12:38 +00:00
|
|
|
if os.path.isfile(path) and imghdr.what(path) in acceptedImageTypes:
|
2012-05-27 12:10:35 +00:00
|
|
|
ol.append(wx.Bitmap(path))
|
2012-05-27 17:12:38 +00:00
|
|
|
return ol, -1, "bitmap"
|
2012-08-08 06:39:50 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def loadfile(self, event):
|
2012-08-08 07:38:48 +00:00
|
|
|
dlg = wx.FileDialog(self, ("Open file to print"), style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
|
2012-05-27 12:10:35 +00:00
|
|
|
dlg.SetWildcard(("Slic3r or Skeinforge svg files (;*.svg;*.SVG;);3DLP Zip (;*.3dlp.zip;)"))
|
2012-01-10 14:05:56 +00:00
|
|
|
if(dlg.ShowModal() == wx.ID_OK):
|
2012-05-27 12:10:35 +00:00
|
|
|
name = dlg.GetPath()
|
2012-01-10 14:05:56 +00:00
|
|
|
if not(os.path.exists(name)):
|
|
|
|
self.status.SetStatusText(("File not found!"))
|
|
|
|
return
|
2012-05-27 12:10:35 +00:00
|
|
|
if name.endswith(".3dlp.zip"):
|
|
|
|
layers = self.parse3DLPzip(name)
|
|
|
|
layerHeight = float(self.thickness.GetValue())
|
|
|
|
else:
|
|
|
|
layers = self.parsesvg(name)
|
|
|
|
layerHeight = layers[1]
|
|
|
|
self.thickness.SetValue(str(layers[1]))
|
|
|
|
print "Layer thickness detected:", layerHeight, "mm"
|
|
|
|
print len(layers[0]), "layers found, total height", layerHeight * len(layers[0]), "mm"
|
|
|
|
self.layers = layers
|
2012-05-21 20:38:49 +00:00
|
|
|
self.f.slicer = layers[2]
|
2012-04-18 13:19:44 +00:00
|
|
|
dlg.Destroy()
|
2012-01-10 14:05:56 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
def startdisplay(self, event):
|
2012-01-10 14:05:56 +00:00
|
|
|
self.f.Raise()
|
2012-05-27 12:10:35 +00:00
|
|
|
if (self.fullscreen.GetValue()):
|
|
|
|
self.f.ShowFullScreen(1)
|
|
|
|
l = self.layers[0][:]
|
2012-05-21 20:38:49 +00:00
|
|
|
self.f.present(l,
|
2012-08-08 07:38:48 +00:00
|
|
|
thickness = float(self.thickness.GetValue()),
|
|
|
|
interval = float(self.interval.GetValue()),
|
|
|
|
scale = float(self.scale.GetValue()),
|
|
|
|
pause = float(self.delay.GetValue()),
|
|
|
|
size = (float(self.X.GetValue()), float(self.Y.GetValue())),
|
|
|
|
offset = (float(self.offsetX.GetValue()), float(self.offsetY.GetValue())))
|
2012-01-10 14:05:56 +00:00
|
|
|
|
2012-05-27 12:10:35 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
a = wx.App()
|
2012-01-10 16:09:46 +00:00
|
|
|
setframe(None).Show()
|
|
|
|
a.MainLoop()
|