2008. március 25., kedd

Invert colors in a TImage


Problem/Question/Abstract:

Is there an easy way to invert the colors in a TImage? I have a bitmap that is a black background with white text and I want it to be a white background with black text.

Answer:

Solve 1:

Ok, first we need a little theory of how an image is represented in the screen, computers use a color model in which images are represented in pixels (picture elements), each pixel can be represented with a pixel depth, in other words, the information of each pixel can be stored in diferent number of bits.

For example images with a pixel depth of 8 bits can store a maximum of 256 colors since each bit can have one of two values (0 or 1), we have 2x2x2x2x2x2x2x2 = 256.

Nowadays we have images of 24 and even 32 pixels depth, I will cover how to obtain invert the color of only this kind of images.

The RGB color model (where R=Red, G=Green, and B=Blue) threats an image of 24 pixels depth, as it is divided in 3 color chanels, where each chanel consits of 8 bits, and once again we have up to 256 posible values for each chanel, if we add the three chanels we have the final representation of the image.

Ok, enough theory, we can acomplish that with the following procedure:

procedure InvertImage(const AnImage: TImage);
var
  BytesPorScan: integer;
  vi_width, vi_height: integer;
  p: pByteArray;
begin
  //This only works with images of 24 or 32 bits per pixel
  if not (AnImage.Picture.Bitmap.PixelFormat in [pf24Bit, pf32Bit]) then
    raise exception.create('Error, Format File not soported!');

  try
    BytesPorScan := Abs(Integer(AnImage.Picture.Bitmap.ScanLine[1]) -
      Integer(AnImage.Picture.Bitmap.ScanLine[0]));
  except
    raise exception.create('Error');
  end;

  //Invert the RGB for each pixel
  for vi_height := 0 to AnImage.Picture.Bitmap.Height - 1 do
  begin
    P := AnImage.Picture.Bitmap.ScanLine[vi_height];
    for vi_width := 0 to BytesPorScan - 1 do
      P^[vi_width] := 255 - P^[vi_width];
  end;
  AnImage.Refresh;
end;

the important part is the for loop, since the values for each color chanel can vary from 0 to 255, whe only have to substract the actual value of the pixel (P^[vi_width) from 255 to obtain the inverse color, and assign this new value to the pixel.


Solve 2:

begin
  Image1.Canvas.CopyMode := cmDstInvert;
  Image1.Canvas.CopyRect(Image1.ClientRect, Image1.Canvas, Image1.ClientRect);
  imgZoom.Canvas.CopyMode := cmSrcCopy;
end


Solve 3:

var
  R: TRect;
begin
  { ... }
  with Image1.Picture.Bitmap do
  begin
    R := Rect(0, 0, Width, Height);
    InvertRect(Canvas.Handle, R);
  end;
  Image1.Invalidate;
  { ... }

Nincsenek megjegyzések:

Megjegyzés küldése