#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 の指定をおこなっておく必要があります。