Recent

Author Topic: Solved: Png Grayscale (Got vertical line artifacts)  (Read 387 times)

Boleeman

  • Hero Member
  • *****
  • Posts: 524
Solved: Png Grayscale (Got vertical line artifacts)
« on: May 17, 2024, 03:41:04 pm »
I was playing around with the grayscale code from https://forum.lazarus.freepascal.org/index.php?topic=50124.0

It stated: "Fastest way, no external libraries needed, no temporary image needed, good final quality:"

Solved by adding TBitmapPixel = record B, G, R, A: UInt8 end;     Thanks to WP.

Code: Pascal  [Select][+][-]
  1.     procedure GrayBuffer(ABuffer: TBitmap);
  2.     type
  3.       //TBitmapPixel = record B, G, R: UInt8 end;  // For RGB
  4.         TBitmapPixel = record B, G, R, A: UInt8 end;   // For ARGB
  5.     type
  6.       PBitmapLine = ^TBitmapLine;
  7.       TBitmapLine = array [UInt16] of TBitmapPixel;
  8.     var
  9.       Line: PBitmapLine;
  10.       LineIndex, PixelIndex: Integer;
  11.       GrayShade: UInt8;
  12.     begin
  13.       ABuffer.BeginUpdate();
  14.      
  15.       for LineIndex := 0 to ABuffer.Height - 1 do
  16.       begin
  17.         Line := ABuffer.ScanLine[LineIndex];
  18.      
  19.         for PixelIndex := 0 to ABuffer.Width - 1 do
  20.           with Line^[PixelIndex] do
  21.           begin
  22.             GrayShade := Round(0.299 * R + 0.587 * G + 0.114 * B);
  23.          
  24.             B := GrayShade;
  25.             G := GrayShade;
  26.             R := GrayShade;
  27.           end;
  28.       end;
  29.      
  30.       ABuffer.EndUpdate();
  31.     end;


Now used this working code:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, LCLType, FPImage,
  9.   IntfGraphics, StdCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     btnTograyscale: TButton;
  17.     OpenDialog1: TOpenDialog;
  18.     procedure btnTograyscaleClick(Sender: TObject);
  19.   private
  20.  
  21.   public
  22.  
  23.   end;
  24.  
  25. var
  26.   Form1: TForm1;
  27.  
  28. implementation
  29.  
  30. {$R *.lfm}
  31.  
  32. procedure GrayBuffer(ABuffer: TBitmap);
  33. type
  34.   //TBitmapPixel = record B, G, R: UInt8 end;
  35.    TBitmapPixel = record B, G, R, A: UInt8 end;
  36. type
  37.   PBitmapLine = ^TBitmapLine;
  38.   TBitmapLine = array [UInt16] of TBitmapPixel;
  39. var
  40.   Line: PBitmapLine;
  41.   LineIndex, PixelIndex: Integer;
  42.   GrayShade: UInt8;
  43. begin
  44.   ABuffer.BeginUpdate();
  45.  
  46.   for LineIndex := 0 to ABuffer.Height - 1 do
  47.   begin
  48.     Line := ABuffer.ScanLine[LineIndex];
  49.  
  50.     for PixelIndex := 0 to ABuffer.Width - 1 do
  51.       with Line^[PixelIndex] do
  52.       begin
  53.         GrayShade := Round(0.299 * R + 0.587 * G + 0.114 * B);
  54.  
  55.         B := GrayShade;
  56.         G := GrayShade;
  57.         R := GrayShade;
  58.       end;
  59.   end;
  60.  
  61.   ABuffer.EndUpdate();
  62. end;
  63.  
  64. { TForm1 }
  65.  
  66. procedure TForm1.btnTograyscaleClick(Sender: TObject);
  67. var
  68.   PNGImage: TPortableNetworkGraphic;
  69.   GrayscaleBitmap: TBitmap;
  70.   OpenDialog: TOpenDialog;
  71. begin
  72.   PNGImage := TPortableNetworkGraphic.Create;
  73.   GrayscaleBitmap := TBitmap.Create;
  74.   OpenDialog := TOpenDialog.Create(nil);
  75.  
  76.   try
  77.     // Configure the OpenDialog
  78.     OpenDialog.Filter := 'PNG Files|*.png';
  79.     OpenDialog.Title := 'Select a PNG File';
  80.  
  81.     // If the user selects a file and clicks OK
  82.     if OpenDialog.Execute then
  83.     begin
  84.       // Load the selected PNG file into the PNGImage object
  85.       PNGImage.LoadFromFile(OpenDialog.FileName);
  86.  
  87.       // Load the PNG image into a TBitmap object
  88.       GrayscaleBitmap.Assign(PNGImage);
  89.  
  90.       // Convert the TBitmap to grayscale
  91.       GrayBuffer(GrayscaleBitmap);
  92.  
  93.       // Display the grayscale image on the form
  94.       Canvas.Draw(0, 0, GrayscaleBitmap);
  95.  
  96.       // Save the grayscale image as gray_myimage.png using PNG format
  97.       PNGImage.Assign(GrayscaleBitmap);
  98.       PNGImage.SaveToFile('gray_myimage.png');
  99.     end;
  100.   finally
  101.     OpenDialog.Free;
  102.     GrayscaleBitmap.Free;
  103.     PNGImage.Free;
  104.   end;
  105. end;
  106.  
  107. end.
  108.  




All solved now !

« Last Edit: May 17, 2024, 05:02:08 pm by Boleeman »

Ally

  • Jr. Member
  • **
  • Posts: 54
Re: Png Grayscale: Got vertical line artifacts
« Reply #1 on: May 17, 2024, 04:09:43 pm »
Hello Boleeman,

here is an example program.
The conversion to grayscale is done by the unit rhsBitmapGrayscale.pas

Greetings
Roland

wp

  • Hero Member
  • *****
  • Posts: 12067
Re: Png Grayscale: Got vertical line artifacts
« Reply #2 on: May 17, 2024, 04:35:24 pm »
When you work with Canvas.Scanline you must know what you are doing. A png image very probably has 4 color channels (red, green, blue, and alpha - 32 bits per pixel); the alpha (transparency) channel is why the png format has become so popular. The TBitmapPixel record in your code, however, has only three elements (B, G, R)! Probably, adding a 4th element (A) to the record should fix the issue:
Code: Pascal  [Select][+][-]
  1.     type
  2.       TBitmapPixel = record B, G, R, A: UInt8 end;
  3.  
BUT: Without further investigation, I would not know whether the A should be added as first or as last record element, and I also would not be able to sware that this is correct in all widgetsets. So - I don't know what I am doing, and I'd use a well-tested method written by others instead.

Ally's method, BitmapGrayscale, BTW has been included in the GraphUtil unit of Lazarus 3.0x.
« Last Edit: May 17, 2024, 05:00:54 pm by wp »

Boleeman

  • Hero Member
  • *****
  • Posts: 524
Re: Png Grayscale: Got vertical line artifacts
« Reply #3 on: May 17, 2024, 04:51:20 pm »
Thanks Roland and WP.

WP, The png I was using had alpha.  You were correct TBitmapPixel = record B, G, R, A: UInt8 end;  solved it.
       Also Thanks for the conversion of GeoPattern. Was so happy playing with it.

Roland, got and error at if ImageSource.HasGraphic then , but found a slightly different version of your gray scaler so I replaced:

procedure TForm1.Scale;
begin
  if ImageSource.HasGraphic then
    ImageScaled.Picture.Assign(ImageSource.Picture)
  else
    Exit;

  if (ImageScaled.Picture.Width / ImageScaled.Picture.Height) > (Panel1.Width / Panel1.Height) then
    BitmapScale(ImageScaled.Picture.Bitmap, Panel1.Width, 0)
  else
    BitmapScale(ImageScaled.Picture.Bitmap, 0, Panel1.Height);
end; 



with


procedure TForm1.Scale;
begin
  ImageScaled.Picture.Assign(ImageSource.Picture);
  if (ImageSource.Picture.Width > Panel1.Width) or (ImageSource.Picture.Height > Panel1.Height) then
    if (ImageScaled.Picture.Width / ImageScaled.Picture.Height) > (Panel1.Width / Panel1.Height) then
      BitmapScale(ImageScaled.Picture.Bitmap, Panel1.Width, 0)
    else
      BitmapScale(ImageScaled.Picture.Bitmap, 0, Panel1.Height);
end;   

Many thanks Roland for that.
Also thanks for the Vector version of Spiral of Theodorus. Much appreciated.





« Last Edit: May 17, 2024, 04:55:06 pm by Boleeman »

 

TinyPortal © 2005-2018