Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

converting a PNGImage to grayscale using delphi

hi there here it is my code:

procedure TForm4.Button1Click(Sender: TObject);
var
  png: TPNGImage;
  data: PRGBQarray;
  p: ^tagRGBQuad;
  i, o: integer;
begin
  png := TPNGImage.Create;
  try
    png.LoadFromFile('C:\Untitled.png');
    for o := 1 to 100 do
    begin
      data:=png.Scanline[o];
      for I := 1 to 400 do
      begin
        p := @data^[i];
        p.rgbGreen := p.rgbBlue;
        p.rgbRed := p.rgbGreen;
      end;
    end;
    img.picture.Assign(png);
  finally
    png.Free;
  end;
end;

it doesn't work and it makes the pic messy, I'm sure it's because of the rgbReserved. what should i do?

like image 788
Javid Avatar asked Nov 30 '22 09:11

Javid


2 Answers

This is how to greyify a bitmap. (And, yes, if you want to greyify a PNG, you first need to get the bitmap data out of it. I think the VCL will do this for you.)

type
  PRGB32Array = ^TRGB32Array;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGBQuad)-1] of TRGBQuad;

procedure MakeGrey(Bitmap: TBitmap);
var
  w, h: integer;
  y: Integer;
  sl: PRGB32Array;
  x: Integer;
  grey: byte;
begin
  Bitmap.PixelFormat := pf32bit;
  w := Bitmap.Width;
  h := Bitmap.Height;
  for y := 0 to h - 1 do
  begin
    sl := Bitmap.ScanLine[y];
    for x := 0 to w - 1 do
      with sl[x] do
      begin
        grey := (rgbBlue + rgbGreen + rgbRed) div 3;
        rgbBlue := grey;
        rgbGreen := grey;
        rgbRed := grey;
      end;
  end;
end;

Sample usage:

procedure TForm4.Button1Click(Sender: TObject);
var
  bm: TBitmap;
begin
  bm := TBitmap.Create;
  try
    bm.LoadFromFile('C:\Users\Andreas Rejbrand\Pictures\Porträtt, litet, kvadratiskt.bmp');
    MakeGrey(bm);
    Canvas.Draw(0, 0, bm);
  finally
    bm.Free;
  end;
end;
like image 199
Andreas Rejbrand Avatar answered Dec 04 '22 11:12

Andreas Rejbrand


Andreas's answer will give you a good, fast approximation, but you'll lose some quality, because red, green and blue don't mix with equal intensities in the human eye. If you want to "get it right", instead of

grey := (rgbBlue + rgbGreen + rgbRed) div 3;

try this:

grey := round(rgbRed * .3) + round(rgbGreen * .59) + round(rgbBlue * .11);

You'll get a bit of a performance hit over the simple average, though it probably won't be noticeable unless you're on a very large image.

like image 20
Mason Wheeler Avatar answered Dec 04 '22 12:12

Mason Wheeler