change a bitmap's pixel colour

前端 未结 4 1783
鱼传尺愫
鱼传尺愫 2020-12-10 07:04

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 i

4条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-10 07:39

    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).]

提交回复
热议问题