pywin32로 시작하는 파포에 연속 이미지 삽입

이런 느낌이 됩니다↓



Windows에서 사용한다고 가정하고 다음 powershell cmdlet에서 .py 파일을 호출하여 실행합니다. cmdlet 이름이 하면 길지만 보완이 효과가 있기 때문에 문제는 없다…

부팅 중인 Office 제품의 작업에는 더 직접적인 방법도 있지만, powershell 6 이상에서는 [System.Runtime.InteropServices.Marshal]::GetActiveObject()를 사용할 수 없으므로 pywin32로 대체하고 있습니다.
function Add-Image2ActivePptSlideWithPython {
    <#
        .SYNOPSIS
        pywin32 を利用して現在開いているパワポのスライドに画像を連続挿入する
    #>
    if ((Get-Process | Where-Object ProcessName -EQ "POWERPNT").Count -lt 1) {
        return
    }
    $targetPath = @($input).Fullname
    if (-not $targetPath) {
        return
    }

    if ((Read-Host "「ファイル内のイメージを圧縮しない」の設定はオンになっていますか? (y/n)") -ne "y") {
        return
    }

    $tmp = New-TemporaryFile
    $targetPath | Out-File -Encoding utf8 -FilePath $tmp.FullName # BOMつき

    # このスクリプトと同じディレクトリに後述の python スクリプトを配置しておく
    $pyCodePath = "{0}\activeppt_insert-image.py" -f $PSScriptRoot
    'python -B "{0}" "{1}"' -f $pyCodePath, $tmp.FullName | Invoke-Expression
    Remove-Item -Path $tmp.FullName
}

첫번째 쪽에서는 이미지 압축 사용 안함 되어 있는지 확인하고 있습니다(이것을 잊으면 삽입된 이미지의 해상도가 떨어지기 때문에).

실제의 커멘드 라인상에서는 아래와 같이 파이프 라인 경유로 삽입하고 싶은 이미지 오브젝트를 건네주고 합니다.
ls -File | Add-Image2ActivePptSlideWithPython

파이프라인을 통해 건네받은 이미지의 패스를 인수로서 건네주는 방법도 있습니다만, 그것이라면 특수 문자의 이스케이프나 인수의 상한등이 귀찮기 때문에 New-TemporaryFile 그리고 작성한 임시 파일에 써내고 있습니다.
이 때, powershell 의 사양에 의해 UTF8 를 지정해도 BOM 첨부가 되므로 문자 코드에는 주의가 필요.

호출하는 python 파일은 다음과 같이 합니다. 파워포를 시작한 상태에서 실행하면 ActivePresentation 로 기동중의 프로세스를 포착할 수 있습니다.
미리 호출자가 PowerPoint를 시작했는지 확인했지만 여전히 프레젠테이션이 열려 있지 않은 경우 아무 작업도 수행하지 않습니다. 또, 불가시의 좀비 프로세스를 잡아 버렸을 때는 프로세스 자체를 종료시킵니다.

activeppt_insert-image.py
"""
pywin32 を使用して現在開いている PowerPoint スライドに画像を連続を挿入する
"""
import win32com.client
import argparse

class vb:
    msoFalse        = 0
    msoTrue         = -1
    ppLayoutBlank   = 12

def main(file_list_path):
    pptApp = win32com.client.Dispatch("PowerPoint.Application")
    if pptApp.Presentations.Count < 1:
        if not pptApp.Visible:
            pptApp.Quit()
        return

    with open(file_list_path, "r", encoding="utf_8_sig") as f:
        all_lines = f.read()
    image_path_list = all_lines.splitlines()

    presen = pptApp.ActivePresentation
    slide_width = presen.PageSetup.SlideWidth
    slide_height = presen.PageSetup.SlideHeight

    for img_path in image_path_list:
        slide_index = presen.Slides.Count + 1
        presen.Slides.Add(slide_index, vb.ppLayoutBlank)
        last_slide = presen.Slides(slide_index)
        inserted_img = last_slide.Shapes.AddPicture(
            FileName = img_path,
            LinkToFile = vb.msoFalse,
            SaveWithDocument = vb.msoTrue,
            Left = 0,
            Top = 0
            )
        inserted_img.Left = (slide_width - inserted_img.Width) / 2
        inserted_img.Top = (slide_height - inserted_img.Height) / 2
        print(f"inserted: {img_path}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument("file_list_path")
    args = parser.parse_args()
    main(args.file_list_path)

마지막으로



(´-`).

좋은 웹페이지 즐겨찾기