吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 319|回复: 2
收起左侧

[经验求助] word中插入pdf自动转图片

[复制链接]
gaoxiaoao 发表于 2026-5-16 14:18
25吾爱币
本帖最后由 gaoxiaoao 于 2026-5-16 14:22 编辑

一个坛友的留言希望实现功能:在word中插入pdf文档,自动以图片形式展示在文档中。省确了先将pdf转化为图片格式再插入。受此启发问deepseek,形成了如下代码,问题是反复调试一天一夜达不到预期的结果,一直提示png图片未生成。菜鸟一枚,实在没辙,请教大佬们出手相助,修正成正确显示的代码。目前的条件win10系统64位office2019,poppler正确安装功能正常。
[Visual Basic] 纯文本查看 复制代码
Option Explicit

'========================================================
' Word 企业级 PDF → 高清图片 插入系统(最终稳定版)
'
' 功能:
' 1. 多选 PDF
' 2. 当前光标位置插入
' 3. Poppler 真300DPI渲染
' 4. 自动分页
' 5. 图片自动居中
' 6. 自动适应页面
' 7. 保持原始比例
' 8. 支持超大PDF
' 9. 自动等待转换完成
'10. 自动删除缓存
'11. 支持中文路径
'12. Office 32/64位兼容
'13. 超时保护
'14. 防止哈希溢出
'15. 防止空数组崩溃
'
'========================================================

#If VBA7 Then

    Private Declare PtrSafe Function OpenProcess Lib "kernel32" _
        (ByVal dwDesiredAccess As Long, _
         ByVal bInheritHandle As Long, _
         ByVal dwProcessId As Long) As LongPtr

    Private Declare PtrSafe Function GetExitCodeProcess Lib "kernel32" _
        (ByVal hProcess As LongPtr, _
         lpExitCode As Long) As Long

    Private Declare PtrSafe Function CloseHandle Lib "kernel32" _
        (ByVal hObject As LongPtr) As Long

    Private Declare PtrSafe Sub Sleep Lib "kernel32" _
        (ByVal dwMilliseconds As LongPtr)

#Else

    Private Declare Function OpenProcess Lib "kernel32" _
        (ByVal dwDesiredAccess As Long, _
         ByVal bInheritHandle As Long, _
         ByVal dwProcessId As Long) As Long

    Private Declare Function GetExitCodeProcess Lib "kernel32" _
        (ByVal hProcess As Long, _
         lpExitCode As Long) As Long

    Private Declare Function CloseHandle Lib "kernel32" _
        (ByVal hObject As Long) As Long

    Private Declare Sub Sleep Lib "kernel32" _
        (ByVal dwMilliseconds As Long)

#End If

Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const STILL_ACTIVE = &H103

'========================================================
' 主入口
'========================================================
Sub InsertPDF_AsImages_Poppler_Final()

    Dim fd As FileDialog
    Dim pdfFile As Variant

    Dim popplerExe As String
    Dim mainTempFolder As String

    Dim rng As Range
    Dim maxWidth As Single

    Dim totalPages As Long
    Dim startTime As Double

    Dim fso As Object

    '====================================================
    ' 修改为你的真实路径
    '====================================================
    popplerExe = "C:\Poppler\Library\bin\pdftoppm.exe"

    '====================================================
    ' 检查 Poppler
    '====================================================
    If Dir(popplerExe) = "" Then

        MsgBox _
               "未找到 pdftoppm.exe:" & vbCrLf & _
               popplerExe, _
               vbCritical, _
               "缺少 Poppler"

        Exit Sub

    End If

    '====================================================
    ' 初始化
    '====================================================
    Application.ScreenUpdating = False
    Application.DisplayAlerts = wdAlertsNone

    startTime = Timer

    Set rng = Selection.Range
    Set fso = CreateObject("Scripting.FileSystemObject")

    '====================================================
    ' 页面宽度
    '====================================================
    With ActiveDocument.PageSetup

        maxWidth = .PageWidth _
                 - .LeftMargin _
                 - .RightMargin

        If maxWidth <= 0 Then
            maxWidth = .PageWidth * 0.9
        End If

    End With

    '====================================================
    ' 主缓存目录
    '====================================================
    mainTempFolder = _
                     Environ$("TEMP") & _
                     "\WordPDF_Poppler_" & _
                     Format(Now, "yyyymmdd_hhnnss") & "\"
    
    If Not fso.FolderExists(mainTempFolder) Then
        fso.CreateFolder mainTempFolder
    End If
    
    '====================================================
    ' 选择 PDF
    '====================================================
    Set fd = Application.FileDialog(msoFileDialogFilePicker)

    With fd

        .Title = "选择 PDF 文件(可多选)"

        .Filters.Clear
        .Filters.Add "PDF 文件", "*.pdf"

        .AllowMultiSelect = True

        If .Show <> -1 Then GoTo CLEAN_EXIT

    End With

    totalPages = 0

    '====================================================
    ' 遍历 PDF
    '====================================================
    For Each pdfFile In fd.SelectedItems

        totalPages = totalPages + _
            ProcessOnePDF( _
            CStr(pdfFile), _
            popplerExe, _
            mainTempFolder, _
            rng, _
            maxWidth, _
            fso)

    Next

    '====================================================
    ' 完成
    '====================================================
    Application.StatusBar = False

    MsgBox _
        "PDF 插入完成!" & vbCrLf & vbCrLf & _
        "总页数:" & totalPages & vbCrLf & _
        "耗时:" & _
        Format(Timer - startTime, "0.0") & " 秒", _
        vbInformation

CLEAN_EXIT:

    On Error Resume Next

    If fso.FolderExists(mainTempFolder) Then
        fso.DeleteFolder mainTempFolder, True
    End If

    On Error GoTo 0

    Application.ScreenUpdating = True
    Application.DisplayAlerts = wdAlertsAll
    Application.StatusBar = False

End Sub

'========================================================
' 处理单个 PDF
'========================================================
Private Function ProcessOnePDF( _
            pdfPath As String, _
            popplerExe As String, _
            mainTempFolder As String, _
            rng As Range, _
            maxWidth As Single, _
            fso As Object) As Long

    Dim pdfName As String
    Dim subFolder As String
    Dim outputPrefix As String

    Dim cmd As String

    Dim processID As Long
    Dim processHandle As LongPtr
    Dim exitCode As Long

    Dim waitStart As Double

    Dim imgFiles As Variant
    Dim imgCount As Long

    Dim i As Long

    Dim shp As inlineShape

    On Error GoTo ERROR_HANDLER

    '====================================================
    ' PDF名称
    '====================================================
    pdfName = CleanFileName( _
     fso.GetBaseName(pdfPath))
    
    pdfName = pdfName & "_" & _
     GetShortHash(pdfPath)
    '====================================================
    ' 独立子目录
    '====================================================
    subFolder = mainTempFolder & pdfName & "\"

    If Not fso.FolderExists(subFolder) Then
        fso.CreateFolder subFolder
    End If

    '====================================================
    ' 输出前缀
    '====================================================
    outputPrefix = subFolder & pdfName

    '====================================================
    ' 状态栏
    '====================================================
    Application.StatusBar = _
        "正在转换:" & pdfPath

    DoEvents

    '====================================================
    ' Poppler命令
    '====================================================
    cmd = Chr$(34) & popplerExe & Chr$(34) & _
          " -png -r 300 " & _
          Chr$(34) & pdfPath & Chr$(34) & " " & _
          Chr$(34) & outputPrefix & Chr$(34)

    '====================================================
    ' 执行
    '====================================================
MsgBox cmd
processID = Shell(cmd, vbNormalFocus)
    If processID = 0 Then
        Err.Raise 1001, , "Shell 启动失败"
    End If

    processHandle = OpenProcess( _
                    PROCESS_QUERY_INFORMATION, _
                    False, _
                    processID)

    If processHandle = 0 Then
        Err.Raise 1002, , "无法获取进程句柄"
    End If

    '====================================================
    ' 等待转换完成
    '====================================================
    waitStart = Timer

    Do

        GetExitCodeProcess processHandle, exitCode

        DoEvents
        Sleep 200

        If Timer - waitStart > 120 Then

            CloseHandle processHandle

            Err.Raise 1003, , _
                "PDF 转换超时"

        End If

    Loop While exitCode = STILL_ACTIVE

    CloseHandle processHandle

    '====================================================
    ' 获取 PNG
    '====================================================
    imgFiles = CollectImagesByPrefix( _
               subFolder, _
               pdfName)

    '====================================================
    ' 空数组保护
    '====================================================
    If Not IsArray(imgFiles) Then

        Err.Raise 1004, , _
            "未生成 PNG 文件"

    End If

    If UBound(imgFiles) < 0 Then

        Err.Raise 1005, , _
            "PNG 文件为空"

    End If

    imgCount = UBound(imgFiles) + 1

    '====================================================
    ' 插入图片
    '====================================================
    For i = 0 To imgCount - 1

        Application.StatusBar = _
            "插入第 " & _
            (i + 1) & "/" & _
            imgCount & " 页"

        DoEvents

        '------------------------------------------------
        ' 自动分页
        '------------------------------------------------
        If i > 0 Then
            rng.InsertBreak wdPageBreak
        End If

        rng.Collapse wdCollapseEnd

        '------------------------------------------------
        ' 插入图片
        '------------------------------------------------
        Set shp = _
            ActiveDocument.InlineShapes.AddPicture( _
            fileName:=imgFiles(i), _
            LinkToFile:=False, _
            SaveWithDocument:=True, _
            Range:=rng)

        '------------------------------------------------
        ' 保持比例
        '------------------------------------------------
        With shp

            .LockAspectRatio = msoTrue

            If .Width > maxWidth Then
                .Width = maxWidth
            End If

        End With

        '------------------------------------------------
        ' 图片居中
        '------------------------------------------------
        With shp.Range.ParagraphFormat

            .Alignment = wdAlignParagraphCenter
            .SpaceBefore = 0
            .SpaceAfter = 6
            .LineSpacingRule = wdLineSpaceSingle

        End With

        rng.SetRange shp.Range.End, shp.Range.End

    Next

    ProcessOnePDF = imgCount

    Exit Function

ERROR_HANDLER:

    MsgBox _
        "处理 PDF 失败:" & vbCrLf & vbCrLf & _
        pdfPath & vbCrLf & vbCrLf & _
        "错误:" & Err.Description, _
        vbExclamation

    ProcessOnePDF = 0

End Function

'========================================================
' 收集 PNG 文件
'========================================================
Private Function CollectImagesByPrefix( _
    folderPath As String, _
    prefix As String) As Variant

    Dim fso As Object
    Dim fld As Object
    Dim file As Object

    Dim tempList() As String
    Dim count As Long

    Dim i As Long
    Dim j As Long
    Dim tmp As String

    Set fso = CreateObject("Scripting.FileSystemObject")

    If Not fso.FolderExists(folderPath) Then
        Exit Function
    End If

    Set fld = fso.GetFolder(folderPath)

    count = 0

    '====================================================
    ' 收集 PNG
    '====================================================
    For Each file In fld.Files

        If LCase(fso.GetExtensionName(file.Name)) = "png" Then

            If InStr(file.Name, prefix) > 0 Then

                ReDim Preserve tempList(count)

                tempList(count) = file.path

                count = count + 1

            End If

        End If

    Next

    If count = 0 Then
        Exit Function
    End If

    '====================================================
    ' 排序
    '====================================================
    For i = LBound(tempList) To UBound(tempList) - 1

        For j = i + 1 To UBound(tempList)

            If tempList(i) > tempList(j) Then

                tmp = tempList(i)
                tempList(i) = tempList(j)
                tempList(j) = tmp

            End If

        Next

    Next

    CollectImagesByPrefix = tempList

End Function

'========================================================
' 清理非法字符
'========================================================
Private Function CleanFileName( _
    ByVal s As String) As String

    Dim badChars As Variant
    Dim i As Long

    badChars = Array("\", "/", ":", "*", _
                     "?", """", "<", ">", "|")

    For i = LBound(badChars) To UBound(badChars)

        s = Replace$(s, badChars(i), "_")

    Next

    CleanFileName = s

End Function

'========================================================
' 安全短哈希(防溢出)
'========================================================
Private Function GetShortHash( _
            ByVal path As String) As String

    Dim i As Long
    Dim hash As Double

    hash = 0

    For i = 1 To Len(path)

        hash = hash + _
               Asc(Mid$(path, i, 1)) * i

        hash = hash Mod 1000000

    Next

    GetShortHash = _
                   Format$(CLng(hash), "000000")

End Function


发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| gaoxiaoao 发表于 2026-5-17 10:15
已自行解决,求助取消。
zhq628880 发表于 2026-5-17 15:12
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-6-10 07:31

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表