PySide6中QPdfView渲染至QPrintPreviewDialog效率优化求助
优化QPdfView打印预览效率:直接渲染而非转图片
我是QT/PySide6新手,编写了继承QPdfView的Viewer类实现打印预览功能,但当前方案通过将每页PDF渲染为图片再打印,速度极慢且效率低下,希望能直接将QPdfView的内容渲染至打印机。原实现代码如下:
class Viewer(QPdfView): def __init__(self, parent: QWidget | None = None): super().__init__(parent) self.setPageMode(QPdfView.PageMode.MultiPage) self.setVisible(False) def print_(self): printer = QPrinter(QPrinter.PrinterMode.HighResolution) dialog = QPrintPreviewDialog(printer, self.parent()) dialog.paintRequested.connect(self.draw) dialog.exec() def draw(self, printer: QPrinter): painter = QPainter(printer) painter.setRenderHints( QPainter.RenderHint.Antialiasing | QPainter.RenderHint.TextAntialiasing | QPainter.RenderHint.SmoothPixmapTransform | QPainter.RenderHint.LosslessImageRendering, True ) document = self.document() options = QPdfDocumentRenderOptions() options.setRenderFlags( QPdfDocumentRenderOptions.RenderFlag.ImageAliased | QPdfDocumentRenderOptions.RenderFlag.TextAliased | QPdfDocumentRenderOptions.RenderFlag.ForceHalftone ) print_range = printer.pageRanges() rng = print_range.toString().split("-") rng = [i.strip() for i in rng if i.strip().isdigit()] if len(rng) == 2: range_ = range(int(rng[0]) - 1, int(rng[1])) elif len(rng) == 1: range_ = tuple([int(rng[0]) - 1]) else: range_ = range(document.pageCount()) if max(range_) > document.pageCount(): range_ = range(document.pageCount()) layout = printer.pageLayout() if layout.orientation() == QPageLayout.Orientation.Landscape: printer.setPageOrientation(QPageLayout.Orientation.Landscape) if layout.pageSize().isValid(): printer.setPageSize(layout.pageSize()) for i in range_: if i > 0: printer.newPage() printer.setPageMargins(layout.margins()) target_rect = printer.pageRect(QPrinter.DevicePixel) image_size = QSize(int(target_rect.width()), int(target_rect.height())) image = document.render(i, image_size, options) if not image.isNull(): painter.drawImage(target_rect, image) painter.end()
优化方案:直接渲染到打印机Painter
不需要先将页面渲染为图片,直接调用QPdfDocument.renderToPainter()方法将PDF页面直接绘制到打印机的QPainter上,这会大幅提升打印效率,同时保留矢量内容的清晰度。
修改后的draw方法如下:
def draw(self, printer: QPrinter): painter = QPainter(printer) # 保留必要的渲染提示 painter.setRenderHints( QPainter.RenderHint.Antialiasing | QPainter.RenderHint.TextAntialiasing | QPainter.RenderHint.SmoothPixmapTransform, True ) document = self.document() if not document: painter.end() return options = QPdfDocumentRenderOptions() # 调整渲染标志,移除不必要的强制半色调等设置,保留矢量渲染优势 options.setRenderFlags( QPdfDocumentRenderOptions.RenderFlag.Annotations | QPdfDocumentRenderOptions.RenderFlag.Selection ) # 处理打印范围逻辑保留不变 print_range = printer.pageRanges() rng = print_range.toString().split("-") rng = [i.strip() for i in rng if i.strip().isdigit()] if len(rng) == 2: start = int(rng[0]) - 1 end = int(rng[1]) range_ = range(start, end) if start < end else [start] elif len(rng) == 1: range_ = [int(rng[0]) - 1] else: range_ = range(document.pageCount()) # 修正范围超出的情况 max_page = document.pageCount() - 1 range_ = [page for page in range_ if 0 <= page <= max_page] if not range_: painter.end() return layout = printer.pageLayout() # 应用页面设置 printer.setPageOrientation(layout.orientation()) printer.setPageSize(layout.pageSize()) printer.setPageMargins(layout.margins()) for idx, page_num in enumerate(range_): if idx > 0: printer.newPage() # 获取打印机的页面矩形(使用DevicePixel确保精度) target_rect = printer.pageRect(QPrinter.DevicePixel) # 直接将PDF页面渲染到painter document.renderToPainter(page_num, painter, target_rect, options) painter.end()
关键优化点:
- 替换
document.render()生成图片的逻辑为document.renderToPainter(),直接将PDF内容矢量渲染到打印机的画布,避免图片转换的开销。 - 调整渲染标志,移除原代码中会强制位图化的
ImageAliased、TextAliased、ForceHalftone,保留矢量内容的清晰度和渲染效率。 - 优化了打印范围的边界检查逻辑,避免索引越界。
内容的提问来源于stack exchange,提问作者Clueless
相关产品推荐
相关产品推荐

