【问题标题】:Is there any way to do Image Quantization safely and with no Marshalling?有什么方法可以安全地进行图像量化且无需编组?
【发布时间】:2010-11-09 03:17:28
【问题描述】:

我目前正在使用 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 中以中等信任度运行。

有人知道在中等信任度下运行的图像量化库吗?

更新 我不在乎解决方案是否缓慢。我只需要一些有用的东西。

【问题讨论】:

    标签: c# asp.net image medium-trust


    【解决方案1】:

    您应该能够通过 BinaryReader 之类的东西显式读取底层流来替换使用 Marshal 的代码。这可能会更慢,因为您必须将流完全读入托管内存或查找它,而不是依赖已在非托管内存中快速访问的副本,但这基本上是您唯一的选择。

    您根本无法从中等信任上下文中深入研究非托管内存,即使只执行读取操作也是如此。

    查看了链接代码后,您不被允许做这种事情是有原因的。首先,他忽略了 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() 将处理第二遍。请注意,这是移植事物的最简单方法,但绝对不是在中等信任环境中进行移植的最快方法。

    【讨论】:

    • 对 Marshal 的任何调用都将在中等信任下失败。 :-(
    • 以及任何需要非托管代码的链接需求,所有这些都来自内存。不能直接读取底层位图吗?
    • 你可以合法地调用 Bitmap.GetPixel(x,y),这会给你颜色,虽然很慢
    • 您可能会更好地将整个图像读入 托管 内存,然后在那里处理它,而不是一次一个像素地通过 GetPixel 来回处理。遗憾的是,这将需要托管堆上更多的内存(并限制最大可能的图像大小)
    • 图像被读入非托管内存。您根本无法做到这一点,您必须将其加载到托管内存中(或使用缓慢但安全的 calsl 一点一点地获取数据)
    猜你喜欢
    • 2013-09-16
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多