views:

178

answers:

1

I'm currently using Brendan Tompkins ImageQuantization dll. http://codebetter.com/blogs/brendan.tompkins/archive/2007/06/14/gif-image-color-quantizer-now-with-safe-goodness.aspx

But it doesn't run in medium trust in asp.net.

Does anyone know of a Image Quantization library that does run in medium trust?

Update I don't care if the solution is slow. I just need something that works.

+2  A: 

You should be able to replace the code using Marshal with explicit reading of the underlying stream via something like BinaryReader. This may be slower since you must read the stream entirely into your managed memory or seek into it rather than relying on the copy already in unmanaged memory being quickly accessible but is fundamentally your only option.

You simply cannot go spelunking into unmanaged memory from a medium trust context, even if only performing read operations.

Having looked at the linked code there's a reason you're not allowed to do this sort of thing. For starters he's ignoring the 64/32bit aspect of the IntPtr!

The underlying BitMapData class he's using is utterly predicated on having unfettered read access to arbitrary memory, this is never happening under medium trust.
A significant rewrite of his base functionality will be required to either use BitMap's directly (with the slow GetPixel calls) or read the data directly via conventional stream apis, dropping it into an array(s) and then parse it out yourself. Neither of these are likely to be pleasant. The former will be much slower (I would expect order of magnitude due to the high overhead per pixel read), the later less slow (though still slower) but has much more associated effort in terms of rewriting the low level parsing of the image data.

Here's a rough guide to what you need to change based on the current code:

from 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...
    }
}

you would need to do roughly the same in the other functions. This removes any need for Color32, the Bitmap class will deal with all that for you.

Bitmap.SetPixel() will deal with the second pass. Note that this is the easiest way to port things but absolutely not the fastest way to do it within a medium trust environment.

ShuggyCoUk
Any calls to Marshal will fail in medium trust. :-(
Donny V.
well anything with the link demand requiring unmanaged code, which is all of them from memory. Can you not read the underlying bitmap directly?
ShuggyCoUk
You can call Bitmap.GetPixel(x,y) legally, this will get you the color, albeit slowly
ShuggyCoUk
you are likely better reading the whole image into _managed_ memory and then dealing with it there ratehr than going back and forth through the GetPixel stuff one pixel at a time. this will require significantly more memory on the managed heap though sadly (and limits the max possible image size)
ShuggyCoUk
the image is read into _unmanaged_ memory. you can't get at that at all, you must load it into managed memory (or use slow but safe calsl to get at the data bit by bit)
ShuggyCoUk
Sorry I know it's not what you want to hear but the fundamental design of this library is based around having more trust than you have.
ShuggyCoUk
Do you have any examples for this? ThaNKS
Donny V.
for the per pixel call, yes this is trivial in that you replace all usage of the BitmapData with Bitmap and replace data.Scan0.IntPtr then pointer arithmeticwith bitmap.GetPixel(x,y) iterating over x and y. If you iterate over scan lines still this will be markedly quicker due to caching, i.e. put x in your _inner_ loop. Rewriting it to load the whole thing into managed memory is going to be pretty much a total rewrite of the library
ShuggyCoUk
I really need this for my site too. I guess I'll have to slowly rewrite it. I have no clue what I'm doing with images, so I'll have to research while I do it.Thanks for all your help.
Donny V.
Here you go - I added a rough guide as a starter. You will fundamentally need to learn a bit about the Bitmap class if you want to do this.
ShuggyCoUk
+1, since it appears that no one else will. You certainly sound like you know what you are doing.
Robert Harvey
+1 Thank you for the start!! I'm going to leave this question unanswered for a couple days just to see anyone else wants to chime in. If now one anwsers I'll give you points. Thanks again!
Donny V.