it编程 > 前端脚本 > Python

Python+PyQt6实现将PDF文件转高清图片

2人参与 2026-08-07 Python

一、源码分享

1、源码分享

import sys
from pyqt6.qtcore import qt, qsize, qfileinfo
from pyqt6.qtgui import qimage, qpainter
# 低版本仅能导入这三个,去掉 qpdfdocumentloader
from pyqt6.qtpdf import qpdfdocument, qpdfdocumentrenderoptions
from pyqt6.qtwidgets import qapplication, qmainwindow, qpushbutton, qwidget, qvboxlayout


class mainwindow(qmainwindow):
    def __init__(self, parent=none):
        super().__init__(parent)
        self.setwindowtitle("pdf转高清图片 pyqt6")
        self.resize(400, 120)

        central_widget = qwidget()
        self.setcentralwidget(central_widget)
        layout = qvboxlayout(central_widget)
        self.btn_convert = qpushbutton("执行pdf转图片")
        layout.addwidget(self.btn_convert)
        self.btn_convert.clicked.connect(self.on_pushbutton_clicked)

    def pdftohighresimage(self, pdfpath: str, imgpath: str, size: qsize, dpi: int) -> bool:
        # 关键修复:传入self作为父对象,解决构造参数不足报错
        doc = qpdfdocument(self)

        err = doc.load(pdfpath)
        if err != qpdfdocument.error.none_:
            print(f"load pdf error code: {err}")
            return false

        # 校验自定义尺寸
        if not size.isvalid() or size.width() <= 0 or size.height() <= 0:
            print("input size width or height less zero!")
            return false

        # 拆分路径,自动创建目录
        imagefileinfo = qfileinfo(imgpath)
        suffix = imagefileinfo.suffix().lower()
        imgformat = ""
        quality = -1
        if suffix == "png":
            imgformat = "png"
        elif suffix in ("jpg", "jpeg"):
            imgformat = "jpg"
            quality = 100
        else:
            print("unsupported image extensions, only png / jpg / jpeg are supported!")
            return false

        pageidx = 0
        print(f"page point size: {doc.pagepointsize(pageidx)}")

        opts = qpdfdocumentrenderoptions()
        opts.setrenderflags(qpdfdocumentrenderoptions.renderflag.none_)
        img = doc.render(pageidx, size, opts)

        if img.isnull():
            print(f"page {pageidx + 1} rendering failed!")
            return false

        # 白底画布
        whitebgimg = qimage(size, qimage.format.format_rgb32)
        whitebgimg.fill(qt.globalcolor.white)

        painter = qpainter(whitebgimg)
        painter.setrenderhints(qpainter.renderhint.antialiasing | qpainter.renderhint.textantialiasing)
        painter.drawimage(0, 0, img)
        painter.end()

        img = whitebgimg

        # dpi 设置
        dotspermeter = round(dpi / 25.4 * 1000)
        img.setdotspermeterx(dotspermeter)
        img.setdotspermetery(dotspermeter)

        if imgformat == "png":
            img.settext("dpi", str(dpi))

        saveok = false
        if quality > 0:
            saveok = img.save(imgpath, imgformat, quality)
        else:
            saveok = img.save(imgpath, imgformat)

        if not saveok:
            print(f"failed to save the image: {imgpath}")
        else:
            print(f"success to save the image: {imgpath}")

        return saveok

    def on_pushbutton_clicked(self):
        self.pdftohighresimage("l000137362.pdf", "l000137362.jpg", qsize(896, 1534), 300)
        self.pdftohighresimage("l000137362.pdf", "l000137362.png", qsize(896, 1534), 300)


if __name__ == "__main__":
    app = qapplication(sys.argv)
    win = mainwindow()
    win.show()
    sys.exit(app.exec())

2、效果展示

二、pyqt pdf模块详解

pyqt6 的 pdf 模块提供了强大的 pdf 文档处理能力,主要包含在 qtpdf 模块中。该模块允许开发者加载、渲染、查看和操作 pdf 文档,是构建 pdf 阅读器、转换工具或文档处理应用的理想选择。

1、核心类介绍

qpdfdocument

qpdfdocument 是 pdf 模块的核心类,负责加载和管理 pdf 文档。它提供了以下关键功能:

qpdfdocumentrenderoptions

qpdfdocumentrenderoptions 控制 pdf 页面的渲染行为,可以设置:

qpdfpagenavigator

qpdfpagenavigator 提供页面导航功能,支持:

qpdfselection

qpdfselection 表示 pdf 页面上的文本选择,可以:

2、基本使用流程

加载 pdf 文档

from pyqt6.qtpdf import qpdfdocument

# 创建文档对象(需要传入父对象)
doc = qpdfdocument(parent=self)

# 加载 pdf 文件
error = doc.load("example.pdf")

# 检查加载结果
if error != qpdfdocument.error.none_:
    print(f"加载失败,错误代码: {error}")
else:
    print(f"pdf 加载成功,共 {doc.pagecount()} 页")

获取页面信息

# 获取页面数量
page_count = doc.pagecount()

# 获取第一页的尺寸(以点为单位,1点=1/72英寸)
page_size = doc.pagepointsize(0)  # qsizef 对象
print(f"页面尺寸: {page_size.width()} x {page_size.height()} 点")

# 转换为像素(假设 dpi=72)
dpi = 72
width_px = page_size.width() * dpi / 72
height_px = page_size.height() * dpi / 72

渲染页面为图像

from pyqt6.qtpdf import qpdfdocumentrenderoptions
from pyqt6.qtgui import qimage

# 创建渲染选项
opts = qpdfdocumentrenderoptions()
opts.setrenderflags(qpdfdocumentrenderoptions.renderflag.none_)

# 设置目标尺寸(以像素为单位)
target_size = qsize(800, 600)

# 渲染第一页
image = doc.render(0, target_size, opts)

if not image.isnull():
    print(f"渲染成功,图像尺寸: {image.width()} x {image.height()}")
    # 保存图像
    image.save("page_0.png", "png")
else:
    print("渲染失败")

提取页面文本

# 创建页面对象(需要 qpdfpagemodel 配合)
# 注意:文本提取功能相对有限,复杂布局可能无法正确提取
from pyqt6.qtpdf import qpdfpagemodel

page_model = qpdfpagemodel(doc)
if page_model.pagecount() > 0:
    # 获取页面文本(简化示例,实际使用更复杂)
    text = page_model.text(0)
    print(f"页面文本: {text[:100]}...")  # 显示前100个字符

3、高级功能

自定义渲染选项

opts = qpdfdocumentrenderoptions()

# 设置裁剪区域(渲染页面的一部分)
from pyqt6.qtcore import qrectf
crop_rect = qrectf(50, 50, 200, 300)  # 左上角(50,50),宽200,高300
opts.setcroprect(crop_rect)

# 设置缩放
opts.setscalefactor(2.0)  # 放大2倍

# 设置渲染标志
from pyqt6.qtpdf import qpdfdocumentrenderoptions
flags = (qpdfdocumentrenderoptions.renderflag.antialiasing | 
         qpdfdocumentrenderoptions.renderflag.textantialiasing)
opts.setrenderflags(flags)

处理多页文档

def render_all_pages(doc, output_dir="output"):
    import os
    os.makedirs(output_dir, exist_ok=true)
    
    for page_index in range(doc.pagecount()):
        # 获取原始页面尺寸
        page_size = doc.pagepointsize(page_index)
        
        # 转换为像素(300 dpi)
        dpi = 300
        width = int(page_size.width() * dpi / 72)
        height = int(page_size.height() * dpi / 72)
        target_size = qsize(width, height)
        
        # 渲染
        opts = qpdfdocumentrenderoptions()
        image = doc.render(page_index, target_size, opts)
        
        if not image.isnull():
            # 保存为png
            filename = os.path.join(output_dir, f"page_{page_index:03d}.png")
            image.save(filename, "png")
            print(f"已保存: {filename}")
        else:
            print(f"页面 {page_index} 渲染失败")

错误处理

from pyqt6.qtpdf import qpdfdocument

class pdfprocessor:
    def __init__(self):
        self.document = qpdfdocument()
    
    def load_pdf(self, filepath):
        error = self.document.load(filepath)
        
        error_messages = {
            qpdfdocument.error.none_: "成功",
            qpdfdocument.error.filenotfounderror: "文件未找到",
            qpdfdocument.error.invalidfileformaterror: "无效的文件格式",
            qpdfdocument.error.incorrectpassworderror: "密码错误",
            qpdfdocument.error.unsupportedsecurityschemeerror: "不支持的加密方案",
            qpdfdocument.error.documentlockederror: "文档被锁定",
            qpdfdocument.error.unknownerror: "未知错误"
        }
        
        if error in error_messages:
            return error_messages[error]
        else:
            return f"未知错误代码: {error}"

4、性能优化建议

异步渲染

对于大型pdf文档,建议在后台线程中进行渲染操作:

from pyqt6.qtcore import qthread, pyqtsignal

class renderthread(qthread):
    finished = pyqtsignal(qimage, int)  # 图像和页码
    
    def __init__(self, doc, page_index, size):
        super().__init__()
        self.doc = doc
        self.page_index = page_index
        self.size = size
    
    def run(self):
        opts = qpdfdocumentrenderoptions()
        image = self.doc.render(self.page_index, self.size, opts)
        self.finished.emit(image, self.page_index)

缓存已渲染页面

对于pdf查看器应用,实现页面缓存可以显著提升性能:

class pdfviewercache:
    def __init__(self, max_cache_size=10):
        self.cache = {}  # page_index -> qimage
        self.max_size = max_cache_size
        self.access_order = []  # 最近访问顺序
    
    def get_page(self, page_index, doc, size):
        if page_index in self.cache:
            # 更新访问顺序
            self.access_order.remove(page_index)
            self.access_order.append(page_index)
            return self.cache[page_index]
        
        # 渲染新页面
        opts = qpdfdocumentrenderoptions()
        image = doc.render(page_index, size, opts)
        
        # 添加到缓存
        self.cache[page_index] = image
        self.access_order.append(page_index)
        
        # 清理旧缓存
        if len(self.cache) > self.max_size:
            oldest = self.access_order.pop(0)
            del self.cache[oldest]
        
        return image

渐进式渲染

对于高分辨率渲染,可以考虑渐进式加载:

def progressive_render(doc, page_index, final_size, steps=3):
    """渐进式渲染:从低分辨率开始,逐步提高"""
    images = []
    
    for step in range(1, steps + 1):
        # 逐步增加尺寸
        scale = step / steps
        current_size = qsize(
            int(final_size.width() * scale),
            int(final_size.height() * scale)
        )
        
        opts = qpdfdocumentrenderoptions()
        image = doc.render(page_index, current_size, opts)
        images.append(image)
    
    return images  # 返回不同分辨率的图像序列

5、常见问题与解决方案

内存泄漏问题

qpdfdocument 需要正确管理生命周期:

# 正确做法:设置父对象,自动管理内存
class pdfwidget(qwidget):
    def __init__(self):
        super().__init__()
        self.doc = qpdfdocument(self)  # 设置父对象
        
    def load_pdf(self, path):
        self.doc.load(path)
        
    # 析构时自动释放

中文显示问题

确保系统字体包含中文字符集,或指定字体:

from pyqt6.qtgui import qfont, qfontdatabase

# 加载中文字体
font_id = qfontdatabase.addapplicationfont("path/to/chinese_font.ttf")
if font_id != -1:
    font_families = qfontdatabase.applicationfontfamilies(font_id)
    if font_families:
        chinese_font = qfont(font_families[0])
        # 应用到渲染上下文

加密pdf处理

处理加密pdf需要密码:

def load_encrypted_pdf(filepath, password):
    doc = qpdfdocument()
    
    # 先尝试无密码加载
    error = doc.load(filepath)
    
    if error == qpdfdocument.error.incorrectpassworderror:
        # 使用密码重试
        # 注意:pyqt6的qpdfdocument目前没有直接的密码接口
        # 可能需要通过其他方式处理加密pdf
        print("需要密码解密")
        return none
    
    return doc

6、实际应用示例

简单的pdf查看器

from pyqt6.qtwidgets import (qapplication, qmainwindow, qwidget, 
                             qvboxlayout, qlabel, qscrollarea)
from pyqt6.qtpdf import qpdfdocument
from pyqt6.qtgui import qpixmap

class simplepdfviewer(qmainwindow):
    def __init__(self):
        super().__init__()
        self.setwindowtitle("pdf查看器")
        self.resize(800, 600)
        
        self.doc = qpdfdocument(self)
        self.current_page = 0
        
        # 创建界面
        central = qwidget()
        self.setcentralwidget(central)
        layout = qvboxlayout(central)
        
        self.image_label = qlabel()
        self.image_label.setalignment(qt.alignmentflag.aligncenter)
        
        scroll = qscrollarea()
        scroll.setwidget(self.image_label)
        scroll.setwidgetresizable(true)
        layout.addwidget(scroll)
        
        # 加载pdf
        self.load_pdf("document.pdf")
    
    def load_pdf(self, filepath):
        error = self.doc.load(filepath)
        if error == qpdfdocument.error.none_:
            self.show_page(0)
    
    def show_page(self, page_index):
        if 0 <= page_index < self.doc.pagecount():
            self.current_page = page_index
            
            # 渲染页面
            page_size = self.doc.pagepointsize(page_index)
            target_size = qsize(
                int(page_size.width() * 2),  # 放大显示
                int(page_size.height() * 2)
            )
            
            opts = qpdfdocumentrenderoptions()
            image = self.doc.render(page_index, target_size, opts)
            
            if not image.isnull():
                pixmap = qpixmap.fromimage(image)
                self.image_label.setpixmap(pixmap)
                self.setwindowtitle(f"pdf查看器 - 第 {page_index + 1} 页")

pdf转图片工具

class pdftoimageconverter:
    def __init__(self, dpi=300, output_format="png"):
        self.dpi = dpi
        self.output_format = output_format.upper()
    
    def convert(self, pdf_path, output_dir):
        import os
        from pyqt6.qtpdf import qpdfdocument
        
        doc = qpdfdocument()
        if doc.load(pdf_path) != qpdfdocument.error.none_:
            return false
        
        os.makedirs(output_dir, exist_ok=true)
        
        for i in range(doc.pagecount()):
            page_size = doc.pagepointsize(i)
            
            # 计算像素尺寸
            width = int(page_size.width() * self.dpi / 72)
            height = int(page_size.height() * self.dpi / 72)
            
            # 渲染
            opts = qpdfdocumentrenderoptions()
            image = doc.render(i, qsize(width, height), opts)
            
            if not image.isnull():
                # 保存
                filename = os.path.join(
                    output_dir, 
                    f"page_{i:03d}.{self.output_format.lower()}"
                )
                
                if self.output_format == "jpg":
                    image.save(filename, "jpeg", 95)  # 95%质量
                else:
                    image.save(filename, self.output_format)
        
        return true

三、总结

pyqt6 的 pdf 模块提供了完整的 pdf 处理能力,从简单的文档加载和渲染到高级的文本提取和页面导航。关键点总结:

  1. 核心类qpdfdocument 是基础,qpdfdocumentrenderoptions 控制渲染
  2. 基本流程:加载 → 获取信息 → 渲染 → 保存/显示
  3. 性能考虑:使用缓存、异步渲染和渐进式加载优化体验
  4. 错误处理:正确处理各种加载和渲染错误
  5. 实际应用:可以构建查看器、转换工具、文档处理应用等

以上就是python+pyqt6实现将pdf文件转高清图片的详细内容,更多关于pyqt pdf转图片的资料请关注代码网其它相关文章!

(0)

您想发表意见!!点此发布评论

推荐阅读

Python+PyQt6实现跨平台串口设备热插拔检测

08-07

Python基础入门之模块搜索路径sys.path用法详解

08-07

Python difflib库实现文本差异比较与合并实战指南

08-07

Python结合PyQt6实现屏幕截图工具(附源码)

08-07

python time包精讲及异常处理

08-07

一文详解Python文件操作与路径处理

08-07

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论