Bakulog

獏の夢日記的な何か。

【IronPython】Excelに点描を打ち込む【エクストリームExcel方眼紙】

WordPressの有名プラグインであるCrayon Syntax Highlighterの表示チェックを兼ねてお遊びプログラムの紹介です。「IronPythonExcelを自動操作する」というプログラムの例示ですが、基本ネタです。

皆さんはExcel方眼紙をご存知でしょうか。そう、ピクセル単位でドキュメントフォーマットを整えるという、人によって好き嫌いが分かれるあの技法です。正直なところ私はExcel方眼紙が嫌いなので、方眼紙としてExcelを使う人々をおちょくるべく、Excelのセルを1ピクセル四方に縮め、画像をもとに点描を打ち込むおバカなプログラムを作りました。1ピクセル単位の方眼紙が欲しいならくれてやる、と。

 

プログラムを動かした動画はこちらです。本記事には絵が出てこないので、絵的な成分が欲しい方はコチラで補充してください。


  で。このプログラムはIronPythonというプログラミング言語で書いたのですが…IronPythonというプログラミング言語を知っている方はどのくらい居るのでしょうか。私もつい半年前くらいまで知らなかった言語ですが、概略としては以下の4点だけ知ってれば十分かと思います。

  このうち重要なのは普通のPython同様コンパイル無しでプログラムが走ってくれることです。この特徴から.NETを軽いノリで使うのに便利です。実際、この点描プログラムは60行くらいしか無いのでIronPythonとの相性は良いです(逆にC#コンパイルすると大げさな印象です)。手前味噌ですがIronPython含めたPythonの導入解説動画も別で上げてるので良かったらコチラもどうぞ。


それで、今回の点描プログラムのコードはこんな感じ。

# -*- encoding: UTF-8 -*-

from random import shuffle
from itertools import product

import clr

clr.AddReference("System.Drawing")
clr.AddReference("Microsoft.VisualBasic")
clr.AddReference("Microsoft.Office.Interop.Excel")

from System.Environment import GetFolderPath, SpecialFolder
from System.IO.Path import Combine

from System.Drawing import Bitmap
from Microsoft.VisualBasic.Information import RGB
from Microsoft.Office.Interop import Excel

imgFile = "hoge.png"
excelFile = "hoge.xlsx"

#読み込む画像ファイルのパス
filenameImg = Combine(GetFolderPath(SpecialFolder.Desktop), imgFile)
#出力するExcelファイルのパス
filenameExl = Combine(GetFolderPath(SpecialFolder.Desktop), excelFile)

#Excelの起動
ex = Excel.ApplicationClass()
ex.Visible = True
ex.DisplayAlerts = False


#ワークブック(ファイル)を生成して保存
wb = ex.Workbooks.Add()
wb.SaveAs(filenameExl)

#シートを生成し、縦横の幅を1ピクセルに調整
sheet = wb.Sheets.Add()
sheet.Name = "dots"
sheet.Select()
#枠線が鬱陶しい(しかも処理重い)ので消去
ex.Windows.Application.ActiveWindow.DisplayGridlines = False
#0.08や0.75はピクセル値への換算に必要な定数
ex.Cells.ColumnWidth = 1 * 0.08
ex.Cells.RowHeight = 1 * 0.75

#画像の全ピクセルを拾いながら背景色として代入
with Bitmap(filenameImg) as bmp:
    width, height = bmp.Width, bmp.Height
    pos = product(range(height), range(width))
    #ここの2行を消すと左上から規則正しく描画される
    pos = list(pos)
    shuffle(pos)
    for y, x in pos:
        pixel = bmp.GetPixel(x, y)
        color = RGB(pixel.R, pixel.G, pixel.B)
        #Excelセル配列は1番目からスタート
        ex.Cells[y + 1, x + 1].Interior.Color = color

wb.Save()

#True指定によって保存終了される
#wb.Close(True)
#Excel自体の終了
#ex.Quit()

読んだら雰囲気は伝わります…よね?やってること自体はExcelの起動、シートの選択、セルのプロパティ(今回なら背景色を表すInterior.Color)への代入という手作業の再現だけです。

IronPythonが初見の方の為に実行方法も書いておくと、上記のコードを丸ごとローカルに"img2excel.py"などという名前で保存し、

  1. ExcelをPCにインストール
  2. IronPythonをインストール
  3. デスクトップに小サイズ(100 x 100くらい)の"hoge.png"という画像ファイルを用意
  4. コマンドプロンプトを起動し、スクリプト(img2excel.py)のディレクトリに移動
  5. "ipy img2excel.py"を実行

とすれば、Excelが起動して点描が打ち込まれるのを見られるはずです。もし5の操作で失敗した場合、環境変数IronPythonのインストール先ディレクト(多分"C:\Program Files (x86)\IronPython 2.7"みたいなパスだと思います)が入ってない可能性があるので確認し、必要そうなら追加して再度試してください。

 

本題からは逸れますが、こんなフザけたプログラムじゃなくて役に立つことでIronPython + Excelの協調処理がしたい人は34行目以降の処理を書き換えることで一般的な自動化処理が出来ます。また最下部がコメントアウトされてますが、プログラムの終了時にExcelが閉じるようにしたければ最下部のコメントアウトを解除し、ワークブックの保存とExcel自体の終了処理を有効化すればOKです。

それと今回のプログラムではビットマップがちんたら転写される様子を視覚的に楽しむために上のようなコードを使っていますが、いちいち変更を反映するとパフォーマンスが落ちます。もし「データ1つずつ書き込んだのを視覚的に反映しないでいいからパフォーマンスを上げたい!」という場合、シートへの書き込み処理の前後でScreenUpdatingプロパティを切り替える事も出来ます。

#...

ex.ScreenUpdating = False
#画像の全ピクセルを拾いながら背景色として代入
with Bitmap(filenameImg) as bmp:
    #...

ex.ScreenUpdating = True
wb.Save()

#...

こう書いておくと、ScreenUpdatingがFalseの間、更新がExcel画面に反映されないため、画面処理に時間がかかっていた場合はコレで処理速度の向上が見込めます。…ってなんだかマジメな解説みたいになって良くないですね。

あくまでネタなので落ちもまとめも無しですが、以上です。ご質問等あればお気軽にどうぞ。