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.