ImageMagickでpdfファイルの1ページ目だけをjpegにする

ImagemMgickのconvertコマンドでpdfをjpegにしようとするとエラーになってしまいました.でもこれは見覚えのあるエラー……どこかにメモした気がするのですが見当たらないのでblogにしてみました.

ImageMagickのセキュリティポリシーを変更してpdfファイルを変換できるようにする

$ convert -geometry 640 /var/tmp/Nextcloud2pdf_cache/HQeSTL5TgcgAPtS.pdf[0] /tmp/HQeSTL5TgcgAPtS.jpg
convert-im6.q16: attempt to perform an operation not allowed by the security policy `PDF' @ error/constitute.c/IsCoderAuthorized/408.
convert-im6.q16: no images defined `/tmp/HQeSTL5TgcgAPtS.jpg' @ error/convert.c/ConvertImageCommand/3258.

セキュリティの問題でImageMagickの設定で無効にしてあるのでこれを有効にします.

$ sudo git -C /etc diff /etc/ImageMagick-6/policy.xml
diff --git a/ImageMagick-6/policy.xml b/ImageMagick-6/policy.xml
index 82a3d0b..0953557 100644
--- a/ImageMagick-6/policy.xml
+++ b/ImageMagick-6/policy.xml
@@ -91,6 +91,6 @@
   <policy domain="coder" rights="none" pattern="PS2" />
   <policy domain="coder" rights="none" pattern="PS3" />
   <policy domain="coder" rights="none" pattern="EPS" />
-  <policy domain="coder" rights="none" pattern="PDF" />
+  <policy domain="coder" rights="read|write" pattern="PDF" />
   <policy domain="coder" rights="none" pattern="XPS" />
 </policymap>

設定を編集後実行するとうまく動きました :)

$ convert -geometry 640 /var/tmp/Nextcloud2pdf_cache/HQeSTL5TgcgAPtS.pdf[0] /tmp/HQeSTL5TgcgAPtS.jpg

pdfファイルの指定ページだけを変換する

ソースファイル名を普通に指定すると, ファイル名-%d.jpg のようなファイルが連番で作成されます.
今回は1ページめだけが欲しいので不必要なファイルがたくさん出来てしまいます.

1ページだけが欲しい場合, ソースファイル名.pdf[0] というようにページ指定して実現できます.この添字は1ページ目が0,2ページめが1のように指定します.

存在しないページ番号を指定するとエラーになります.

$ convert -geometry 640 /var/tmp/Nextcloud2pdf_cache/HQeSTL5TgcgAPtS.pdf[99] /tmp/HQeSTL5TgcgAPtS-99.jpg

Requested FirstPage is greater than the number of pages in the file: 33
   No pages will be processed (FirstPage > LastPage).
convert-im6.q16: no images defined `./HQeSTL5TgcgAPtS-1.jpg' @ error/convert.c/ConvertImageCommand/3258.
環境
$ dpkg-query -W imagemagick
imagemagick     8:6.9.10.23+dfsg-2.1+deb10u1
$ lsb_release -dr
Description:    Debian GNU/Linux 10 (buster)
Release:        10
$ uname -m
x86_64

Imagemagickで画像変換時にキャッシュリソースが足りなくて転ける

Google Photoにheic形式でファイルをアップロードすると「高画質」(16MPに縮小される)設定でも縮小されないようなのでどのくらいのサイズまでOKなのかを試していたのですが,倍々で画像結合していたら128MPほどのファイル作成時に失敗しました.

$ convert -append out.heic out.heic out128.heic
convert-im6.q16: cache resources exhausted `out.heic' @ error/cache.c/OpenPixelCache/4083.

処理しているファイルは無駄にでかいです.

$ identify ./out.heic
./out.heic HEIC 9884x6552 9884x6552+0+0 8-bit YCbCr 0.020u 0:00.010

このあたりのページを参考にポリシーファイルを修正してメモリを増やしてみます.

$ sudo git -C /etc diff /etc/ImageMagick-6/policy.xml
diff --git a/ImageMagick-6/policy.xml b/ImageMagick-6/policy.xml
index 59d2fc6..4c6d088 100644
--- a/ImageMagick-6/policy.xml
+++ b/ImageMagick-6/policy.xml
@@ -57,8 +57,8 @@
   <!-- <policy domain="system" name="memory-map" value="anonymous"/> -->
   <!-- <policy domain="system" name="max-memory-request" value="256MiB"/> -->
   <!-- <policy domain="resource" name="temporary-path" value="/tmp"/> -->
-  <policy domain="resource" name="memory" value="256MiB"/>
-  <policy domain="resource" name="map" value="512MiB"/>
+  <policy domain="resource" name="memory" value="2048MiB"/>
+  <policy domain="resource" name="map" value="4096MiB"/>
   <policy domain="resource" name="width" value="16KP"/>
   <policy domain="resource" name="height" value="16KP"/>
   <!-- <policy domain="resource" name="list-length" value="128"/> -->

うまく行くようになりました :)

$ time convert -append out.heic out.heic out128.heic; echo $?

real    2m33.128s
user    6m42.527s
sys     0m4.704s
0
$ ls -l out128.heic
-rw-r--r-- 1 matoken matoken 4286359 Oct 20 00:30 out128.heic
$ identify out128.heic
out128.heic HEIC 9884x13104 9884x13104+0+0 8-bit YCbCr 0.000u 0:00.010

でも割り当て過ぎな気もするのでも少し減らそう.

$ dpkg-query -W imagemagick
imagemagick     8:6.9.10.23+dfsg-2.1+b2
$ lsb_release -dr
Description:    Debian GNU/Linux bullseye/sid
Release:        unstable
$ uname -m
x86_64

Mailmanのban_listを画像にする

最近Mailmanにbotからであろう登録が沢山やってくるようになりました.登録メールアドレスは大抵メジャーなフリーメールアドレスで生きているようなのですが,quotaや転送量のエラーとなって帰ってきます.これらのエラーメールでメールボックスがあふれて辛いです.

Mailmanにcaptchaか何かを設置できるプラグインとか無いかなと探してみたのですが,公式ではないようです.sourceを修正してGoogleのReCaptchaを実装している人は居ますが,バージョンアップのたびにパッチするのは面倒です.最近もセキュリティホールが見つかっていますし放置するわけにも生きません.

該当メールを見ると幸いメールアドレスは使い回しでバリエーションは多くありません.とりあえずMailmanのban_listにこれらのメールアドレスを登録してmailqに溜まっている該当メールはdropしました.1週間くらいしたらリモートからのエラーメールも無くなって静かになると良いなと思っています.
ban_listに登録しましたが,もしかしたらbotではなく普通に登録しようとしてメールボックスがあふれている人も居るかもしれません.それが解るようにban_listを申し込みページに表示することにしました.そのまま表示するのは良くない気がするので画像にしてノイズを散らして波型変形をかけてみました.
Mailmanのconfig_listコマンドで設定を出力してban_listをファイルに書き出し,Imagemagickのconvertコマンドでノイズと波型変形のフィルタをかけて画像を生成しました.
こんな感じの画像になります.これを申し込みページに説明と一緒に載せます.(ノイズのせいで容量が大きく……)

image

cronに登録しました.

$ sudo -u list crontab -l|grep ban_list
39 * * * *      /usr/lib/mailman/bin/config_list -c -o /dev/stdout users|grep ^ban_list |sed -e 's/^.*\[\|\]\|'\''\|'\ '//g'|sed -e 's/\@/ at /g'|tr -s ',' '\n' | sort -n > /var/lib/mailman/lists/users/ban_list && convert -size 1024x600 -background '#FFFFFF' -density 36 -gravity Center -fill black -font SetoFont label:"users ban_list `stat -c \%y /var/lib/mailman/lists/users/ban_list|cut -f1 -d.`\n\n`cat /var/lib/mailman/lists/users/ban_list`" -attenuate 5 -noise 7 +noise Gaussian -wave 15x`expr \( 100 + $((RANDOM \% 100)) \)` /var/lib/mailman/archives/public/users/ban_list.jpg

……長いですね.それに画像サイズ固定なのでlistが増えると文字サイズが小さくなってしまいます.てことでscriptに.

#!/bin/sh
 
LISTNAME='users'
FONT='SetoFont'
BANLIST='/var/lib/mailman/lists/users/ban_list'
IMAGE='/var/lib/mailman/archives/public/users/ban_list.jpg'
 
# ban_listを抽出してファイルに書き出し
/usr/lib/mailman/bin/config_list -c -o /dev/stdout ${LISTNAME} | grep ^ban_list | sed -e 's/^.*\[\|\]\|'\''\|''//g' | sed -e 's/\@/ at /g' | tr -s ',' '\n' | sort -n > ${BANLIST}
 
# ban_listの行数によって画像高さを計算
BANWC=`wc -l ${BANLIST} | cut -d -f1`
HIGHT=`expr \( ${BANWC} \* 60 + 120 \)`
 
# 画像に書き出す文字列を作成
LABEL="users ban_list `stat -c \%${BANLIST} | cut -f1 -d.`\n\n`cat ${BANLIST}`"
 
# 波型変形の波の深さを計算
WAVEX=`expr \( 10 + $((RANDOM % 10)) \)`
WAVEY=`expr \( 100 + $((RANDOM % 100)) \)`
 
# 画像作成
convert -size 1024x${HIGHT} -background '#FFFFFF' -density 36 -gravity Center -fill black -font ${FONT} label:"${LABEL}" -attenuate 5 -noise 7 +noise Gaussian -wave ${WAVWX}x${WAVEY} ${IMAGE}
 

てことでとりあえずの対処療法ですが…….

環境

$ lsb_release -d
Description:    Debian GNU/Linux 9.4 (stretch)
$ uname -m
x86_64
$ dpkg-query -W mailman
mailman 1:2.1.23-1+deb9u2
$ dpkg-query -W imagemagick
imagemagick     8:6.9.7.4+dfsg-11+deb9u4