Solved: Png Grayscale (Got vertical line artifacts) lazarus / 39-Graphics ---------------------------------------------------------------------- Boleeman · 2024-05-17 13:41 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     procedure GrayBuffer(ABuffer: TBitmap);    type      //TBitmapPixel = record B, G, R: UInt8 end;  // For RGB        TBitmapPixel = record B, G, R, A: UInt8 end;   // For ARGB    type      PBitmapLine = ^TBitmapLine;      TBitmapLine = array [UInt16] of TBitmapPixel;    var      Line: PBitmapLine;      LineIndex, PixelIndex: Integer;      GrayShade: UInt8;    begin      ABuffer.BeginUpdate();           for LineIndex := 0 to ABuffer.Height - 1 do      begin        Line := ABuffer.ScanLine[LineIndex];             for PixelIndex := 0 to ABuffer.Width - 1 do          with Line^[PixelIndex] do          begin            GrayShade := Round(0.299 * R + 0.587 * G + 0.114 * B);                     B := GrayShade;            G := GrayShade;          R := GrayShade;          end;      end;           ABuffer.EndUpdate();    end; Now used this working code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, LCLType, FPImage,  IntfGraphics, StdCtrls; type   { TForm1 }   TForm1 = class(TForm)    btnTograyscale: TButton;    OpenDialog1: TOpenDialog;    procedure btnTograyscaleClick(Sender: TObject);  private   public   end; var  Form1: TForm1; implementation {$R *.lfm} procedure GrayBuffer(ABuffer: TBitmap);type  //TBitmapPixel = record B, G, R: UInt8 end;   TBitmapPixel = record B, G, R, A: UInt8 end;type  PBitmapLine = ^TBitmapLine;  TBitmapLine = array [UInt16] of TBitmapPixel;var  Line: PBitmapLine;  LineIndex, PixelIndex: Integer;  GrayShade: UInt8;begin  ABuffer.BeginUpdate();   for LineIndex := 0 to ABuffer.Height - 1 do  begin    Line := ABuffer.ScanLine[LineIndex];     for PixelIndex := 0 to ABuffer.Width - 1 do      with Line^[PixelIndex] do      begin      GrayShade := Round(0.299 * R + 0.587 * G + 0.114 * B);         B := GrayShade;        G := GrayShade;        R := GrayShade;      end;  end;   ABuffer.EndUpdate();end; { TForm1 } procedure TForm1.btnTograyscaleClick(Sender: TObject);var  PNGImage: TPortableNetworkGraphic;  GrayscaleBitmap: TBitmap;  OpenDialog: TOpenDialog;begin  PNGImage := TPortableNetworkGraphic.Create;  GrayscaleBitmap := TBitmap.Create;  OpenDialog := TOpenDialog.Create(nil);   try    // Configure the OpenDialog    OpenDialog.Filter := 'PNG Files|*.png';    OpenDialog.Title := 'Select a PNG File';     // If the user selects a file and clicks OK    if OpenDialog.Execute then    begin      // Load the selected PNG file into the PNGImage object      PNGImage.LoadFromFile(OpenDialog.FileName);       // Load the PNG image into a TBitmap object      GrayscaleBitmap.Assign(PNGImage);     // Convert the TBitmap to grayscale      GrayBuffer(GrayscaleBitmap);       // Display the grayscale image on the form      Canvas.Draw(0, 0, GrayscaleBitmap);       // Save the grayscale image as gray_myimage.png using PNG format      PNGImage.Assign(GrayscaleBitmap);      PNGImage.SaveToFile('gray_myimage.png');    end;  finally    OpenDialog.Free;    GrayscaleBitmap.Free;    PNGImage.Free;  end;end; end.  All solved now ! ---------------------------------------------------------------------- Ally · 2024-05-17 14:09 Hello Boleeman, here is an example program. The conversion to grayscale is done by the unit rhsBitmapGrayscale.pas Greetings Roland ---------------------------------------------------------------------- wp · 2024-05-17 14:35 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i     type    TBitmapPixel = record B, G, R, A: UInt8 end; 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. ---------------------------------------------------------------------- Boleeman · 2024-05-17 14:51 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.