Rubyのwin32oleでWordファイルをPDFに一括変換する
WORD→PDF→結合という変換は結構な頻度で定期的に発生する作業だったのですが、 いい加減めんどくさいので自動化します。
Office2007以上であればPDF保存できるので、Win32OLEを使ってやりましょう。
下記エントリがとても参考になりました。
と、単に自動化したいのであれば上記エントリだけで済んでしまうので、ここでは僕がやったことを載せてみます。
やりたいこと
- 指定したWordファイルを全てPDFに変換
- 変換したら一つのPDFに結合
Word → PDF変換
WordはnewしたらQuitしないと開きっぱなしになるので、おっちょこちょいな僕としては怖いところです。 なので、確実にQuitできるようにちょっと細工します。
EAM(Execute Around Method)というのがあるらしいので、それを使いましょう。
※define_finalizerを使う手もありましたが、こっちのほうが面白そうだったので
require "win32ole" class WordUtil def initialize @word_app = WIN32OLE.new("Word.Application") end def quit if @word_app then @word_app.Quit end end def to_pdf(doc_name) doc_fullpath = File.expand_path(doc_name) pdf_fullpath = doc_fullpath.gsub(/\.doc$/, ".pdf") begin doc = @word_app.Documents.Open(doc_fullpath) doc.ExportAsFixedFormat({ "OutputFileName" => pdf_fullpath, "ExportFormat" => 17, # wdExportFormatPDF "OpenAfterExport" => false }) puts "success: #{doc_fullpath}" rescue puts "fail: #{doc_fullpath}" ensure doc.Close unless doc.nil? end end end class WordManager def WordManager.run_during(&block) begin word = WordUtil.new block.call(word) ensure word.quit end end end input_docs = ARGV[0] input_docs = "*.doc" if input_docs.nil? output_pdfs = input_docs.gsub(/\.doc$/, ".pdf") puts "input docs: " + input_docs puts "output pdfs: " + output_pdfs # convert to pdf WordManager.run_during do |word| Dir.glob(input_docs) do |fn| word.to_pdf(fn) end end
WordManagerにブロックを渡して変換してもらっています。 これなら解放漏れしないね!
PDFを結合する
出力したPDFを結合するにはいくつか方法がありそうでしたが、今回は一番簡単そうだったpdftkを呼び出します。
今回やりたいPDFの結合はちょっと注意が必要でして。
- 指定した順番で結合
- ファイル名は毎回一定パターンで変わる
なので、yamlにキーワード並べて、その順番でパターンマッチングして結合、ということをしてます。 なんとめんどくさい。
require "yaml" class PDFCat def initialize(pdf_names, pdf_keys) @sorted_pdf_names = pdf_keys.map do |key| Dir.glob(pdf_names) do |fn| break fn if /#{key}/ =~ fn end end end def concatenate(export_fname) cat_list = @sorted_pdf_names.join(" ") puts "files to be concatenated:\n " + cat_list.split(" ").join("\n ") puts "export file name: #{export_fname}" `"C:/Program Files/PDF Labs/PDFtk Server/bin/pdftk" #{cat_list} cat output #{export_fname}` end end # concatenate pdf files yaml_fname = ENV['HOME'] + "/bin/pdf_keys.yaml" yaml_data = YAML.load_file(yaml_fname) pdfcat = PDFCat.new(output_pdfs, yaml_data['sorted_keyword_list']) export_fname = 'catcatcat.pdf' pdfcat.concatenate(export_fname)
もうちょいリファクタリングできそうですね。
でも疲れたから寝る。