change a bitmap's pixel colour

delphi, image

Solution

You should use scanlines for this. Example:

procedure ChangeWhiteToBlack(var Bitmap: TBitmap);
var
  scanline: PRGBTriple;
  y: Integer;
  x: Integer;
begin
  Assert(Bitmap.PixelFormat = pf24bit);
  for y := 0 to Bitmap.Height - 1 do
  begin
    scanline := Bitmap.ScanLine[y];
    for x := 0 to Bitmap.Width - 1 do
    begin
      with scanline^ do
      begin
        if (rgbtBlue = 255) and (rgbtGreen = 255) and (rgbtRed = 255) then
          FillChar(scanline^, sizeof(TRGBTriple), 0);
      end;
      inc(scanline);
    end;
  end;
end;

To try this:

procedure TForm5.FormCreate(Sender: TObject);
var
  bm: TBitmap;
begin
  bm := TBitmap.Create;
  try
    bm.LoadFromFile('C:\Users\Andreas Rejbrand\Desktop\test.bmp');
    ChangeWhiteToBlack(bm);
    bm.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\test2.bmp');
  finally
    bm.Free;
  end;
end;

Update: You need only a very minor modification of the code to make it work on 32-bit bitmaps instead:

procedure ChangeWhiteToBlack32(var Bitmap: TBitmap);
var
  scanline: PRGBQuad;
  y: Integer;
  x: Integer;
begin
  Assert(Bitmap.PixelFormat = pf32bit);
  for y := 0 to Bitmap.Height - 1 do
  begin
    scanline := Bitmap.ScanLine[y];
    for x := 0 to Bitmap.Width - 1 do
    begin
      with scanline^ do
      begin
        if (rgbBlue = 255) and (rgbGreen = 255) and (rgbRed = 255) then
          FillChar(scanline^, sizeof(TRGBQuad), 0);
      end;
      inc(scanline);
    end;
  end;
end;

In fact, you could do

procedure ChangeWhiteToBlack24(var Bitmap: TBitmap);
var
  scanline: PRGBTriple;
  y: Integer;
  x: Integer;
begin
  Assert(Bitmap.PixelFormat = pf24bit);
  for y := 0 to Bitmap.Height - 1 do
  begin
    scanline := Bitmap.ScanLine[y];
    for x := 0 to Bitmap.Width - 1 do
    begin
      with scanline^ do
      begin
        if (rgbtBlue = 255) and (rgbtGreen = 255) and (rgbtRed = 255) then
          FillChar(scanline^, sizeof(TRGBTriple), 0);
      end;
      inc(scanline);
    end;
  end;
end;

procedure ChangeWhiteToBlack32(var Bitmap: TBitmap);
var
  scanline: PRGBQuad;
  y: Integer;
  x: Integer;
begin
  Assert(Bitmap.PixelFormat = pf32bit);
  for y := 0 to Bitmap.Height - 1 do
  begin
    scanline := Bitmap.ScanLine[y];
    for x := 0 to Bitmap.Width - 1 do
    begin
      with scanline^ do
      begin
        if (rgbBlue = 255) and (rgbGreen = 255) and (rgbRed = 255) then
          FillChar(scanline^, sizeof(TRGBQuad), 0);
      end;
      inc(scanline);
    end;
  end;
end;

procedure ChangeWhiteToBlack(var Bitmap: TBitmap);
begin
  case Bitmap.PixelFormat of
    pf24bit: ChangeWhiteToBlack24(Bitmap);
    pf32bit: ChangeWhiteToBlack32(Bitmap);
  else
    raise Exception.Create('Pixel format must be pf24bit or pf32bit.');
  end;
end;

if you don't want to make a single procedure that works with both 24-bit and 32-bit bitmaps, as `TLama` did. [One benefit of having two separate procedures is that these short procedures are easier to read (and maintain).]

Problem

I am trying to change a bit-map's pixel color if it's white. I wrote following code. But it's awfully slow!. i want to check if a pixel's color is white or not, and if it is white, change the color to black. Can anybody suggest a better approach? ``` procedure TForm1.Button1Click(Sender: TObject); var BitMap1 : TBitmap; X, Y, Size : Integer; P: Cardinal; begin BitMap1 := TBitmap.Create; bitMap1.LoadFromFile('image1.bmp'); for Y := 0 to Bitmap1.Height - 1 do begin for X := 0 to Bitmap1.width * size - 1 do begin p := BitMap1.Canvas.Pixels[X,Y]; if p = 255 then BitMap1.Canvas.Pixels[X,Y] := 0; end; end; Image1.Picture.Assign(BitMap1); end; ```

Original source

Related problems