Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換する

 Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換することができるが、上手く変換されない場合がある。

 

以前作った魔法陣イラスト素材をイラスト素材ストックサイトへ登録しようと思い立ち、改めて素材用にラスタライズ変換をかけようとした。

 

ラスタライズ変換にはImageMagickの convert が使用でき、DPI的な設定  -density 600  でサイズ調整している。


` convert -density 600 $filename.svg $filename-ss.jpg `

 

元画像はこちら


 変換結果はこのようになってしまう。

30枚の画像をSVGからJPGへ変換した結果、6枚ほど結果が明らかにおかしい。
 

失敗しているものを拡大した抜粋。


真っ白で明らかに変換できていないものもあれば、circle要素などSVG画像から一部が抜け落ちてしまっているものもある。

 

また上のような真っ白な変換失敗や大きなパーツの欠損は明らかに見てわかるのでまだ良いが、小さなパーツの漏れ欠けがあるかもしれないし、そうなると今回のように多数の画像を扱っている中では見落としが起こると思う。

 

コマンドラインでバッチ処理したのだが、いくつかはエラーが通知されている。

```

MN@daisy-bell:MagickCircle/$ bash a.sh
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.
convert-im6.q16: memory allocation failed `' @ error/draw.c/CheckPrimitiveExtent/2274.
convert-im6.q16: non-conforming drawing primitive definition `circle' @ error/draw.c/RenderMVGContent/4405.

```

ただ、 ` memory allocation failed` とはいうものの、メモリはかなりとっているのだが。

```  /etc/ImageMagick-6/policy.xml

<policy domain="resource" name="memory" value="8GiB"/>
<policy domain="resource" name="map" value="8GiB"/>
<policy domain="resource" name="width" value="128KP"/>
<policy domain="resource" name="height" value="128KP"/>
<policy domain="resource" name="area" value="2048MP"/>
<policy domain="resource" name="disk" value="16GiB"/>

```

 

小さなサイズで出力してみる。

```

convert -density 600 $filename.svg $filename-ss.jpg

convert -density 90 $filename.svg $filename-3ss.jpg

 ```

 

 

小さなサイズで出力すると、たしかに結果が改善する。


 エラー通知も1個減っていた。

 


とはいえ、ストックサイトへ登録するにあたっては大きいサイズでほしいのだが。

 

GIMPでもSVGをインポートしてラスタライズすることができる。

GUI操作で読み込むと任意のスケールで問題なく読み込めるのだが、CLI呼び出しでバッチ処理に使おうとすると、きちんと変換された結果が出ない。


 画像のような変換結果になる。変換されているごく一部のパーツを見るだけでも、明らかに画質が悪い。

またこの場合は背景を 白背景で書き出せば上手く行きそうに見えるが、試した範囲では、変換結果が真っ白になるだけで上手く行かなかった。

 

以下、うまく行かなかったGIMPでのSVGインポート変換を一応抜粋。

```

# GIMPのコマンドを使ってSVGを読み込む
gimp -i -b - <<EOF
(let* (
       (image (car (gimp-file-load RUN-NONINTERACTIVE "$input_file" "$input_file")))
       (drawable (car (gimp-image-get-active-layer image)))
       (new-width $size)
       (new-height $size)
       )
  (gimp-image-scale image new-width new-height)
  (file-jpeg-save RUN-NONINTERACTIVE image drawable "$output_file" "$output_file" 0.9 0 1 0 "" 0 1 0 1)
  (gimp-image-delete image)
  )
(gimp-quit 0)
EOF

```


またGIMP操作にはもう1つ、Pythonからgimpfuを経由して呼び出す方法もあり、こちらは上野LISPな古いGIMPスクリプトより高度な操作ができるのだが、現状GIMPがPython3に対応していないとかで、今回は断念した。

FireFoxでcontent_scripts内のconsole.log()のメッセージが出力されない

 本件は、2023/09頃には解決しているはずの話です。

 

TL;DR 

Q. chromeで動いたwebextensionsがFireFoxでcontent_scripts内のconsole.log()のメッセージをコンソールに出力しないのはなぜか?

A. FireFoxが 2023/06 FireFox 114.0時点でmanifest v3に対応していないにもかかわらずエラーを全く出さないため。

 

# 再現

 

```: ディレクトリ構成

DaisyWarekiConv/

├── manifest.json

├── icons/icon128.png

└── my_content_script.js

 ```

```: my_content_script.js

console.log("hello webextensions daisy wareki conv.");

```

```: manifest.json

{
"manifest_version": 3,
"name": "dev-DaisyWarekiConv",
"version": "0.0.1",

"icons": {
"128": "icons/icon128.png"
},

"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["my_content_script.js"]
}
]
}

```

 

# 間違った解決策

## Webコンソール ではなくブラウザーコンソールを開く

 FireFoxのwebextensionsのconsole.log()メッセージはF12キーで開くWebコンソールではなく、Ctrl+Shift+Jで開くブラウザーコンソールに表示される、らしい。

https://qiita.com/mouseofmicky/items/05dc51f792e16e25ae29 

Fコレ自体が相当にFireFox固有の落とし穴感があるが、こちらをチェックしていてもやはりログメッセージは出力されない。


 

また、開発ツールのコンソール(一時的な拡張機能の読み込み>調査 ボタンから開く )もあるが、こちらにも表示されない。これはbackgroundのメッセージが表示される(のだったと思う)。



## document.addEventListener('DOMContentLoaded', ~)

そもそもcontent_scriptsがデフォルトでページ読み込みが完了したこのあたり(雑)のタイミングで読み込まれるものであるし、console.log()の出力成否はページの描画状況とは関係ない。

 

## document.body.appendChild(elemDebugMsgOnDisplay);

console.logが出ないならDOMでページ上に直接出してしまえばいいじゃない、のアプローチ。

content_scriptsが走っていないので DOM書き換えが行われず、うまくいかない。

 

# 解決策

manifest v2(MV2)に変更する。

```

{
"manifest_version": 2,

```
 

# おわりに

FireFoxはまだMV3未対応できちんと動かないなら、最初から読み込まないとか、動かないというエラーログを出してほしい。

 

Blenderでレンダリング画像の色がおかしい場合の対処

レンダリング結果の画像が編集画面と一致せずおかしくなる場合が有ります。

編集画面ではこれで、

 レンダリング結果の色がおかしくなっています。


原因はWorldの背景色が反射でオブジェクトに映っているためです。

 Scene>Surface>Color から設定できます。

また右上のViewを選択することでRenderingプレビューで表示して編集することもできます。

またViewの設定ではSceneWorldのチェックを外すと背景色がオブジェクトに映らなくなります。

 


以上です。

ImageMagickで画像変換に失敗する場合に行うリソース上限設定

ImageMagickでPNGをJPGに変換しようとしたところ、 エラーが発生。

 


使用コマンド:

`find *.png | xargs -I{} convert "{}" "{}.jpg"

 エラーメッセージ:

```
convert-im6.q16: no images defined `Shinden144_Camera.FreeTop-fs8.png.jpg' @ error/convert.c/ConvertImageCommand/3229.
```


エラーメッセージは原因を指しておらず、またコマンドのファイルパスやオプションによるものではなく、原因はリソース不足でした。

PCの性能ではなく、ImageMagickの設定上のリソース上限です。

10000*10000pxを超えるようなサイズの大きい画像をImageMagickで変換するには、ImageMagickのリソース上限Upが必要となります。


Ubuntu24.04の場合のパスは次の通り。

`sudo vim /etc/ImageMagick-6/policy.xml`

次のように上限変更してリソース使用量を増やしました。

```
<policy domain="resource" name="memory" value="1024MiB"/>
<policy domain="resource" name="map" value="1024MiB"/>
<policy domain="resource" name="width" value="64KP"/>
<policy domain="resource" name="height" value="64KP"/>
<policy domain="resource" name="area" value="512MP"/>
<policy domain="resource" name="disk" value="4GiB"/>
```




参考:
http://www.imagemagick.org/discourse-server/viewtopic.php?t=34044


ドラッグ可能なHTMLダイアログ(pure javascript)

 ファイルを開くダイアログならともかく、Itemの回転ダイアログなどは画面に被っていると、編集対象が隠れてダイアログ操作しずらくなってしまいます。

そこでモーダルダイアログ をドラッグで移動できるようにする必要があります。

HTMLのダイアログの場合、ドラッグ可能にするにはJSが必要で少しばかり手間です。

 


 

 

こちらに一案が紹介されていますが、これが動かなかったので別案を立てたものです。

 ドラッグで移動できるdialogタグをざっくりと作る

たぶんdialogやその親ページにかけられているCSSやHTML構造によって異なるのでしょう。

 

JS,CSS,HTML共にバニラな状態で動くはずです。

HTML

<dialog id='doc-save-dialog' draggable="true">
<form method="dialog">
<h1>Save?</h1>
document name:<br>
<input id='doc-name-input' type='text' class="default-focus-in-dialog"/>
<menu>
<button value="cancel">Cancel</button>
<button value="Save">Save</button>
</menu>
</form>
</dialog>

 大事なのはこれです。

draggable="true"

dialogタグにこれを付け忘れると、ドラッグはできるもののマウスでポイントが一発で上手く行かないダイアログになってしまいます。

かなり操作がストレスになります。


 JS

{
const dialogs = document.getElementsByTagName('dialog');
dialogs.forEach(dialog => {
let mouse = {
x: 0,
y: 0,
};
let pos = {
x: 0,
y: 0,
};
dialog.addEventListener('dragstart', evt => {
mouse.y = evt.pageY;
mouse.x = evt.pageX;
if(! dialog.style.top){
dialog.style.top = "0px";
dialog.style.left = "0px";
pos.y = 0;
pos.x = 0;
}else{
pos.y = parseInt(dialog.style.top.slice(0, -2), 10);
pos.x = parseInt(dialog.style.left.slice(0, -2), 10);
}
evt.dataTransfer.setDragImage(document.createElement('div'), 0, 0);
console.log('dragstart', evt.pageX, evt.pageY, mouse, pos, dialog.style.top);
});
dialog.addEventListener('drag', evt => {
if (evt.x === 0 && evt.y === 0) return;
const movey = (evt.pageY - mouse.y) * 2;
const movex = (evt.pageX - mouse.x) * 2;
dialog.style.top = (pos.y + movey) + 'px';
dialog.style.left = (pos.x + movex) + 'px';
console.log('drag', evt.pageX, evt.pageY, mouse, pos, dialog.style.top, movey);
});
});
}

drag開始とdrag中のマウス位置の差分をとって、drag開始時のDialog位置に足し合わせた新しい座標をセットしています。

mouseの移動量をそのまま差分で足していくと、mousemoveイベントの発行具合でだんだんズレていくので(このコードでは検証していませんが恐らく経験的に)、わざわざ初期値を保存して差分を計算しています。

 

TODO として、移動量に2を掛けないと上手く行かない理由は不明です。なのでこのコードは結果的に動いていますが何か間違っている気がします。


 最初は、

dialog.style.top = "0px";
dialog.style.left = "0px";

 がundefinedで存在しないので、セットしてしまいます。

初期位置はtop,left共に0pxらしいです。

2度め以降の移動では、dialogの初期位置もここから取るようにします。

 

 

本ドラッグ可能dialogコードは一応、手元の環境の中で

- 同ページ内に複数ダイアログで問題なし。 

- 開き直したダイアログが同じ位置に出る。

- 1度ドラッグして、再度ドラッグしてもズレたり問題は起こらない。

 ことを確認しています。

HTML Dialog上で入力中にEnterキー押下しても大丈夫にする

 HTML Dialog上で入力中にEnterキー押下してしまうとユーザ入力内容が消えてしまう問題を解決する方法です。

 HTML Dialog上でEnterキー押下した場合のデフォルト動作は、Cancelボタン押下された扱いで閉じることです。

しかしこの動作はinput elementにフォーカスが入っている状態でも有効です。

Dialog上でinput elementで入力している途中で閉じてしまいます。

しかも、WebアプリとしてはCancelボタン押下を検出したら入力をなかったことにするはずです。

結果、ユーザとしては入力途中の内容が突然消えてしまうわけで、困ります。

 

そこでこの、キャンセルで閉じてしまうDialogの動作を変更します。


// MEMO デフォルトではdialog内のinputでEnter押下すると、dialogが閉じてしまう。
// そのためEnterキーをキャンセルしつつ、入力の確定は行う処理をここで追加。
dialog.addEventListener('keydown', (event) => {
const elem = document.activeElement;
console.log(`dialog keydown "${event.key}"`, elem)
if('INPUT' === elem.tagName && 'Enter' === event.key){
elem.dispatchEvent( new KeyboardEvent('change'));
event.preventDefault();
return;
}
});


入力確定したらOKボタン押下扱いでDialogを閉じる、などしたければさらに工夫が必要になりますが、とりあえずこれでユーザ入力が失われる問題は解決します。


なお他の方法。

https://developer.hatenastaff.com/entry/2021/12/01/100000

 

 

画像Buttonのclickイベントが発火しないとき

画像Buttonのクリックイベントが発火せず、けっこう悩みました。
 



 デベロッパーツールのコンソールには特にエラーなど表示されず。

またクリックイベントも登録された状態になっています。登録忘れや削除されてしまったなどではないようです。

 


 

問題の起こったボタンがjsで生成した直後のもので、他のところではすでに同じような画像Buttonで問題なくclickイベントが動作していました。

状況的に「documentツリー内にappendしてからでないとダメなのか?」などと疑ったり試したりと悩んだものの、原因はそれではなく。

理由は全く別のところにありました。

 そもそもHTMLで「画像ボタン」 を実装する方法はいくつも種類があります。

img要素のclickイベントをListenするとか。

その中で今回はSVGを使う都合から、「Button要素にObject要素を入れて、Object要素でSVGを表示」という方法を取っていました。

 つまりこれです。

<button class="layer_is-visible">
<object data="resource/layer/is-visible-open.svg" type="image/svg+xml"></object>
</button>

 

さんざんListenの方法やタイミング、ターゲットを変えてと一通り試してから、そういえばかなり初期に画像ButtonにCSS設定していたな、 と思い出して確認したところそこに正解がありました。


CSSにて以下を記載。

/* click event Buttonのclickイベントを動作させる */
button object{
pointer-events: none;
}

 以上です。

 

恐らくButtonのchildrenにObjectがあることで、ClickイベントをObjectが受け取り下のButtonまでたどり着かないということなのだと思います。

 

CSS設定を忘れたまま別の箇所で意図しない影響が出ないよう、CSSセレクタでターゲットを絞っていたのが裏目に出ました。今度こそドキュメント全体に影響するよう変更したので、もう次からはドキュメントのどこでSVG画像ボタンを使っても大丈夫です。

...恐らく。

 

 ここでひとつ罠なのは、「内側のObject要素がClickイベントを受け止めているからButtonにClickが発生しない」にもかかわらず、「ならばとObject要素でClickイベントをListenerしても、これもまた発火しない」という部分。

(Object要素の中のSVGが要素扱いでClickイベントを受けているのかもしれないけれど、だったらデベロッパーツールでObject要素内のSVG まで展開されるのが一貫性というものでは? などと思ったり。)

 

なんというか「こういう設計(挙動)になっているきっと合理的な理由があるのだろうけれど、そんなのユーザにはわかりっこないよ!(要約)」というやつの気がします。

DOMイベント構造は複雑怪奇。

Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換する

 Linuxコマンドライン上でSVGベクタ画像をJPG等へラスタライズ変換することができるが、上手く変換されない場合がある。   以前作った魔法陣イラスト素材をイラスト素材ストックサイトへ登録しようと思い立ち、改めて素材用にラスタライズ変換をかけようとした。   ラスタライズ変換...