Есть ли какой-нибудь способ выполнить квантование изображения безопасно и без сортировки?
-
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.Это может быть медленнее, поскольку вы должны полностью считывать поток в свою управляемую память или искать в нем, а не полагаться на то, что копия, уже находящаяся в неуправляемой памяти, будет быстро доступна, но, по сути, это ваш единственный вариант.
Вы просто не можете проникнуть в неуправляемую память из контекста среднего доверия, даже если выполняете только операции чтения.
Посмотрев на связанный код, я понял, почему вам не разрешено делать подобные вещи.Для начала, он игнорирует 64/32-битный аспект IntPtr!
Базовый класс 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()
разберемся со вторым проходом.Обратите внимание, что это самый простой способ переноса данных, но абсолютно не самый быстрый способ сделать это в среде среднего уровня доверия.