Monday, October 19, 2015 / PDF, Swift

PDFをページごとにPNG画像に変換( swift 編 )

PDFをページごとにPNG画像に変換してみた話。 Swift で実装。

複数のPNG画像からPDFを生成する の逆の処理。 このエントリーで生成した concat-png.pdf からページごとにPNGデータを生成する。

pdf-to-png

swiftc によりコマンドラインからビルドできるのはありがたい。

Xcode 7.0.1 環境で... hello.swift ファイルに

print("hello")

と書いて

$ swiftc -o hello hello.swift

とすれば実行ファイルを生成できる。

extractPng.swift

import Foundation
import CoreFoundation
import CoreImage

let path = NSProcessInfo.processInfo().arguments[1]
let url:NSURL  = NSURL(fileURLWithPath: path) as CFURLRef
let pdfDocument = CGPDFDocumentCreateWithURL(url) // CGPDFDocument

//
// save each page into png file.
//

let pageCount = CGPDFDocumentGetNumberOfPages(pdfDocument)
for index in 1...pageCount {

	let page = CGPDFDocumentGetPage(pdfDocument, index) // CGPDFPage

	let colorSpace = CGColorSpaceCreateDeviceRGB() // CGColorSpace
	let bitmapInfo = CGImageAlphaInfo.PremultipliedFirst
	
	let mediaBoxRect = CGPDFPageGetBoxRect(page, CGPDFBox.MediaBox) // CGRect
	let w = Int( mediaBoxRect.size.width )
	let h = Int( mediaBoxRect.size.height )
	
	let context = CGBitmapContextCreate(
		nil,
		w, h, 8, 0, colorSpace, bitmapInfo.rawValue)
	
	CGContextDrawPDFPage(context, page)
	
	let image = CGBitmapContextCreateImage(context) //CGImageRef
	let dataProvider = CGImageGetDataProvider( image ) // CGDataProviderRef
	let data = CGDataProviderCopyData(dataProvider)
	let imageType = kUTTypePNG

	let savePngFilename = "page-" + String(index) + ".png"
	let savePngFileUrl:NSURL  = NSURL(fileURLWithPath: savePngFilename) as CFURLRef

	let file = CGImageDestinationCreateWithURL( savePngFileUrl, imageType, 1, nil ) 
	print( file ) // CGImageDestination
	
	let options: [NSString:AnyObject] = [
		kCGImagePropertyOrientation : 1,
		kCGImagePropertyHasAlpha : true,
		kCGImageDestinationLossyCompressionQuality : 0.80]
	
	CGImageDestinationAddImage(file!, image!, options)
	CGImageDestinationFinalize(file!)
}

実行

swiftc -o extractPng extractPng.swift
./extractPng input.pdf

Groovyと比べて速い。ビルドと実行が一瞬。 Core Graphics のAPIに精通していく必要があるがPDF操作関連は Groovy + PDFBox などで処理するよりよいかもしれない。 Swift2 が Linux でも作動するようになればなお良い。 そのとき Core Graphics などの関連ライブラリも移植されるのだろうか…