Question

How can I replace color on TCanvas on Delphi XE2? The following code works incredibly slow:

  for y := ARect.Top to ARect.Top + ARect.Height - 1 do
    for x := ARect.Left to ARect.Left + ARect.Width - 1 do
      if Canvas.Pixels[x, y] = FixedColor then
        Canvas.Pixels[x, y] := Canvas.Pixels[ARect.Left, ARect.Top];
Was it helpful?

Solution 2

var
  aBitmap: TBitmap;
  x, y: Integer;
  aPixel: PRGBTriple;

 ...

  aBitmap := TBitmap.Create;
  try
    aBitmap.PixelFormat := pf24bit;
    aBitmap.Height := ARect.Height;
    aBitmap.Width := ARect.Width;
    aBitmap.Canvas.CopyRect(TRect.Create(0, 0, aBitmap.Width, aBitmap.Height), Canvas, ARect);
    for y := 0 to aBitmap.Height - 1 do
      for x := 0 to aBitmap.Width - 1 do
      begin
        aPixel := aBitmap.ScanLine[y];
        Inc(aPixel, x);
        if (aPixel^.rgbtRed = GetRValue(FixedColor)) and (aPixel^.rgbtGreen = GetGValue(FixedColor)) and (aPixel^.rgbtBlue = GetBValue(FixedColor)) then
          aPixel^ := PRGBTriple(aBitmap.ScanLine[y])^;
      end;
    Canvas.Draw(ARect.Left, ARect.Top, aBitmap);
  finally
    aBitmap.Free;
  end;

OTHER TIPS

For lazy people (like me) here is the full code.
There are two function: with/without tolerance.

Bonus:
Code to test the functions also provided (move the mouse over the TImage to see the apply the ReplaceColor on real time on the second TImage).

procedure ReplaceColor(BMP: TBitmap; OldColor, NewColor: TColor);
VAR
   x, y: Integer;
   R,G,B: Byte;
   R_,G_,B_: Byte;
   aPixel: PRGBTriple;
begin
 R:= GetRValue(OldColor);
 G:= GetGValue(OldColor);
 B:= GetBValue(OldColor);

 R_:= GetRValue(NewColor);
 G_:= GetGValue(NewColor);
 B_:= GetBValue(NewColor);

 BMP.PixelFormat := pf24bit;
 for y := 0 to BMP.Height - 1 do
  for x := 0 to BMP.Width - 1 do
   begin
     aPixel := BMP.ScanLine[y];
     Inc(aPixel, x);
     if  (aPixel^.rgbtRed   = R)
     AND (aPixel^.rgbtGreen = G)
     AND (aPixel^.rgbtBlue  = B) then
      begin
       aPixel^.rgbtRed   := R_;
       aPixel^.rgbtGreen := G_;
       aPixel^.rgbtBlue  := B_;
      end;
   end;
end;


procedure ReplaceColor(BMP: TBitmap; OldColor, NewColor: TColor; ToleranceR, ToleranceG, ToleranceB: Byte);
VAR
   x, y: Integer;
   R,G,B: Byte;
   R_,G_,B_: Byte;
   aPixel: PRGBTriple;
begin
 R:= GetRValue(OldColor);
 G:= GetGValue(OldColor);
 B:= GetBValue(OldColor);

 R_:= GetRValue(NewColor);
 G_:= GetGValue(NewColor);
 B_:= GetBValue(NewColor);

 BMP.PixelFormat := pf24bit;
 for y := 0 to BMP.Height - 1 do
  for x := 0 to BMP.Width - 1 do
   begin
     aPixel := BMP.ScanLine[y];
     Inc(aPixel, x);
     if  (abs(aPixel^.rgbtRed  - R)< ToleranceR)
     AND (abs(aPixel^.rgbtGreen- G)< ToleranceG)
     AND (abs(aPixel^.rgbtBlue - B)< ToleranceB) then
      begin
       aPixel^.rgbtRed   := R_;
       aPixel^.rgbtGreen := G_;
       aPixel^.rgbtBlue  := B_;
      end;
   end;
end;


procedure TfrmTester.imgReplaceOrigMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
VAR
   Pixel: TColor;
   BMP: TBitmap;
begin
  Pixel := imgReplaceOrig.Picture.Bitmap.Canvas.Pixels[x, y];
  pnlTop.Color:= Pixel;
  if Pixel < 0 then EXIT;

  Label1.Caption := 'x'+IntToStr(X)+':y='
         + IntToStr(Y)
         +'  r'+ IntToStr(GetRValue(Pixel))
         +', g'+ IntToStr(GetGValue(Pixel))
         +', b'+ IntToStr(GetBValue(Pixel));

 BMP:= TBitmap.Create;
 BMP.Assign(imgReplaceOrig.Picture.Bitmap);
 cGraphUtil.ReplaceColor(BMP, Pixel, clBlue, 44, 44, 44);
 imgReplace.Picture.Assign(BMP);
 FreeAndNil(BMP);
end;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top