LoginSignup
9
9

More than 5 years have passed since last update.

Swift Package Managerで画像を作成する

Last updated at Posted at 2018-05-24

先日書いたXCTestのUIテストの結果をイイ感じで見たいという記事ではXCTestで撮影したスクリーンショットをHTMLにまとて表示する様にしてみました。
ただ、HTMLではチームのメンバーにそのまま共有するのは大変だったので、画像かPDF化してみたいなと考えていました。
今回はSwift Package Manager上で画像を作成する事で、生成した画像を手軽にチームメンバーに共有出来る様にしてみました。


本題

普段iOSやmacOSのアプリを書いていると画像生成はCore Graphic等を利用して簡単に画像を作成する事が出来ますね。ただ、Swift Package ManagerなどのPure Swiftな環境では簡単な画像すら作成する環境が整っていません。簡単な画像合成プログラムをPure Swiftな環境で書いてみたので共有したいと思います。


前提

  • macOS High Sierra
  • Xcode 9.3

検討したツール

今回検討したツールはImagemagickGD Graphics Libraryです。最初に使おうと思ったのがImagemagickです。サーバーで画像生成するには最近では定番の画像作成ツールですね。但し、今回は利用しませんでした。 理由としては誰でもインストール出来るCLIツールを作りたかったのですが、インストールだけでかなりの時間を取られてしまった為です。


今回は GD を利用

次に検討したのがGDと呼ばれるPHPではお馴染みの昔からある画像生成ライブラリです。こちらはインストールが比較的さくっと出来たので今回はこちらを利用する事にしました。


何故AppKit使わないのか

GDならLinuxからでも利用出来る為今回はAppKitを利用しませんでした。将来的に利用シーンを広げる事を視野に入れるとLinuxで利用出来る事は価値があるかなと思います。


GDのインストール

brew install gd

最初にGDをインストールします。GDはHomebrewでインストール可能です。


SwiftからC言語のライブラリを利用する

これで画像を生成する準備ができました。次にSwiftからC言語のライブラリを利用出来る様にしましょう。


module.modulemap を作成

mkdir ./GD && cd $_
touch module.modulemap

今回作成するプロジェクトと並列の階層にGDという名前のディレクトリを作成して、module.modulemapファイルを作成します。


module.modulemap 内容

module GD [system] {
    header "/usr/local/include/gd.h"
    header "/usr/local/include/gdfontt.h"
    header "/usr/local/include/gdfonts.h"
    header "/usr/local/include/gdfontl.h"
    header "/usr/local/include/gdfontg.h"
    header "/usr/local/include/gdfontmb.h"
    link "gd"
    export *
}

module.mobulemapの内容はこんな感じです。名前の定義とヘッダーファイルへのパスを示します。


同じ階層に Package.swift を作成

import PackageDescription

let package = Package(
    name: "GD",
    pkgConfig: "gdlib",
    providers: [
        .brew(["gd"])
    ]
)

module.modulemapファイルと同じ階層にPackage.swiftファイルを作成します。Homebrew経由のGDを利用する様な記述がある事が分かります。


Gitでタグ付け

git init .
git add .
git commit -m "Initial commit"
git tag 0.0.1 -m "Initial commit"

これでGitをコミットしてタグ付けしておきます。プロジェクト側からはこのタグを参照する様です。


プロジェクトを作成

cd ../ && mkdir ./MyProject && cd $_
swift package init --type executable

ようやくプロジェクトの作成です。GDと同階層にMyProjectという名前のディレクトリを作成して、SPMを実行可能形式で初期化しておきます。


Package.swift を編集

import PackageDescription

let package = Package(
    name: "MyProject",
    dependencies: [
        .package(url: "../GD", from: "0.0.1"),
    ],
    targets: [
        .target(
            name: "MyProject",
            dependencies: []),
    ]
)

Package.swiftファイルのdependenciesにGDをリンクします。


一度ビルドする

swift build

Fetching /PATH/TO/GD
Cloning /PATH/TO/GD
Resolving /PATH/TO/GD at 0.0.1
Compile Swift Module 'MyProject' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/MyProject

GD がフェッチされてちゃんとビルドされている事を確認します。


Xcodeprojを作成

swift package generate-xcodeproj

ここでXcodeプロジェクトを作成して、ガシガシコードが書ける様になりました。


フォルダ構成

tree .
.
├── GD
│   ├── Package.swift
│   └── module.modulemap
└── MyProject
    ├── MyProject.xcodeproj
    │   ├── project.pbxproj
    │   ├── project.xcworkspace
    │   │   ├── contents.xcworkspacedata
    │   │   ├── xcshareddata
    │   │   │   └── IDEWorkspaceChecks.plist
    │   │   └── xcuserdata
    │   │       └── fromkk.xcuserdatad
    │   │           └── UserInterfaceState.xcuserstate
    │   ├── xcshareddata
    │   │   └── xcschemes
    │   │       ├── MyProject-Package.xcscheme
    │   │       └── xcschememanagement.plist
    │   └── xcuserdata
    │       └── fromkk.xcuserdatad
    │           └── xcschemes
    │               └── xcschememanagement.plist
    ├── Package.resolved
    ├── Package.swift
    ├── README.md
    ├── Sources
    │   └── MyProject
    │       └── main.swift
    └── Tests

現時点でのフォルダ構成はこの様な感じです。最初に作ったGDと並列でMyProjectを作成しました。


GDの基礎


画像新規作成

import GD

let width: Int32 = 640
let height: Int32 = 480
let image = gdImageCreateTrueColor(width, height)

画像を新規作成するにはgdImageCreateXXXXXを利用します。画像から読み込む事も可能です。


画像保存

import GD

let handler = fopen("path/to/image.png", "wb")
defer { fclose(handler) }
gdImagePng(image, handler)

画像を保存する時はgdImageXXXXを利用します。保存したい形式によっていくつか関数があるのでその時々で選んでください。


画像合成

import GD

let file = fopen("copy/image/path.png", "rb")
defer { fclose(file) }

let copyImage = gdImageCreateFromPng(file)
gdImageCopy(image, copyImage, dstX, dstY, srcX, srcY, width, height)

画像同士を合成するには別の画像を読み込んで、gdImageCopy関数で貼り付けます。


文字列を書き込む

import GD

let blackColor = gdImageColorAllocate(image, 0, 0, 0)
defer { gdImageColorDeallocate(image, blackColor) }

let text = UnsafeMutablePointer<UInt8>(mutating: "hogehoge")
gdImageString(image, gdFontGetSmall(), x, y, text, blackColor)

文字列を書き込む為にはgdImageString関数にフォントサイズ、位置、テキスト、色を指定します。デフォルトのフォントではAscii以外は文字化けします。
※日本語が利用したい場合は別でフォントを指定する必要がありますが今回は割愛します。


作ってみたツール

https://github.com/fromkk/TestSummaries


インストール方法

brew install fromkk/TestSummaries/testsummaries

結果

result.png


まとめ

XCTestで撮ったスクショを画像にまとめてチームに共有出来る様にしてみました。Homebrewから誰でもインストール出来ますので手軽に試せるかと思います。まだまだ過去の資産を活用する事で便利なツールは作れるなと思うのでこれを機にCLIでツールの作成に挑戦してみてはいかがでしょうか?


参考

9
9
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
9
9