def processNextJob(self): """Take a job from the queue and process it. emits renderfinished(jobid, img, painthelper) when done, if job has not been superseded """ self.mutex.lock() jobid, helper = self.latestjobs[-1] del self.latestjobs[-1] lastadded = self.latestaddedjob self.mutex.unlock() # don't process jobs which have been superseded if lastadded == jobid: img = qt4.QImage(helper.pagesize[0], helper.pagesize[1], qt4.QImage.Format_ARGB32_Premultiplied) img.fill(setting.settingdb.color('page').rgb()) painter = qt4.QPainter(img) aa = self.plotwindow.antialias painter.setRenderHint(qt4.QPainter.Antialiasing, aa) painter.setRenderHint(qt4.QPainter.TextAntialiasing, aa) helper.renderToPainter(painter) painter.end() self.mutex.lock() # just throw away result if it older than the latest one if jobid > self.latestdrawnjob: self.emit(qt4.SIGNAL("renderfinished"), jobid, img, helper) self.latestdrawnjob = jobid self.mutex.unlock() # tell any listeners that a job has been processed self.plotwindow.emit(qt4.SIGNAL("queuechange"), -1)
def painter(self, widget, bounds, clip=None): """Return a painter for use when drawing the widget. widget: widget object bounds: tuple (x1, y1, x2, y2) of widget bounds clip: another tuple, if set clips drawing to this rectangle """ s = self.states[widget] = DrawState(widget, bounds, clip, self) if widget.parent is None: self.rootstate = s else: self.states[widget.parent].children.append(s) if self.directpaint: # only paint to one output painter p = self.directpaint if self.directpainting: p.restore() self.directpainting = True p.save() else: # save to multiple recorded layers p = qt4.QPainter(s.record) p.scaling = self.scaling p.pixperpt = self.pixperpt p.pagesize = self.pagesize p.maxsize = max(*self.pagesize) p.dpi = self.dpi[1] if clip: p.setClipRect(clip) return p
class _MmlRenderer(_Renderer): """MathML renderer.""" def _initText(self, text): """Setup MML document and draw it in recording paint device.""" self.error = '' self.size = qt4.QSize(1, 1) if not mmlsupport: self.mmldoc = None self.error = 'Error: MathML support not built\n' return self.mmldoc = doc = qtmml.QtMmlDocument() try: self.mmldoc.setContent(text) except ValueError, e: self.mmldoc = None self.error = ('Error interpreting MathML: %s\n' % unicode(e)) return # this is pretty horrible :-( # We write the mathmml document to a RecordPaintDevice device # at the same DPI as the screen, because the MML code breaks # for other DPIs. We then repaint the output to the real # device, scaling to make the size correct. screendev = qt4.QApplication.desktop() self.record = recordpaint.RecordPaintDevice(1024, 1024, screendev.logicalDpiX(), screendev.logicalDpiY()) rpaint = qt4.QPainter(self.record) # painting code relies on these attributes of the painter rpaint.pixperpt = screendev.logicalDpiY() / 72. rpaint.scaling = 1.0 # Upscale any drawing by this factor, then scale back when # drawing. We have to do this to get consistent output at # different zoom factors (I hate this code). upscale = 5. doc.setFontName(qtmml.QtMmlWidget.NormalFont, self.font.family()) ptsize = self.font.pointSizeF() if ptsize < 0: ptsize = self.font.pixelSize() / self.painter.pixperpt ptsize /= self.painter.scaling doc.setBaseFontPointSize(ptsize * upscale) # the output will be painted finally scaled self.drawscale = (self.painter.scaling * self.painter.dpi / screendev.logicalDpiY() / upscale) self.size = doc.size() * self.drawscale doc.paint(rpaint, qt4.QPoint(0, 0)) rpaint.end()
def exportPIC(self): """Export document as Qt PIC""" pic = qt4.QPicture() painter = qt4.QPainter(pic) dpi = (pic.logicalDpiX(), pic.logicalDpiY()) size = self.doc.pageSize(self.pagenumber, dpi=dpi) self.renderPage(size, dpi, painter) pic.save(self.filename)
def exportEMF(self): """Export document as EMF.""" dpi = 90. size = self.doc.pageSize(self.pagenumber, dpi=(dpi, dpi), integer=False) paintdev = emf_export.EMFPaintDevice(size[0] / dpi, size[1] / dpi, dpi=dpi) painter = qt4.QPainter(paintdev) self.renderPage(size, (dpi, dpi), painter) paintdev.paintEngine().saveFile(self.filename)
def exportSelfTest(self): """Export document for testing""" dpi = svg_export.dpi * 1. size = width, height = self.doc.pageSize(self.pagenumber, dpi=(dpi, dpi), integer=False) f = open(self.filename, 'w') paintdev = selftest_export.SelfTestPaintDevice(f, width / dpi, height / dpi) painter = qt4.QPainter(paintdev) self.renderPage(size, (dpi, dpi), painter) f.close()
def exportSVG(self): """Export document as SVG""" if qt4.PYQT_VERSION >= 0x40600: # custom paint devices don't work in old PyQt versions dpi = svg_export.dpi * 1. size = self.doc.pageSize(self.pagenumber, dpi=(dpi, dpi), integer=False) f = open(self.filename, 'w') paintdev = svg_export.SVGPaintDevice( f, size[0] / dpi, size[1] / dpi, writetextastext=self.svgtextastext) painter = qt4.QPainter(paintdev) self.renderPage(size, (dpi, dpi), painter) f.close() else: # use built-in svg generation, which doesn't work very well # (no clipping, font size problems) import PyQt4.QtSvg dpi = 90. size = self.doc.pageSize(self.pagenumber, dpi=(dpi, dpi), integer=False) # actually paint the image gen = PyQt4.QtSvg.QSvgGenerator() gen.setFileName(self.filename) gen.setResolution(dpi) gen.setSize(qt4.QSize(int(size[0]), int(size[1]))) painter = qt4.QPainter(gen) self.renderPage(size, (dpi, dpi), painter)
def getPreviewPixmap(self, ds): """Get a preview pixmap for a dataset.""" size = (140, 70) if ds.dimensions != 1 or ds.datatype != "numeric": return None pixmap = qt4.QPixmap(*size) pixmap.fill(qt4.Qt.transparent) p = qt4.QPainter(pixmap) p.setRenderHint(qt4.QPainter.Antialiasing) # calculate data points try: if len(ds.data) < size[1]: y = ds.data else: intvl = len(ds.data) / size[1] + 1 y = ds.data[::intvl] x = N.arange(len(y)) # plot data points on image minval, maxval = N.nanmin(y), N.nanmax(y) y = (y - minval) / (maxval - minval) * size[1] finite = N.isfinite(y) x, y = x[finite], y[finite] x = x * (1. / len(x)) * size[0] poly = qt4.QPolygonF() utils.addNumpyToPolygonF(poly, x, size[1] - y) p.setPen(qt4.QPen(qt4.Qt.blue)) p.drawPolyline(poly) # draw x axis if span 0 p.setPen(qt4.QPen(qt4.Qt.black)) if minval <= 0 and maxval > 0: y0 = size[1] - (0 - minval) / (maxval - minval) * size[1] p.drawLine(x[0], y0, x[-1], y0) else: p.drawLine(x[0], size[1], x[-1], size[1]) p.drawLine(x[0], 0, x[0], size[1]) except (ValueError, ZeroDivisionError): # zero sized array after filtering or min == max, so return None p.end() return None p.end() return pixmap
def exportBitmap(self, format): """Export to a bitmap format.""" # get size for bitmap's dpi dpi = self.bitmapdpi size = self.doc.pageSize(self.pagenumber, dpi=(dpi, dpi)) # create real output image backqcolor = utils.extendedColorToQColor(self.backcolor) if format == '.png': # transparent output image = qt4.QImage(size[0], size[1], qt4.QImage.Format_ARGB32_Premultiplied) else: # non transparent output image = qt4.QImage(size[0], size[1], qt4.QImage.Format_RGB32) backqcolor.setAlpha(255) image.setDotsPerMeterX(dpi * m_inch) image.setDotsPerMeterY(dpi * m_inch) if backqcolor.alpha() == 0: image.fill(qt4.qRgba(0, 0, 0, 0)) else: image.fill(backqcolor.rgb()) # paint to the image painter = qt4.QPainter(image) painter.setRenderHint(qt4.QPainter.Antialiasing, self.antialias) painter.setRenderHint(qt4.QPainter.TextAntialiasing, self.antialias) self.renderPage(size, (dpi, dpi), painter) # write image to disk writer = qt4.QImageWriter() # format below takes extension without dot writer.setFormat(qt4.QByteArray(format[1:])) writer.setFileName(self.filename) if format == 'png': # min quality for png as it makes no difference to output # and makes file size smaller writer.setQuality(0) else: writer.setQuality(self.quality) writer.write(image)
def rendernextstate(state): """Recursively draw painter. Checks whether drawing a widgetchanges the small image around the point given. """ pixmap = qt4.QPixmap(origpix) painter = qt4.QPainter(pixmap) painter.setRenderHint(qt4.QPainter.Antialiasing, antialias) painter.setRenderHint(qt4.QPainter.TextAntialiasing, antialias) # this makes the small image draw from x-box->x+box, y-box->y+box # translate would get overriden by coordinate system playback painter.setWindow(x-box,y-box,box*2+1,box*2+1) state.record.play(painter) painter.end() newimg = pixmap.toImage() if newimg != origimg: lastwidget[0] = state.widget for child in state.children: rendernextstate(child)
def makeSplashLogo(): '''Make a splash screen logo.''' border = 16 xw, yw = 520, 240 pix = qt4.QPixmap(xw, yw) pix.fill() p = qt4.QPainter(pix) # draw logo on pixmap logo = utils.getPixmap('logo.png') p.drawPixmap(xw / 2 - logo.width() / 2, border, logo) # add copyright text doc = qt4.QTextDocument() doc.setPageSize(qt4.QSizeF(xw, yw - 3 * border - logo.height())) f = qt4.qApp.font() f.setPointSize(14) doc.setDefaultFont(f) doc.setDefaultTextOption(qt4.QTextOption(qt4.Qt.AlignCenter)) doc.setHtml(splashcopyr % utils.version()) p.translate(0, 2 * border + logo.height()) doc.drawContents(p) p.end() return pix
def printTo(self, printer, pages, scaling=1., dpi=None, antialias=False): """Print onto printing device.""" dpi = (printer.logicalDpiX(), printer.logicalDpiY()) painter = qt4.QPainter(printer) if antialias: painter.setRenderHint(qt4.QPainter.Antialiasing, True) painter.setRenderHint(qt4.QPainter.TextAntialiasing, True) # This all assumes that only pages can go into the root widget num = len(pages) for count, page in enumerate(pages): size = self.pageSize(page, dpi=dpi) helper = painthelper.PaintHelper(size, dpi=dpi, directpaint=painter) self.paintTo(helper, page) painter.restore() # start new pages between each page if count < num - 1: printer.newPage() painter.end()
def exportPS(self, ext): """Export to EPS or PDF format.""" printer = qt4.QPrinter() printer.setFullPage(True) # set printer parameters printer.setColorMode( (qt4.QPrinter.GrayScale, qt4.QPrinter.Color)[self.color]) if ext == '.pdf': fmt = qt4.QPrinter.PdfFormat else: fmt = qt4.QPrinter.PostScriptFormat printer.setOutputFormat(fmt) printer.setOutputFileName(self.filename) printer.setCreator('Veusz %s' % utils.version()) printer.setResolution(self.pdfdpi) # setup for printing printer.newPage() painter = qt4.QPainter(printer) # write to printer with correct dpi dpi = (printer.logicalDpiX(), printer.logicalDpiY()) width, height = size = self.doc.pageSize(self.pagenumber, dpi=dpi) self.renderPage(size, dpi, painter) # fixup eps/pdf file - yuck HACK! - hope qt gets fixed # this makes the bounding box correct # copy output to a temporary file tmpfile = "%s.tmp.%i" % (self.filename, random.randint(0, 1000000)) fout = open(tmpfile, 'wb') fin = open(self.filename, 'rb') if ext == '.eps': # adjust bounding box for line in fin: if line[:14] == '%%BoundingBox:': # replace bounding box line by calculated one parts = line.split() widthfactor = float(parts[3]) / printer.width() origheight = float(parts[4]) line = "%s %i %i %i %i\n" % ( parts[0], 0, int(math.floor(origheight - widthfactor * height)), int(math.ceil( widthfactor * width)), int(math.ceil(origheight))) fout.write(line) elif ext == '.pdf': # change pdf bounding box and correct pdf index text = fin.read() text = utils.scalePDFMediaBox(text, printer.width(), width, height) text = utils.fixupPDFIndices(text) fout.write(text) fout.close() fin.close() os.remove(self.filename) os.rename(tmpfile, self.filename)