Asked By James Maeding
24-Jan-07 06:25 PM

I generally work with large scans, so speed matters for me.
I wanted to set transparency for colors whose RGB byte total is less than 10 (light colors).
I tried the Bob powell method listed at:
http://www.bobpowell.net/lockingbits.htm
which locks a source and dest bitmap, then writes to the dest bitmap with:
Marshal.WriteByte(bmd.Scan0, offset, currentByte)
This is proving to be way too slow for images, say 2000x2000 pixels.
I think I have figured out a solution, based on looking at lots of others' code, I am interested in any comments on if I
am right or wrong...
Here is the solution summary:
1) lock source image and write bytes to byte array
2) make dest bitmap and lock
3) modify byte array as desired
4) write byte array to dest image memory all at once and unlock dest image
It seems a byte array is way faster to edit, and worth the trouble to write back at the end.
I have only done this for black and white conversions but I think the pattern applies to all bitmap manipulations.
Detailed code that changes image to black and white very fast (not transparency involved here):
1) lock the source bitmap,
marshall.copy the bytes to a byte array
unlock the source.
' Lock source bitmap in memory
Dim sourceData As BitmapData = source.LockBits(New Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
' Copy image data to binary array
Dim imageSize As Integer = sourceData.Stride * sourceData.Height
Dim sourceBuffer As Byte() = New Byte(imageSize - 1) {}
Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, imageSize)
' Unlock source bitmap
source.UnlockBits(sourceData)
2) Make destination bitmap,
lock bits
make desination buffer (leave bitmap locked for later write)
' Create destination bitmap
Dim destination As Bitmap = New Bitmap(source.Width, source.Height, PixelFormat.Format1bppIndexed)
' Lock destination bitmap in memory
Dim destinationData As BitmapData = destination.LockBits(New Rectangle(0, 0, destination.Width,
destination.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed)
' Create destination buffer
imageSize = destinationData.Stride * destinationData.Height
Dim destinationBuffer As Byte() = New Byte(imageSize - 1) {}
3) modify dest buffer as needed, this code loops through source and changes destination pixels to black or white:
Dim sourceIndex As Integer = 0
Dim destinationIndex As Integer = 0
Dim pixelTotal As Integer = 0
Dim destinationValue As Byte = 0
Dim pixelValue As Integer = 128
Dim height As Integer = source.Height
Dim width As Integer = source.Width
Dim threshold As Integer = 650
' Iterate lines
Dim y As Integer = 0
Do While y < height
sourceIndex = y * sourceData.Stride
destinationIndex = y * destinationData.Stride
destinationValue = 0
pixelValue = 128
' Iterate pixels
Dim x As Integer = 0
Do While x < width
' Compute pixel brightness (i.e. total of Red, Green, and Blue values)
pixelTotal = CInt(sourceBuffer(sourceIndex + 1)) + CInt(sourceBuffer(sourceIndex + 2)) +
CInt(sourceBuffer(sourceIndex + 3))
If pixelTotal > threshold Then
destinationValue += CByte(pixelValue)
End If
If pixelValue = 1 Then
destinationBuffer(destinationIndex) = destinationValue
destinationIndex += 1
destinationValue = 0
pixelValue = 128
Else
pixelValue >>= 1
End If
sourceIndex += 4
x += 1
Loop
If pixelValue <> 128 Then
destinationBuffer(destinationIndex) = destinationValue
End If
y += 1
Loop
4) write buffer to destination bits all at once
unlock dest bitmap
' Copy binary image data to destination bitmap
Marshal.Copy(destinationBuffer, 0, destinationData.Scan0, imageSize)
' Unlock destination bitmap
destination.UnlockBits(destinationData)
Then do whatever with the bitmap, save to file, write to form, whatever.
This runs like 50 times faster than writing to the destination bitmap's pixels one by one.
Am I off here? I have only been doing GDI+ for a couple weeks...
thanks