Below are two procedures that I use to darken or lighten entire 24-bit bitmaps in the
Deep Platformer project. They are very effective due to the use of
ScanLine. If you are not interested in modifying the brightness of the whole bitmap, focus on three lines performing calculations (I highlighted them).
The second parameter is the level of dimming/lightening, which can have a value from
0 to
255.
0 means that nothing will be changed, and
255 means full darkening or brightening. So the higher the value of this parameter, the stronger the change.
type
TBitmapPixel = record
B, G, R: UInt8;
end;
type
PBitmapLine = ^TBitmapLine;
TBitmapLine = array [UInt16] of TBitmapPixel;
procedure DarkenBuffer(ABuffer: TBitmap; ALevel: UInt8);
var
Line: PBitmapLine;
LineIndex, PixelIndex: Integer;
begin
ALevel := 255 - ALevel;
ABuffer.BeginUpdate();
for LineIndex := 0 to ABuffer.Height - 1 do
begin
Line := ABuffer.ScanLine[LineIndex];
for PixelIndex := 0 to ABuffer.Width - 1 do
with Line^[PixelIndex] do
begin
B := B * ALevel shr 8;
G := G * ALevel shr 8;
R := R * ALevel shr 8;
end;
end;
ABuffer.EndUpdate();
end;
procedure LightenBuffer(ABuffer: TBitmap; ALevel: UInt8);
var
Line: PBitmapLine;
LineIndex, PixelIndex: Integer;
begin
ALevel := 255 - ALevel;
ABuffer.BeginUpdate();
for LineIndex := 0 to ABuffer.Height - 1 do
begin
Line := ABuffer.ScanLine[LineIndex];
for PixelIndex := 0 to ABuffer.Width - 1 do
with Line^[PixelIndex] do
begin
B := Round(B * ALevel / 255 + 255 - ALevel);
G := Round(G * ALevel / 255 + 255 - ALevel);
R := Round(R * ALevel / 255 + 255 - ALevel);
end;
end;
ABuffer.EndUpdate();
end;
If you are interested in the percentage mixing of two colors, below is a simple procedure for doing this task. The parameter determining the level of mixing is the percentage, i.e. a value from
0 to
100:
type
TRGBTriple = packed record
B, G, R: UInt8;
end;
function CombineColors(AColorA, AColorB: TColor; APercent: UInt8): TColor;
var
ColorA, ColorB, ColorDest: TRGBTriple;
begin
RedGreenBlue(AColorA, ColorA.R, ColorA.G, ColorA.B);
RedGreenBlue(AColorB, ColorB.R, ColorB.G, ColorB.B);
ColorDest.R := Round(ColorA.R + (ColorB.R - ColorA.R) / 100 * APercent);
ColorDest.G := Round(ColorA.G + (ColorB.G - ColorA.G) / 100 * APercent);
ColorDest.B := Round(ColorA.B + (ColorB.B - ColorA.B) / 100 * APercent);
Result := RGBToColor(ColorDest.R, ColorDest.G, ColorDest.B);
end;
This algorithm is useful — with it you can combine two images and create a smooth transition between them:
procedure CombineImages(AImageA, AImageB, AImageDest: TPortableNetworkGraphic; ALevel, AScale: UInt8);
type
PPNGPixel = ^TPNGPixel;
TPNGPixel = record B, G, R, A: UInt8; end;
type
PPNGLine = ^TPNGLine;
TPNGLine = array [UInt16] of TPNGPixel;
var
LineA, LineB, LineDest: PPNGLine;
PixelA, PixelB, PixelDest: PPNGPixel;
var
LineIndex, PixelIndex: Integer;
begin
AImageDest.BeginUpdate();
try
for LineIndex := 0 to AImageA.Height - 1 do
begin
LineA := AImageA.ScanLine[LineIndex];
LineB := AImageB.ScanLine[LineIndex];
LineDest := AImageDest.ScanLine[LineIndex];
for PixelIndex := 0 to AImageA.Width - 1 do
begin
PixelA := @LineA^[PixelIndex];
PixelB := @LineB^[PixelIndex];
PixelDest := @LineDest^[PixelIndex];
PixelDest^.R := Round(PixelA^.R + (PixelB^.R - PixelA^.R) / AScale * ALevel);
PixelDest^.G := Round(PixelA^.G + (PixelB^.G - PixelA^.G) / AScale * ALevel);
PixelDest^.B := Round(PixelA^.B + (PixelB^.B - PixelA^.B) / AScale * ALevel);
end;
end;
finally
AImageDest.EndUpdate();
end;
end;
This time the procedure operates on 24-bit PNG images, but nothing prevents you from adding alpha channel support or bitmap support. The first two parameters are source images, the third parameter is the target image.
The
AScale parameter determines the sensitivity and can have a value e.g.
100 (percentage mixing) or another value, e.g.
255. The
ALevel parameter specifies the level of color mixing and must be between
0 and
AScale. The higher the
AScale value, the more levels of color mixing available.
To the attachments I add the sources of both small tools, which I created a long time ago to test the above two algorithms (used on Windows). Feel free to use them.