C# を使用して透明な画像のサイズを変更する
-
09-06-2019 - |
質問
透明な画像(主にGIF)のサイズを変更する秘密の公式を知っている人はいますか? それなし 品質の低下はありますか?
たくさんのものを試しましたが、最も近いものでは十分ではありません。
私のメイン画像を見てください。
http://www.thewallcompany.dk/test/main.gif
そして、拡大縮小された画像:
http://www.thewallcompany.dk/test/ScaledImage.gif
//Internal resize for indexed colored images
void IndexedRezise(int xSize, int ySize)
{
BitmapData sourceData;
BitmapData targetData;
AdjustSizes(ref xSize, ref ySize);
scaledBitmap = new Bitmap(xSize, ySize, bitmap.PixelFormat);
scaledBitmap.Palette = bitmap.Palette;
sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, bitmap.PixelFormat);
try
{
targetData = scaledBitmap.LockBits(new Rectangle(0, 0, xSize, ySize),
ImageLockMode.WriteOnly, scaledBitmap.PixelFormat);
try
{
xFactor = (Double)bitmap.Width / (Double)scaledBitmap.Width;
yFactor = (Double)bitmap.Height / (Double)scaledBitmap.Height;
sourceStride = sourceData.Stride;
sourceScan0 = sourceData.Scan0;
int targetStride = targetData.Stride;
System.IntPtr targetScan0 = targetData.Scan0;
unsafe
{
byte* p = (byte*)(void*)targetScan0;
int nOffset = targetStride - scaledBitmap.Width;
int nWidth = scaledBitmap.Width;
for (int y = 0; y < scaledBitmap.Height; ++y)
{
for (int x = 0; x < nWidth; ++x)
{
p[0] = GetSourceByteAt(x, y);
++p;
}
p += nOffset;
}
}
}
finally
{
scaledBitmap.UnlockBits(targetData);
}
}
finally
{
bitmap.UnlockBits(sourceData);
}
}
上記のコードを使用して、インデックス付きのサイズ変更を行っています。
改善のアイデアを持っている人はいますか?
解決
スケーリング後にファイルタイプを保持する必要がない場合は、次のアプローチをお勧めします。
using (Image src = Image.FromFile("main.gif"))
using (Bitmap dst = new Bitmap(100, 129))
using (Graphics g = Graphics.FromImage(dst))
{
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(src, 0, 0, dst.Width, dst.Height);
dst.Save("scale.png", ImageFormat.Png);
}
結果は非常に素晴らしいアンチエイリアス処理されたエッジになります。
- 削除された画像小屋の画像が広告に置き換えられました
画像を gif でエクスポートする必要がある場合は、すぐに実行できます。GDI+ は GIF とうまく連携しません。見る このブログ投稿 詳細については
編集: この例ではビットマップを破棄するのを忘れていました。修正されました
他のヒント
これは、GDI+ を活用するいくつかのアプリケーションで使用した基本的なサイズ変更関数です。
/// <summary>
/// Resize image with GDI+ so that image is nice and clear with required size.
/// </summary>
/// <param name="SourceImage">Image to resize</param>
/// <param name="NewHeight">New height to resize to.</param>
/// <param name="NewWidth">New width to resize to.</param>
/// <returns>Image object resized to new dimensions.</returns>
/// <remarks></remarks>
public static Image ImageResize(Image SourceImage, Int32 NewHeight, Int32 NewWidth)
{
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(NewWidth, NewHeight, SourceImage.PixelFormat);
if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format1bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format4bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format8bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Undefined | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.DontCare | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppArgb1555 | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppGrayScale)
{
throw new NotSupportedException("Pixel format of the image is not supported.");
}
System.Drawing.Graphics graphicsImage = System.Drawing.Graphics.FromImage(bitmap);
graphicsImage.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality;
graphicsImage.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
graphicsImage.DrawImage(SourceImage, 0, 0, bitmap.Width, bitmap.Height);
graphicsImage.Dispose();
return bitmap;
}
GIF で機能するかどうかは思い出せませんが、試してみてはいかがでしょうか。
注記:この機能を全面的に評価することはできません。オンラインの他のサンプルからいくつかのものを組み合わせて、ニーズに合わせて機能させました 8^D
問題は、走査線ベースのサイズ変更を行っていることだと思います。これでは、どんなに調整してもジャギーが発生します。画像のサイズ変更の品質を良好にするには、サイズ変更後のピクセルがカバーするサイズ変更前のピクセルの平均色を把握するために、さらに作業を行う必要があります。
この Web サイトを運営している人は、いくつかの画像サイズ変更アルゴリズムについて説明したブログ投稿を投稿しています。おそらく、バイキュービック画像スケーリング アルゴリズムが必要になるでしょう。
Markus Olsson のソリューションを使用して画像のサイズを動的に変更し、応答ストリームに書き出そうとしている人向けです。
これは機能しません:
Response.ContentType = "image/png";
dst.Save( Response.OutputStream, ImageFormat.Png );
しかし、これにより次のことが起こります。
Response.ContentType = "image/png";
using (MemoryStream stream = new MemoryStream())
{
dst.Save( stream, ImageFormat.Png );
stream.WriteTo( Response.OutputStream );
}
PNG は GIF よりも明らかに優れていますが、場合によっては GIF 形式のままにしておく必要があるユースケースもあります。
GIF または 8 ビット PNG では、量子化の問題に対処する必要があります。
量子化では、どの 256 (またはそれより少ない) 色がイメージを最適に保持して表現するかを選択し、RGB 値をインデックスに戻します。サイズ変更操作を実行すると、色を混合したりバランスを変更したりするため、理想的なカラー パレットが変化します。
10 ~ 30% などのわずかなサイズ変更の場合は、元のカラー パレットを保持しても問題ない場合があります。
ただし、ほとんどの場合、再量子化する必要があります。
主に選択できる 2 つのアルゴリズムは Octree と nQuant です。Octree は非常に高速で、特にスマート ディザリング アルゴリズムをオーバーレイできる場合に非常に優れた仕事をします。nQuant はエンコードを実行する (完全なヒストグラムを構築する) ために少なくとも 80 MB の RAM を必要とし、通常は 20 ~ 30 倍遅くなります (平均画像のエンコードごとに 1 ~ 5 秒)。ただし、一貫したパフォーマンスを維持するために値を「丸め」ないため、Octree よりも高い画質が生成される場合があります。
で透明 GIF とアニメーション GIF のサポートを実装する場合、 画像サイズ変更.net プロジェクトでは Octree を選択しました。画像パレットを制御できれば、透明度のサポートは難しくありません。