Azure App Service - Web Apps（Windows）に ImageMagick + Imagick + Ghostscript を導入

# はじめに
ImageMagick は言語毎に異なるモジュールや依存関係の複雑さから yum 等のパッケージ管理の仕組みを利用できる Linux 環境での導入・利用が望ましいようです。
Windows 環境への導入は、既に稼働中のサービスへの追加機能開発で必要など、必要に迫られた場合に限るのが無難かと思われます。

本記事は、必要に迫られ四苦八苦 [^1] しながら ImageMagick 等を導入した記録です。

:::note warn
本記事に掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。
:::

[^1]: 今回、32 ビット環境だった為か Azure 拡張機能として用意されている PHP7_64BIT_IMAGICK_6937 は上手く動かなかった。

# 環境

- Azure App Service - Web Apps
  - Windows IIS 10.0
  - PHP 7.3

# 導入手順
## ImageMagick と Imagick のダウンロード
`phpinfo()` で `Architecture` と `PHP Extension Build` の値を確認する。

- Architecture
  - x86
- PHP Extension Build
  - API20180731,NTS,VC15

今回は上記であった為
VC15 かつ x86 の ImageMagick と
PHP 7.3 で NTS（Non Thread Safe）の VC15 かつ x86 の Imagick を
ダウンロードする。

https://windows.php.net/downloads/pecl/deps/
ImageMagick-7.0.7-11-vc15-x86.zip

https://windows.php.net/downloads/pecl/releases/imagick/3.5.1/
php_imagick-3.5.1-7.3-nts-vc15-x86.zip

## ImageMagick のインストール
ImageMagick-7.0.7-11-vc15-x86.zip を展開し `bin` フォルダの中身を全て `D:\home\site\ImageMagick\` へアップロードする。

## Imagick のインストール
php_imagick-3.5.1-7.3-nts-vc15-x86.zip を展開し `php_imagick.dll` を `D:\home\site\ext\` へアップロードする。

:::note info
他技術ブログ等で ImageMagick のインストール工程で配置した bin 内 CORE_RL_* ファイルを上書きする手順が紹介されているが、バイナリを比較したところファイル内容が同一であった為、上書き不要と判断した。
:::

## ImageMagick 環境変数 PATH の設定
`D:\home\site\` へ以下の `applicationHost.xdt` ファイルをアップロードする。

```xml:home\site\applicationHost.xdt
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <runtime xdt:Transform="InsertIfMissing">
      <environmentVariables xdt:Transform="InsertIfMissing">
        <add name="PATH" value="%PATH%;d:\home\site\ImageMagick" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
      </environmentVariables>
    </runtime>
  </system.webServer>
</configuration>
```

## アプリケーション設定
Azure ポータルから
App Service > 設定 > 構成 > アプリケーション設定 > 新しいアプリケーション設定
以下 3つの設定を追加する。

|名前|値|
|---|---|
|MAGICK_CODER_MODULE_PATH|D:\home\site\ImageMagick|
|MAGICK_HOME|D:\home\site\ImageMagick|
|PHP_EXTENSIONS|D:\home\site\ext\php_imagick.dll|

※デプロイスロットの設定 はチェックしない

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243093/af46b3b5-816e-57bd-d21b-261b718a1759.png)

設定追加後、保存（アプリケーションの再起動）を行う。

## インストール確認
`phpinfo()` で ImageMagick ＋ Imagick が読み込まれていることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243093/781ec97e-3ec3-a845-3351-f0c09b32925e.png)

App Service > 開発ツール > コンソール
からも確認。

```terminal
D:\home\site\wwwroot>magick --version
Version: ImageMagick 7.0.7-11 Q16 x86 2017-11-23 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2015 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Visual C++: 191125547
Features: Cipher DPC HDRI Modules OpenMP 
Delegates (built-in): bzlib cairo flif freetype jng jp2 jpeg lcms lqr openexr pangocairo png ps raw rsvg tiff webp xml zlib
```

## 動作確認

```php:imagick.php
<?php
$im = new Imagick();
$im->newPseudoImage(50, 50, "gradient:red-black");
$draw = new ImagickDraw();
$draw->pushPattern('gradient', 0, 0, 50, 50);
$draw->composite(Imagick::COMPOSITE_OVER, 0, 0, 50, 50, $im);
$draw->popPattern();
$draw->setFillPatternURL('#gradient');
$draw->setFontSize(52);
$draw->annotation(20, 50, "Hello World!");
$canvas = new Imagick();
$canvas->newImage(350, 70, "white");
$canvas->drawImage($draw);
$canvas->borderImage('black', 1, 1);
$canvas->setImageFormat('png');
header("Content-Type: image/png");
echo $canvas;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/243093/3732d3af-ee6d-cd40-3a3b-6d6d631048ff.png)

## Ghostscript のインストール
ImageMagick で PDF を扱う場合はこちらも必要。

https://github.com/ArtifexSoftware/ghostpdl-downloads/releases

任意のバージョンの Windows インストーラー形式をダウンロードする。
今回は最新バージョンであった 9.55.0 を使用。
[gs9550w32.exe](https://github.com/ArtifexSoftware/ghostpdl-downloads/releases/download/gs9550/gs9550w32.exe)

まず、自身のローカル端末へ Ghostscript をインストールする。

インストールされたローカルの `C:\Program Files (x86)\gs\gs9.55.0` を `D:\home\site\gs9.55.0` へアップロードする。

以下のように `applicationHost.xdt` を変更して `bin` と `lib` へパスを通す。
※変更後、要サーバー再起動

```diff_xml:home\site\applicationHost.xdt
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <system.webServer>
    <runtime xdt:Transform="InsertIfMissing">
      <environmentVariables xdt:Transform="InsertIfMissing">
-       <add name="PATH" value="%PATH%;d:\home\site\ImageMagick" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
+       <add name="PATH" value="%PATH%;d:\home\site\ImageMagick;d:\home\site\gs9.55.0\bin;d:\home\site\gs9.55.0\lib" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
      </environmentVariables>
    </runtime>
  </system.webServer>
</configuration>
```

以上で Ghostscript インストールは完了。

App Service > 開発ツール > コンソール
から Ghostscript がインストールされていることを確認。

```terminal
D:\home\site\wwwroot>gs -v
GPL Ghostscript 9.55.0 (2021-09-27)
Copyright (C) 2021 Artifex Software, Inc.  All rights reserved.
```

しかし、このまま Imagick の `readImage()` メソッドで PDF ファイルを読み込もうとすると以下のようなエラーが発生する。

```
PHP Fatal error:  Uncaught ImagickException: PDFDelegateFailed `The system cannot find the file specified.
' @ error/pdf.c/ReadPDFImage/794 in D:\home\site\wwwroot\convert.php:3
Stack trace:
#0 D:\home\site\wwwroot\convert.php(3): Imagick->readImage('test.pdf')
#1 {main}
  thrown in D:\home\site\wwwroot\convert.php on line 3
```

その場合、`D:\home\site\gs9.55.0\bin\gswin32c.exe` を
`D:\home\site\gs9.55.0\bin\gs.exe` へリネームしてやると解決する。



下記コードと同一階層に適当な PDF ファイルを配置し、コードを実行すると PDF から画像が生成される。

```php:convert.php
<?php
$imagick = new Imagick();
$imagick->readImage('test.pdf');
$imagick->writeImage('test.jpg');
```

# おわりに
最終の記事推敲を行っていたところ
https://windows.php.net/downloads/pecl/deps/
から `ImageMagick-7.0.7-11-vc15-x86.zip` がダウンロード出来なくなっており
唯一ダウンロードできる x86 版は `ImageMagick-7.1.0-13-1-vs15-x86.zip` になっていた。[^2]

[^2]: 2021/12/02 時点

試しに本記事の手順で導入したところ

- ImageMagick + Imagick
  - 以下の Warning を吐くので Imagick インストール時に `CORE_RL_*` ファイルの上書きを推奨

```
PHP Warning:  Version warning: Imagick was compiled against ImageMagick version 1799 but version 1808 is loaded. Imagick will run but may behave surprisingly in Unknown on line 0
```

- Ghostscript
  - `gswin32c.exe` のリネーム工程が不要となる

というように必要な作業工程に差異があるものの、一応動いてはいた。
~~やはり ImageMagick 関係を導入する場合は Linux 推奨か。だらしない記事ですまない。~~

# 追記
ダウンロードできる x86 版が `ImageMagick-7.1.0-18-vc15-x86.zip` に更新されていた。[^3]

[^3]: 2021/12/22 時点

ファイル名に含まれる vs15 と vc15 の違いが気になったので少々調べてみた。
ビルドを行った環境を示しているとのことで

- Visual Studio 2017（内部バージョン 15）であれば vs15
- Visual C++ 20XX（内部バージョン 15）であれば vc15

という意味かと思ったのだが

- 現在 Visual C++ はバージョン 14系までしか存在していない
- Visual C++ はあくまで Visual Studio（開発環境）に内包されている Microsoft 社製の C++（プログラミング言語）コンパイラ製品

以上を踏まえると、表記の差異に深い意味はなく vs15 = vc15 との理解でいいのかな。たぶん。

# 参考
https://azureossd.github.io/2015/12/07/php-imagemagick-on-azure-web-apps/
https://github.com/snobu/php-imagick-webapps
https://yotazo.hateblo.jp/entry/2016/12/21/%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E7%92%B0%E5%A2%83_Windows%EF%BC%8BIIS%EF%BC%8BPHP%E3%81%A7ImageMagick%E3%82%92%E4%BD%BF%E3%81%86