正解は、他のいくつかの回答からつなぎ合わせることができますが、どれも完全ではなく、いくつかの非常に悪いアイデア (画像を 2 回描画するなど) を提示するものもあります。
問題
アーティファクトが表示される理由は 3 つあります。
- デフォルト
Graphics.PixelOffsetMode
設定では、ピクセル値が正しくサンプリングされず、特にエッジ周辺で画像がわずかに歪んでしまいます。
InterpolationMode.HighQualityBicubic
デフォルトでは透明である画像の端を越えてピクセルをサンプリングします。これらの透明なピクセルは、サンプラーによってエッジ ピクセルと混合され、半透明のエッジになります。
- 透明度をサポートしない形式 (JPEG など) で半透明の画像を保存すると、透明度の値が黒に置き換えられます。
これらすべてを合計すると、セミブラック (グレー) のエッジになります。
投稿したコードには、他にもいくつかの問題があります。
使用したBitmap
コンストラクターは、元の画像のサイズを変更して新しい画像を初期化しBitmap
ているため、サイズ変更操作を 2 回行っています。空白のキャンバスを作成するには、目的のサイズだけでコンストラクターのオーバーロードを使用する必要があります。
このBitmap
クラスは、メモリ内のイメージの管理されていないコピーを表すことに注意してください。メモリを使い終わったときにメモリを解放するように GDI+ に指示できるように、メモリを破棄する必要があります。return を受け取るコードでそれを行っていると思いますが、Image
他の誰かがこのコードを借りた場合に備えて指摘します。
コードで使用されている設定は、他のCompositingQuality.HighQuality
設定が正しく行われていれば視覚的な効果はなく、実際にはデフォルト値のCompositingMode.SourceOver
. CompositingQuality
設定と設定を省略してCompositingMode.SourceCopy
、より優れたパフォーマンスで同じ結果を得ることができます。
コードで使用されているSmoothingMode
設定は にはまったく影響しないDrawImage()
ため、削除できます。
解決
これらのアーティファクトを削除する正しい方法はPixelOffsetMode.Half
、ImageAttributes
オブジェクトを使用してエッジ タイリングを指定し、HighQualityBicubic
サンプラーがサンプリングする透明なピクセル以外のものを持つようにすることです。
Graphics
クラス設定と、それらが画質とパフォーマンスに与える影響について詳しくは、 http: //photosauce.net/blog/post/image-scaling-with-gdi-part-3-drawimage-and-the-settings-をご覧ください。それが影響する
修正されたコードは次のようになります。
public static Image Scale(Image sourceImage, int destWidth, int destHeight)
{
var toReturn = new Bitmap(destWidth, destHeight);
using (var graphics = Graphics.FromImage(toReturn))
using (var attributes = new ImageAttributes())
{
toReturn.SetResolution(sourceImage.HorizontalResolution, sourceImage.VerticalResolution);
attributes.SetWrapMode(WrapMode.TileFlipXY);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.Half;
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.DrawImage(sourceImage, Rectangle.FromLTRB(0, 0, destWidth, destHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attributes);
}
return toReturn;
}