1

I'm trying to squeeze the best performance out of some imaging code and I've hit a wall.

As far as my knowledge goes it should be possible to speed up the process using pointers but my experience with them is very limited and finding good documentation to read and understand is proving difficult.

Am I correct? Could someone show an annotated example of the code converted to help me understand the process.

    public void UpdatePixelIndexes(IEnumerable<byte[]> lineIndexes)
    {
        int width = this.Image.Width;
        int height = this.Image.Height;

        IEnumerator<byte[]> indexesIterator = lineIndexes.GetEnumerator();
        for (int rowIndex = 0; rowIndex < height; rowIndex++)
        {
            indexesIterator.MoveNext();
            BitmapData data = this.Image.LockBits(Rectangle.FromLTRB(0, rowIndex, width, rowIndex + 1), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

            try
            {
                Marshal.Copy(indexesIterator.Current, 0, data.Scan0, width);
            }
            finally
            {
                this.Image.UnlockBits(data);
            }
        }
    }
James South
  • 10,147
  • 4
  • 59
  • 115

1 Answers1

2

It's unlikely you actually need unsafe here. As suggested, you should just stop locking/unlocking the bitmap for every scan line. Instead, do this:

public void UpdatePixelIndexes(IEnumerable<byte[]> lineIndexes)
{
    int width = this.Image.Width;
    int height = this.Image.Height;
    int rowIndex = 0;

    BitmapData data = this.Image.LockBits(Rectangle.FromLTRB(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
    try
    {
        foreach (byte[] scanLine in lineIndexes)
        {
            Marshal.Copy(scanLine, 0,
               IntPtr.Add(data.Scan0, data.Stride * rowIndex), width);

            if (++rowIndex >= height)
            {
                break;
            }
        }
    }
    finally
    {
        this.Image.UnlockBits(data);
    }
}
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thanks. That's certainly an improvement. I'd like to avoid duplicating the memory by using Marshal.Copy hence why I was looking for unsafe usage if possible. – James South Nov 06 '14 at 20:36
  • `Marshal.Copy()` shouldn't be duplicating data. It should just copy the bytes from one place to the other. Do you have some reason to believe it is duplicating data? – Peter Duniho Nov 06 '14 at 20:37
  • I just thought that's what it did. This comment seemed to back that up. http://stackoverflow.com/questions/6782489/create-bitmap-from-a-byte-array-of-pixel-data#comment24719278_6782489 – James South Nov 06 '14 at 20:53
  • First, that comment is out of context and it may or may not be the case that the commenter intended to mean that the copy of the data was made by `Marshal.Copy()` itself (i.e. they could be talking about the need to allocate memory in the form of a new `Bitmap` object). Second, even if the commenter did mean that `Marshal.Copy()` performs an allocation of some temporary, intermediate buffer, that doesn't mean the commenter knows what they are talking about. – Peter Duniho Nov 06 '14 at 21:10
  • True that. I'm happy to assign this as the answer. – James South Nov 06 '14 at 21:19
  • I think it copies one line for a short time, no problem there. – TaW Nov 07 '14 at 05:35