LoginSignup
2
0

More than 3 years have passed since last update.

[ネタ]Excel方眼紙の上に好きな画像を正方形にペイントするツールをGoで作ってみた

Last updated at Posted at 2020-03-05

概要

日本の文化圏にいれば、どこかで「Excel方眼紙」に出会うことがあるでしょう。
このエントリでは、Excel方眼紙にお気に入りの絵をペイントして眺めてみるツールを作ってみました。

lenna_rendered.png
図:コンピュータで画像系のサンプルでよく使われる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のフォーマットが読み込めるプログラムで、心ゆくまでご鑑賞ください。

コード

大まかな流れは、下記のとおりです。

  1. 元画像ファイルを読み込む
  2. 元画像を正方形に切り取る(短い方の辺の長さで、中心によせて)
  3. さらにリサイズする(256x256に)
  4. 色が多すぎると大変なので、色の数を限るため、パレットを作る
  5. 変換された画像をもとに、Worksheetのセルを塗りつぶす
  6. ブックのファイルを書きだす

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」はお好きな形に編集できます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0