Bug(バグ) #3062
完了リサイズ後の画像サイズが荒い
0%
説明
Overview (現象)¶
Bug(バグ) #1931: 透過PNG画像が透過されずに背景が黒くなってしまう - OpenPNE 3 - OpenPNE Issue Tracking System
https://redmine.openpne.jp/issues/1931
の対策後、画像をリサイズした際に画質が荒くなるようになった。
Causes (原因)¶
#1931 で imagecopyresampled()
の代わりに imagecopyresized()
をコールするように変更されたことが原因だが、この変更は truecolor 画像に対してはおこなう必要がなかった。
Way to fix (修正内容)¶
#1931 でおこなわれた変更をより好ましい形に改善する形で、以下のような対処を実施した。
1. truecolor 時のみ PEAR::Image_Transform のオプションの scaleMethod を指定する (= imagecopyresampled()
の代わりに imagecopyresized()
をコールする)
2. save()
前の crop()
はこれまでにリサイズをおこなわなかったときにのみ実行する
詳しくは https://redmine.openpne.jp/issues/3062#note-5 の記載内容を参考のこと
Kousuke Ebihara さんが12年以上前に更新
- ステータス を New(新規) から Invalid(無効) に変更
- 対象バージョン を削除 (
OpenPNE 3.8.x)
#3059 と重複です。
Kousuke Ebihara さんが12年以上前に更新
- トラッカー を Enhancement(機能追加・改善) から Bug(バグ) に変更
- ステータス を Invalid(無効) から New(新規) に変更
- 対象バージョン を OpenPNE 3.9.0-old にセット
- 3.6 で発生するか を Yes (はい) にセット
本チケットが重複しているとしていましたが、重複元の #3059 が複数の問題を扱っていたため、本チケットを「リサイズ後の画像サイズが荒い」という問題を対応するためのチケットとしてリオープンします。
それから本現象はバグとしてみなすべきです。トラッカーを変更します。
Kousuke Ebihara さんが12年以上前に更新
#1931 では、最初に、 PEAR::Image_Transform のオプションの scaleMethod を pixel に設定することで現象を回避していました。これによってリサイズ時に imagecopyresampled()
の代わりに imagecopyresized()
がコールされることになりますが、それによって生じることについてまず説明します。
PHP にバンドルされている libgd のコードを確認したところ、 gdImageCopyResized()
では出力が truecolor と明示されていない場合、アルファチャネル関連の処理を自動的におこないますが、 gdImageCopyResampled()
ではそれがありません (truecolor と明示された場合のみ。 truecolor でない場合は gdImageCopyResized()
への fallback がおこなわれる)。
つまり truecolor についての考慮を自前でしないのであれば、アルファチャネル情報を保持するために (truecolor であっても) imagecopyresampled()
ではなく imagecopyresampled()
を使う必要があります。しかし、この方針には本チケットで指摘されているように、拡大縮小後の画像が粗くなる傾向があるといった問題があります。
ではどうするべきかというと、
- アルファブレンディングを無効に (
imagealphablending()
) し、 - 完全なアルファチャネル情報を保持するよう (
imagesavealpha()
) にしたうえで、 - リサイズの必要がある場合は
imagecopyresampled()
でリサイズをおこなう
必要があります。
実は PEAR::Image_Transform では、 truecolor 画像の場合はリサイズ時に (リサイズのためにパレット情報を構築する際に) 前二者は透過的におこなわれていました。
#1931 で問題になっていたのは、 リサイズしない場合に 画像が透過されないというものでした。これは実は単純な話で、 PEAR::Image_Transform によるリサイズがおこなわれない場合に前二者を満たしていなかったという現象だったようです。ただし、 a3c2edbf でおこなわれた scaleMethod の変更は、リサイズ処理を通らないためあまり意味がなく、 ab5cfd3a の、「PEAR::Image_Transform による画像パレット情報構築処理を実行させるために crop()
メソッドをコールする」ことによってはじめて実質上の対策となりました (ただし crop()
がリサイズ時に実質二回コールされてしまうのは過剰と言えます)。
ということで本チケットの問題への対策としては、
1. scaleMethod の指定を外し、
2. save()
前の crop()
は活かす (が、未リサイズ時に限定したい)
が適切であるといえます。
しかし、「1. scaleMethod の指定を外し、」には問題があります。このオプションを外すことで、 PEAR::Image_Transform 側で画像が常に truecolor としてみなされてしまうようで、リサイズ時に GIF の透過情報が壊れるといった問題があるようです。
そこで、画像が truecolor でない場合にはリサイズ前と保存前に、この scaleMethod の指定をおこなっておく必要があります。
Kousuke Ebihara さんが12年以上前に更新
- ステータス を Accepted(着手) から Pending Review(レビュー待ち) に変更
- 進捗率 を 0 から 50 に変更
更新履歴 a95f680bdbdebd254e17109d76496381f3c10bbc で適用されました。
Kousuke Ebihara さんが12年以上前に更新
1. 非 truecolor 時のみ scaleMethod を指定する
2. save()
前の crop()
はこれまでにリサイズをおこなわなかったときにのみ実行する
形で修正しました
Shinichi Urabe さんが10年以上前に更新
- ステータス を Pending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
- 進捗率 を 50 から 70 に変更
レビューOK