マーシャリングなしで安全に画像量子化を行う方法はありますか?
-
11-09-2019 - |
質問
現在、Brendan Tompkins ImageQuantization dll を使用しています。http://codebetter.com/blogs/brendan.tompkins/archive/2007/06/14/gif-image-color-quantizer-now-with-safe-goodness.aspx
ただし、asp.net の中の信頼度では実行されません。
中程度の信頼で実行される画像量子化ライブラリを知っている人はいますか?
アップデート解決が遅くても気にしません。機能するものが必要なだけです。
解決
Marshal を使用してコードを置き換え、BinaryReader などを介して基礎となるストリームを明示的に読み取ることができるはずです。これは、すぐにアクセスできるアンマネージド メモリ内に既にあるコピーに依存するのではなく、ストリーム全体をマネージド メモリに読み取るか、シークする必要があるため、遅くなる可能性がありますが、基本的にはこれが唯一の選択肢です。
読み取り操作のみを実行する場合でも、中信頼コンテキストからアンマネージド メモリへのスペランキングを実行することはできません。
リンクされたコードを見ると、この種のことが許可されていない理由があります。まず第一に、彼は IntPtr の 64/32 ビットの側面を無視しています。
彼が使用している基礎となる BitMapData クラスは、任意のメモリへの無制限の読み取りアクセスを行うことを完全に前提としています。これは中程度の信頼の下では決して起こりません。
BitMap を直接 (遅い GetPixel 呼び出しで) 使用するか、従来のストリーム API 経由でデータを直接読み取り、配列にドロップして自分で解析するには、基本機能を大幅に書き直す必要があります。どちらも楽しいものではないでしょう。前者ははるかに遅くなります (ピクセル読み取りあたりのオーバーヘッドが高いため、桁違いに大きいと予想されます)。後者はそれほど遅くはありませんが (それでも遅いですが)、画像データの低レベルの解析を書き直すという点で、関連する作業がはるかに多くなります。 。
現在のコードに基づいて変更する必要があるものの大まかなガイドは次のとおりです。
Quantizer.cs より
public Bitmap Quantize(Image source)
{
// Get the size of the source image
int height = source.Height;
int width = source.Width;
// And construct a rectangle from these dimensions
Rectangle bounds = new Rectangle(0, 0, width, height);
// First off take a 32bpp copy of the image
Bitmap copy = new Bitmap(width, height, PixelFormat.Format32bppArgb);
// And construct an 8bpp version
Bitmap output = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
// Now lock the bitmap into memory
using (Graphics g = Graphics.FromImage(copy))
{
g.PageUnit = GraphicsUnit.Pixel;
// Draw the source image onto the copy bitmap,
// which will effect a widening as appropriate.
g.DrawImage(source, bounds);
}
//!! BEGIN CHANGES - no locking here
//!! simply use copy not a pointer to it
//!! you could also simply write directly to a buffer then make the final immage in one go but I don't bother here
// Call the FirstPass function if not a single pass algorithm.
// For something like an octree quantizer, this will run through
// all image pixels, build a data structure, and create a palette.
if (!_singlePass)
FirstPass(copy, width, height);
// Then set the color palette on the output bitmap. I'm passing in the current palette
// as there's no way to construct a new, empty palette.
output.Palette = GetPalette(output.Palette);
// Then call the second pass which actually does the conversion
SecondPass(copy, output, width, height, bounds);
//!! END CHANGES
// Last but not least, return the output bitmap
return output;
}
//!! Completely changed, note that I assume all the code is changed to just use Color rather than Color32
protected virtual void FirstPass(Bitmap source, int width, int height)
{
// Loop through each row
for (int row = 0; row < height; row++)
{
// And loop through each column
for (int col = 0; col < width; col++)
{
InitialQuantizePixel(source.GetPixel(col, row));
} // Now I have the pixel, call the FirstPassQuantize function...
}
}
他の関数でもほぼ同じことを行う必要があります。これにより、Color32 の必要性がなくなり、Bitmap クラスがすべてを処理します。
Bitmap.SetPixel()
2回目のパスを処理します。これは移植する最も簡単な方法ですが、中程度の信頼環境内で移植を行う場合は決して最速の方法ではないことに注意してください。