How to read image pixels fast #21
Ever needed to modify/read a bitmap? Using TBitamp.Canvas.Pixels is works just fine, but when you try it with a larger bitmap you'll notice the problem.
TBitmap.Canvas.Pixels provides an easy way to access pixels but it's very slow. A way to get around this is to use ScanLine() to work on the bitmap. What do we get back? Every timem you change TBitmap.Canvas.Pixels the bitmap is redrawn. This of course consumes resources and valuable time. ScanLine() leaves this decision up to you, the programmer. There is a little catch here, though. When using Canvas.Pixels you get in return a TColor value, but when using ScanLine() you get back the bytes of the line. What does this mean? Well, you have to worry about what is Red, Green and Blue. With Canvas.Pixels you could've used GetRValue(), GetBValue() or GetGValue(), but with scan line you have to remember: each pixel is made of 3 values: Red, Green and Blue. You have to make sure you are reading the correct value.
Look at this code:
var iX : Integer; Line: PByteArray; ... Line := Image1.ScanLine; // We are scanning the first line iX := 0; // We can't use the 'for' loop because iX could not be modified from // within the loop repeat Line[iX] := Line[iX] - $F; // Red value Line[iX + 1] := Line[iX] - $F; // Green value Line[iX + 2] := Line[iX] - $F; // Blue value Inc(iX, 3); // Move to next pixel until iX > (Image1.Width - 1) * 3;
As you can see you each color is now made of 3 values, so if you miscalculate the next trio (may happen) you will be editing/reading garbage. Not only will you mix up Red, Green and Blue but you will be reading values from two neighbouring pixels.
Here's code that show how to reads the Red and Blue values and switched them.
var btTemp: Byte; // Used to swap colors iY, iX: Integer; Line : PByteArray; ... for iY := 0 to Image1.Height - 1 do begin Line := Image1.ScanLine[iY]; // Read the current line repeat btSwap := Line[iX]; // Save red value Line[iX] := Line[iX + 2]; // Switch red with blue Line[iX + 2] := btSwap; // Switch blue with previously saved red // Line[iX + 1] - Green value, not used in example Inc(iX, 3); until iX > (Image1.Width - 1) * 3; end; Image1.Invalidate; // Redraw bitmap after everything's done
The example is quite simple yet it should explain the usage of this function.
Note: This code only works with 24 bit pixel format bitmaps. You should ensure the bitmap's PixelFormat property is set to pf24bit.