Recent

Author Topic: BGRABitmap to TImage fault  (Read 3302 times)

schlueter550v

  • New member
  • *
  • Posts: 9
BGRABitmap to TImage fault
« on: April 22, 2021, 10:01:04 am »
Hello Lazarus Community,

this is my first post, and i hope i get good help. I am very new to Lazarus and ObjPascal, please be kind if i do simple stuff wrong.
To the Problem i have i found nothing in the Wiki nor the Forum.

I am currently doing experiments with BGRABitmap. I simply want to load an image from the clipboard and put it into a TBGRABitmap variable. Later i want to do something with this image, but in my test Code i want to show the TBGRABitmap variable in an Timage on the Form.

this is my current button function:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.btnClipboardClick(Sender: TObject);
  2. var
  3.   image : TBGRABitmap;
  4.   pic : TPicture;
  5. begin
  6.   try
  7.     try
  8.       //initialize
  9.       pic := TPicture.Create();
  10.  
  11.       if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap))) then
  12.        begin
  13.          pic.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
  14.          image := TBGRABitmap.Create(pic.bitmap);
  15.          Image1.Picture.Assign(image);
  16.          Image2.Picture.Assign(pic.Bitmap);
  17.        end
  18.       else if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfPicture))) then
  19.        begin
  20.          pic.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfPicture));
  21.          image := TBGRABitmap.Create(pic.Bitmap);
  22.          Image1.Picture.Assign(image);
  23.          Image2.Picture.Assign(pic.Bitmap);
  24.        end;
  25.     finally
  26.       try
  27.         pic.Free;
  28.         //image.free
  29.       except
  30.         on E : Exception do ShowMessage(E.Message);
  31.       end;
  32.     end;
  33.   except
  34.     on E : Exception do ShowMessage(E.Message);
  35.   end;
  36. end;
  37.  

Image1 on the Form looks corrupted, Image2 fine (see attachment). The Error appears in Windows, in Linux it works fine. What am i doing wrong?

circular

  • Hero Member
  • *****
  • Posts: 3717
    • Personal webpage
Re: BGRABitmap to TImage fault
« Reply #1 on: April 25, 2021, 08:46:05 am »
Hello,

The problem may come arise for different reasons.

If it is related to the the way TPicture stores the image, you could read the file directly:
Code: Pascal  [Select][+][-]
  1. var stream: TStream;
  2.        ...
  3.        Stream := TMemoryStream.Create;
  4.        Clipboard.GetFormat(Clipboard.Formats[i],Stream);
  5.        Stream.Position := 0;
  6.        image := TBGRABitmap.Create(Stream);
  7.        if image.Empty then image.AlphaFill(255);  // you can try to always call AlphaFill
  8.        Stream.Free;

If for some reason the alpha channel or alpha mask is not set properly (sometimes Windows writes inconsistent alpha in opaque bitmaps), then you could try:
Code: Pascal  [Select][+][-]
  1.        pic.LoadFromClipboardFormat(PredefinedClipboardFormat(pcfBitmap));
  2.        image := TBGRABitmap.Create(pic.bitmap);
  3.        image.AlphaFill(255);  // fix alpha channel

Another thing that might help is to assign via a TBitmap copy:
Code: Pascal  [Select][+][-]
  1. var copy: TBitmap;
  2.        ...
  3.        copy := image.MakeBitmapCopy(clNone);
  4.        Image1.Picture.Assign(copy);
  5.        copy.Free;
instead of:
Code: Pascal  [Select][+][-]
  1.        Image1.Picture.Assign(image);
Conscience is the debugger of the mind

schlueter550v

  • New member
  • *
  • Posts: 9
Re: BGRABitmap to TImage fault
« Reply #2 on: May 05, 2021, 07:56:51 am »
Hello circular,

your way with loading the image from stream worked, but now something else occures.
If i have an image with alpha channel, i want to replace it with white, but somehow it turns black?

In my example i copied from Gimp. If i copy from Gimp to Lazpaint it works. If i copy then from Lazpaint to my Program it works too?

Here is my code and in the attechment an example:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.btnFromClipboardClick(Sender: TObject);
  2. var
  3.   image : TBGRABitmap;
  4.   stream : TMemoryStream;
  5. begin
  6.   try
  7.     try
  8.       //initialize
  9.       stream := TMemoryStream.Create;
  10.  
  11.       if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap))) then
  12.        begin
  13.          Clipboard.GetFormat(PredefinedClipboardFormat(pcfBitmap),stream);
  14.          stream.Position := 0;
  15.          image := TBGRABitmap.Create(stream);
  16.          image.ReplaceTransparent(BGRAWhite);
  17.          ShowMessage('bitmap');
  18.          imgPreview.Picture.Bitmap.Assign(image.Bitmap);
  19.          //scaleAndPreviewImage(image); // frees image
  20.        end
  21.       else if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfPicture))) then
  22.        begin
  23.          Clipboard.GetFormat(PredefinedClipboardFormat(pcfPicture),stream);
  24.          stream.Position := 0;
  25.          image := TBGRABitmap.Create(stream);
  26.          image.ReplaceTransparent(BGRAWhite);
  27.          ShowMessage('picture');
  28.          imgPreview.Picture.Bitmap.Assign(image.Bitmap);
  29.          //scaleAndPreviewImage(image); // frees image
  30.        end;
  31.     except
  32.       on E : Exception do ShowMessage(E.Message);
  33.     end;
  34.   finally
  35.     try
  36.       stream.Free;
  37.     except
  38.       on E : Exception do ShowMessage(E.Message);
  39.     end;
  40.   end;
  41. end;
« Last Edit: May 05, 2021, 08:57:39 am by schlueter550v »

schlueter550v

  • New member
  • *
  • Posts: 9
Re: BGRABitmap to TImage fault
« Reply #3 on: May 05, 2021, 01:01:21 pm »
Hello,

ok i got it. I've looked at the uclipboard.pas from LazPaint. I had to define A Clipboardformat for PNG.
It works, so i hope i've done everything correctly:

Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$R *.lfm}
  4.  
  5. var
  6.   pngClipboardFormat : TClipboardFormat;
  7.  
  8. ...
  9.  
  10.  
  11. procedure TForm1.btnFromClipboardClick(Sender: TObject);
  12. var
  13.   image : TBGRABitmap;
  14.   stream : TMemoryStream;
  15. begin
  16.   try
  17.     try
  18.       //initialize
  19.       stream := TMemoryStream.Create;
  20.  
  21.       if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap))) AND (NOT(Clipboard.HasFormat(pngClipboardFormat))) then
  22.        begin
  23.          Clipboard.GetFormat(PredefinedClipboardFormat(pcfBitmap),stream);
  24.          stream.Position := 0;
  25.          image := TBGRABitmap.Create(stream);
  26.          scaleAndPreviewImage(image); // frees image
  27.        end;
  28.       if (Clipboard.HasFormat(pngClipboardFormat)) then
  29.        begin
  30.          Clipboard.GetFormat(pngClipboardFormat,stream);
  31.          stream.Position := 0;
  32.          image := TBGRABitmap.Create;
  33.          image.LoadFromStream(stream);
  34.          //if image.Empty then image.AlphaFill(255);
  35.          scaleAndPreviewImage(image); // frees image
  36.        end;
  37.     except
  38.       on E : Exception do ShowMessage(E.Message);
  39.     end;
  40.   finally
  41.     try
  42.       stream.Free;
  43.     except
  44.       on E : Exception do ShowMessage(E.Message);
  45.     end;
  46.   end;
  47. end;
  48.  
  49. ...
  50.  
  51. initialization
  52.  
  53. pngClipboardFormat := RegisterClipboardFormat({$IfDef WINDOWS}'PNG'{$Else}{$IfDef DARWIN}'public.png'{$Else}'image/png'{$EndIf}{$EndIf});
  54.  
  55.  

Now i only have Problems with Alpha Images from the Browser. I only think, is it possible to change the default background of TBGRABitmap.create to white instead of Black?

Best regards
schlueter550v
« Last Edit: May 05, 2021, 01:52:09 pm by schlueter550v »

winni

  • Hero Member
  • *****
  • Posts: 2510
Re: BGRABitmap to TImage fault
« Reply #4 on: May 05, 2021, 07:17:51 pm »
Hi!

I have tested your code and the transparent pixel exist: Value 0/0/0/0.

The conversion from transparent results if you don't set the parameter opaque of BGRAbitmap.draw to false. So the correct way is

Code: Pascal  [Select][+][-]
  1. BGRAbitmap.draw (Image1.canvas,0,0, false);

That's the whole secret.

Tested with Lin64, fpc 3.2, Laz 2.0.12.0

Winni

winni

  • Hero Member
  • *****
  • Posts: 2510
Re: BGRABitmap to TImage fault
« Reply #5 on: May 05, 2021, 08:39:00 pm »
Hmmmm

Draw with opaque =  false also fails.

The solution ist good old

Code: Pascal  [Select][+][-]
  1. Image1.Canvas.CopyRect (MyRect, BGRAImage.Canvas,MyRect);

It respects the transparent pixels. Strange.

inni

circular

  • Hero Member
  • *****
  • Posts: 3717
    • Personal webpage
Re: BGRABitmap to TImage fault
« Reply #6 on: May 05, 2021, 09:23:09 pm »
Maybe first fill the image canvas with white, then draw the image with transparency?
Conscience is the debugger of the mind

circular

  • Hero Member
  • *****
  • Posts: 3717
    • Personal webpage
Re: BGRABitmap to TImage fault
« Reply #7 on: May 05, 2021, 09:24:52 pm »
I had to define A Clipboardformat for PNG.
Indeed, some programs use PNG as clipboard format.
Conscience is the debugger of the mind

winni

  • Hero Member
  • *****
  • Posts: 2510
Re: BGRABitmap to TImage fault
« Reply #8 on: May 05, 2021, 10:28:35 pm »
Hi!

Gimp for example uses PNG as Clipboard format.

The problems drawing the BGRAbitmap from the Clipboard stream:


Code: Pascal  [Select][+][-]
  1. Bmp.draw (Image.canvas, 0,0);
  2.  
draws the transparent pixels as black, even if you fill the Image with some color.

Code: Pascal  [Select][+][-]
  1. Bmp.draw (Image.canvas,0,0,false);

draws  nothing if you fill the image before with a color.

Code: Pascal  [Select][+][-]
  1. Image.canvas.CopyRect (Arect, Bmp.canvas,ARect);

does the job including respecting transparency.

The transparent pixel exist as 0/0/0/0. That is not the reason.

Talking about Linux.

Winni


schlueter550v

  • New member
  • *
  • Posts: 9
Re: BGRABitmap to TImage fault
« Reply #9 on: May 06, 2021, 08:07:45 am »
Hello,

i tried the following now, but it did no change. Im not even sure if i used the CopyRect correct?
The image background keeps black on Windows:

Code: Pascal  [Select][+][-]
  1. if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap))) AND (NOT(Clipboard.HasFormat(pngClipboardFormat))) then
  2.        begin
  3.          Clipboard.GetFormat(PredefinedClipboardFormat(pcfBitmap),stream);
  4.          stream.Position := 0;
  5.          image := TBGRABitmap.Create(stream);
  6.          imgPreview.Canvas.CopyRect(Rect(0,0,image.Width,image.Height),image.Canvas,Rect(0,0,image.Width,image.Height));
  7.          //scaleAndPreviewImage(image); // frees image
  8.        end;

How to check if those pixels are actual transparent?

Best Regards
schlueter550v

winni

  • Hero Member
  • *****
  • Posts: 2510
Re: BGRABitmap to TImage fault
« Reply #10 on: May 06, 2021, 10:21:16 am »
Hi!

First fill the imgPreview with a color. Otherwise the color is by default black. So the copyrect respects the transparency but the background is black.

Check the values of a pixel:
Code: Pascal  [Select][+][-]
  1. Const LE=LineEnding;
  2. var px : TBGRApixel;
  3. s : string;
  4. ...
  5. px := Image.GetPixel(x,y);
  6. s := IntToStr(px.red)+LE+IntToStr(px.green)+LE+IntToStr(px.blue)+
  7.               LE +IntToStr(px.alpha);
  8. showMessage (s);                
  9. ....
  10.  

If a pixel is transparent it should show 0/0/0/0

Winni

schlueter550v

  • New member
  • *
  • Posts: 9
Re: BGRABitmap to TImage fault
« Reply #11 on: May 06, 2021, 12:46:21 pm »
Hello winni,

i tried your suggestion:

Code: Pascal  [Select][+][-]
  1. if (Clipboard.HasFormat(PredefinedClipboardFormat(pcfBitmap))) AND (NOT(Clipboard.HasFormat(pngClipboardFormat))) then
  2.        begin
  3.          Clipboard.GetFormat(PredefinedClipboardFormat(pcfBitmap),stream);
  4.          stream.Position := 0;
  5.          image := TBGRABitmap.Create(stream);
  6.          //image.LoadFromStream(stream, reader,[loBmpAutoOpaque]);
  7.          px := image.GetPixel(3,1);
  8.          s :=  IntToStr(px.red) + ' ' + IntToStr(px.green) + ' ' + IntToStr(px.blue) + ' ' + IntToStr(px.alpha);
  9.          ShowMessage(s);
  10.          scaleAndPreviewImage(image); // frees image
  11.        end;
  12.  

But somehow i get 0 0 0 255 from that Pixel, which definetly should be transparent.
I also tried to fill the complete Canvas (250x250) white and put the image (200x200) with CopyRect on it.
The (200x200) area background is black from the image, and the rest of the Canvas space is white.
Im talking about a Win 10 System.


Some more ideas??


Best Regards

schlueter550v

winni

  • Hero Member
  • *****
  • Posts: 2510
Re: BGRABitmap to TImage fault
« Reply #12 on: May 06, 2021, 01:07:03 pm »
Hi!

The RGBA value 0/0/0/255 is black.

The value x/x/x/0  is transparent.


It seems that Windows behaves different from gtk2.
We should wait for  circular to give us an answer.

Winni

circular

  • Hero Member
  • *****
  • Posts: 3717
    • Personal webpage
Re: BGRABitmap to TImage fault
« Reply #13 on: May 06, 2021, 01:21:19 pm »
@schlueter550v

In your latest example, you read the BMP format, not PNG. On Windows, BMP clipboard is almost always opaque.
Conscience is the debugger of the mind

schlueter550v

  • New member
  • *
  • Posts: 9
Re: BGRABitmap to TImage fault
« Reply #14 on: May 06, 2021, 01:29:42 pm »
Hello,

so you suggest to use another Clipboardformat than pcfBitmap? But if i copy my PNG Picture from Firefox the Clipboard shows no PNG???
Or do i have to use that very long code from LazPaints uclipboard.pas' functions where some data is obtained from HTML? Is it possible to "use" this unit in uses?

In the attachment is an example of an PNG copied in Firefox. If i do it in IE or Edge it looks again different.

 

TinyPortal © 2005-2018