概要
日本の文化圏にいれば、どこかで「Excel方眼紙」に出会うことがあるでしょう。
このエントリでは、Excel方眼紙にお気に入りの絵をペイントして眺めてみるツールを作ってみました。
![]() |
---|
図:コンピュータで画像系のサンプルでよく使われるLenna様をペイント |
TL;DR;
リポジトリはこちらhttps://github.com/hrkt/xlspaintです。
ご自身でビルドするか、リリースのページから実行形式xlspaint.exeとテンプレのtemplate_256x256.xlsxを取得して、ペイントしたい画像を同じディレクトリに置き、下記のように実行します。
xlspaint 方眼紙に描きたいファイル名
実行例:
>xlspaint.exe sampledata\Lenna_512x512.png
format:png
512
2020/03/06 06:21:19 start redering
................................................................................................................................................................................................................................................................
2020/03/06 06:21:19 redering done.
成功すると、「元のファイル名」に拡張し「.xlsx」がついているファイルが出来上がります。
Excelのフォーマットが読み込めるプログラムで、心ゆくまでご鑑賞ください。
コード
大まかな流れは、下記のとおりです。
- 元画像ファイルを読み込む
- 元画像を正方形に切り取る(短い方の辺の長さで、中心によせて)
- さらにリサイズする(256x256に)
- 色が多すぎると大変なので、色の数を限るため、パレットを作る
- 変換された画像をもとに、Worksheetのセルを塗りつぶす
- ブックのファイルを書きだす
package main
import (
"flag"
"fmt"
"image"
"image/color"
"log"
"path/filepath"
_ "image/gif"
_ "image/jpeg"
_ "image/png"
"os"
"github.com/nfnt/resize"
"github.com/oliamb/cutter"
"github.com/soniakeys/quant/median"
"github.com/tealeg/xlsx"
)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
flag.Parse()
if 0 == len(flag.Args()) {
fmt.Println("Usage: xlspaint [imagefilename]")
os.Exit(1)
}
imgFilename := flag.Args()[0]
imgFile, _ := os.Open(imgFilename)
defer imgFile.Close()
srcImg, fmtName, err := image.Decode(imgFile)
if err != nil {
log.Fatal(err)
}
fmt.Println("format:" + fmtName)
length := min(srcImg.Bounds().Max.X, srcImg.Bounds().Max.Y)
fmt.Println(length)
// crop
croppedImg, err := cutter.Crop(srcImg, cutter.Config{
Width: length,
Height: length,
Mode: cutter.Centered,
})
//resize
resizedImg := resize.Resize(256, 0, croppedImg, resize.Lanczos3)
//make palette
p := median.Quantizer(256).Quantize(make(color.Palette, 0, 256), srcImg)
palletedImg := image.NewPaletted(srcImg.Bounds(), p)
for y := resizedImg.Bounds().Min.Y; y < resizedImg.Bounds().Max.Y; y++ {
for x := resizedImg.Bounds().Min.X; x < resizedImg.Bounds().Max.X; x++ {
palletedImg.Set(x, y, resizedImg.At(x, y))
}
}
excelFileName := "template_256x256.xlsx"
xlFile, err := xlsx.OpenFile(excelFileName)
if err != nil {
os.Exit(1)
}
sheet := xlFile.Sheets[0]
log.Println("start redering")
//read pixels from image and paint cells
for row := 0; row < 256; row++ {
fmt.Print(".")
for col := 0; col < 256; col++ {
style := xlsx.NewStyle()
r, g, b, _ := palletedImg.At(col, row).RGBA()
colorStr := fmt.Sprintf("FF%02x%02x%02x", r>>8, g>>8, b>>8)
style.Fill = *xlsx.NewFill("solid", colorStr, colorStr)
cell := sheet.Rows[row].Cells[col]
cell.SetStyle(style)
}
}
fmt.Println("")
log.Println("redering done.")
err = xlFile.Save(filepath.Base(imgFilename) + ".xlsx")
if err != nil {
fmt.Printf(err.Error())
}
os.Exit(0)
}
おわりに
ふと思い立ったのでやり始めたら、(Golangはあまり得意ではないのですが)あれこれ調べながら3時間くらいで書けました。
補足
テンプレの「template_256x256.xlsx」はお好きな形に編集できます。