Recent

Author Topic: [SOLVED] Create and save PNG  (Read 4937 times)

tk

  • Sr. Member
  • ****
  • Posts: 357
[SOLVED] Create and save PNG
« on: December 30, 2016, 12:53:20 pm »
Hi, I would like to create a new PNG image, modify its pixels and save it. I adapted code from following example (http://wiki.lazarus.freepascal.org/Developing_with_Graphics#Drawing_text_with_sharp_edges_.28non_antialiased.29) but it does not work properly, alpha channel is not respected:

Code: Pascal  [Select][+][-]
  1. uses
  2.   IntfGraphics, FPImage;
  3.  
  4. { TForm1 }
  5.  
  6. procedure TForm1.Button1Click(Sender: TObject);
  7. var
  8.   I, J, W, H: Integer;
  9.   FC: TFPColor;
  10.   IM: TLazIntfImage;
  11.   Png: TPortableNetworkGraphic;
  12. begin
  13.   W := 32;
  14.   H := 32;
  15.   Png := TPortableNetworkGraphic.Create;
  16.   try
  17.     Png.SetSize(W, H);
  18.     IM := Png.CreateIntfImage;
  19.     try
  20.       for I := 0 to W - 1 do
  21.       begin
  22.         for J := 0 to H - 1 do
  23.         begin
  24.           FC.red := (128 + I) shl 8;
  25.           FC.green := (128 + J) shl 8;
  26.           FC.blue := 128 shl 8;
  27.           FC.alpha := 128 shl 8; // no matter what value here, always get full opacity
  28.           IM.Colors[I, J] := FC;
  29.         end;
  30.       end;
  31.       Png.LoadFromIntfImage(IM);
  32.     finally
  33.       IM.Free;
  34.     end;
  35.     Png.SaveToFile('test.png');
  36.   finally
  37.     Png.Free;
  38.   end;
  39. end;

Bug?
« Last Edit: December 30, 2016, 02:49:32 pm by tk »

derek.john.evans

  • Guest
Re: Create and save PNG
« Reply #1 on: December 30, 2016, 02:05:50 pm »
TPortableNetworkGraphic.CreateIntfImage doesn't create an image that supports alpha. It also loads the PNG into the image, which isn't required if you are creating a new image.

Also, you dont need TPortableNetworkGraphic, since TLazIntfImage will load/save png/jpeg/etc.

So, try this:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   X, Y: integer;
  4.   LColor: TFPColor;
  5.   LImage: TLazIntfImage;
  6. begin
  7.   LImage := TLazIntfImage.Create(0, 0, [riqfRGB, riqfAlpha]);
  8.   try
  9.     LImage.SetSize(32, 32);
  10.     for X := 0 to LImage.Width - 1 do begin
  11.       for Y := 0 to LImage.Height - 1 do begin
  12.         LColor.red := (128 + X) shl 8;
  13.         LColor.green := (128 + Y) shl 8;
  14.         LColor.blue := 128 shl 8;
  15.         LColor.alpha := 200 shl 8; // no matter what value here, always get full opacity
  16.         LImage.Colors[X, Y] := LColor;
  17.       end;
  18.     end;
  19.     LImage.SaveToFile('test.png');
  20.   finally
  21.     LImage.Free;
  22.   end;
  23. end;  
  24.  

NOTE: There does seem to be a bug in TLazIntfImage which I've know about for a while. You cant provide a width/height via the constructor.

Hence the additional SetSize() command.

derek.john.evans

  • Guest
Re: Create and save PNG
« Reply #2 on: December 30, 2016, 02:12:40 pm »
O, bugger. You do need TPortableNetworkGraphic. TLazIntfImage.SaveToFile() doesn't save the alpha.

So, yes, you also need todo:
Code: Pascal  [Select][+][-]
  1.     with TPortableNetworkGraphic.Create do begin
  2.       try
  3.         LoadFromIntfImage(LImage);
  4.         SaveToFile('test.png');
  5.       finally
  6.         Free;
  7.       end;
  8.     end;  
  9.  

tk

  • Sr. Member
  • ****
  • Posts: 357
Re: Create and save PNG
« Reply #3 on: December 30, 2016, 02:49:18 pm »
Hi Geepster, thank you, it works now.

Summarized to my example:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   I, J, W, H: Integer;
  4.   FC: TFPColor;
  5.   IM: TLazIntfImage;
  6.   Png: TPortableNetworkGraphic;
  7. begin
  8.   W := 32;
  9.   H := 32;
  10.   Png := TPortableNetworkGraphic.Create;
  11.   try
  12.     IM := TLazIntfImage.Create(0, 0, [riqfRGB, riqfAlpha]);
  13.     try
  14.       IM.SetSize(W, H);
  15.       for I := 0 to W - 1 do
  16.       begin
  17.         for J := 0 to H - 1 do
  18.         begin
  19.           FC.red := (128 + I) shl 8;
  20.           FC.green := (128 + J) shl 8;
  21.           FC.blue := 128 shl 8;
  22.           FC.alpha := 128 shl 8; // now works fine
  23.           IM.Colors[I, J] := FC;
  24.         end;
  25.       end;
  26.       Png.LoadFromIntfImage(IM);
  27.     finally
  28.       IM.Free;
  29.     end;
  30.     Png.SaveToFile('test.png');
  31.   finally
  32.     Png.Free;
  33.   end;
  34. end;
  35.  

geraldholdsworth

  • Jr. Member
  • **
  • Posts: 92
Re: [SOLVED] Create and save PNG
« Reply #4 on: April 09, 2021, 09:54:49 am »
I found this when looked at how to do something similar. What it doesn't mention above is what units are required (as I kept getting 'Identifier unknown' for riqfRGB and riqfAlpha). I was also needing to convert to bitmap and show on screen rather than save it. So, using the above as a basis and some other code I was given, I knocked the following up:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.CreatePNG;
  2. //Requires FPImage,IntfGraphics,GraphType in uses clause
  3. var
  4.  img: TLazIntfImage;
  5.  png: TPortableNetworkGraphic;
  6.  col: TFPColor;
  7.  x,y: Integer;
  8. begin
  9.  //Creates and fills a PNG, then converts to BMP
  10.  png:=TPortableNetworkGraphic.Create;
  11.  png.PixelFormat:=pf32bit; //32bpp is required for the alpha channel
  12.  img:=TLazIntfImage.Create(0,0,[riqfRGB, riqfAlpha]);
  13.  img.SetSize(256,256);
  14.  for y:=0 to img.Height-1 do
  15.   for x:=0 to img.Width-1 do
  16.   begin
  17.    // $FF is non-transparent down to $00 fully transparent
  18.    col.Alpha:=(128-(x div 2))+(128-(y div 2));
  19.    col.Red  :=x;
  20.    col.Green:=y;
  21.    col.Blue :=(128-(x div 2))+(128-(y div 2));
  22.    //TFPColor is 16 bit per colour
  23.    col.Alpha:=col.Alpha or col.Alpha<<8;
  24.    col.Red  :=col.Red or col.Red<<8;
  25.    col.Green:=col.Green or col.Green<<8;
  26.    col.Blue :=col.Blue or col.Blue<<8;
  27.    //Set the pixel colour
  28.    img.Colors[x,y]:=col;
  29.   end;
  30.  //Save to PNG
  31.  png.LoadFromIntfImage(img);
  32.  //And to file
  33.  png.SaveToFile('Test.png');
  34.  //Load into the picture, so we can see it...and convert to BMP at the same time
  35.  Image2.Picture.Bitmap.PixelFormat:=pf32bit;
  36.  Image2.Picture.Bitmap.Assign(png);
  37.  //Save to file
  38.  Image2.Picture.Bitmap.SaveToFile('Test.bmp');
  39.  img.Free;
  40.  png.Free;
  41. end;

Produces a nice image too - quite random. I then spent ages trying to get fully Blue eminating from the top left, fully Red from the top right and fully Green from the bottom left. I just added a fading Alpha from the bottom right as an afterthought.

 

TinyPortal © 2005-2018