Recent

Author Topic: Transparent tImage problem  (Read 1806 times)

Rik

  • Jr. Member
  • **
  • Posts: 74
Transparent tImage problem
« on: May 22, 2024, 10:40:34 am »
I have a strange problem with a transparent tImage.
This is my code:
Code: Pascal  [Select][+][-]
  1. procedure TMainForm.FormCreate(Sender: TObject);
  2. begin
  3.   with BgImg do
  4.   begin
  5.     Canvas.Brush.Style:= bsSolid;                      // make BgImg transparent with clSilver as transparent colour ...
  6.     Canvas.Brush.Color:= clSilver;
  7.     Picture.Bitmap.TransparentMode:= tmFixed;
  8.     Picture.Bitmap.TransparentColor:= clSilver;
  9.     Transparent:= True;
  10.     Canvas.FillRect(0,0,Width,Height);               // ... till here
  11.     Canvas.Pen.Color:= clLime;                         // and draw a lime coloured line from top left to bottom right ...
  12.     Canvas.MoveTo(0,0);
  13.     Canvas.LineTo(Width-1,Height-1);               // ... till here
  14.   end;
  15. end;
  16.  
  17. procedure TMainForm.FormClick(Sender: TObject);
  18. begin
  19.   with BgImg do
  20.   begin
  21.     Canvas.MoveTo(0,Height-1); // draw  a second line on BGImg from bottom left to top right ...
  22.     Canvas.LineTo(Width-1,0);    // ... when I click somewhere on the form
  23.   end;
  24. end;
  25.  

The first line (top left to bottom right) is shown at startup, but I don't get the second line (bottom left to top right) when I click on the form.

When I leave out "Transparent:= True;" in FormCreate then it works as expected, both line are shown (on a silver background).

When I leave out "Transparent:= True;" in FormCreate but add it in FormClick then both lines are show, but (as expected) BgImg becomes only transparent after clicking on the form:

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.FormClick(Sender: TObject);
  2. begin
  3.   with BgImg do
  4.   begin
  5.     Transparent:= True;
  6.     Canvas.MoveTo(0,Height-1); // draw  a second line on BGImg from bottom left to top right ...
  7.     Canvas.LineTo(Width-1,0);    // ... when I click somewhere on the form
  8.   end;
  9. end;
  10.  

How can I create a transpanent tImage at startup that allows to draw on it later?



wp

  • Hero Member
  • *****
  • Posts: 12476
Re: Transparent tImage problem
« Reply #1 on: May 22, 2024, 12:25:22 pm »
Modified the OnClick code such to draw the second line in red and with width 5. When I now click on the form a few red pixels appear in the center of the green downward line.

Thinking about it, I think this is as expected. "Color-transparency" (i.e. that what you have when you set Transparent to true) is achieved by means of a mask created from the pixels having the TransparentColor. It seems that this mask is not updated when you paint over this image a second time. Therefore everything is blocked by the mask except for the pixels of the green line, and you paint over the image a second time only the pixels at the intersection between both lines become visible.

This is different from "alpha-channel transparency" (the kind of transparency in png images) where a fourth color channel exists to define the amount of transparency. The alpha-channel can be understood as an integrated mask, too, but when a new opaque line is drawn over an existing image, the alpha-channel of the line pixels is automatically set such that the line appears.

What can be done against this issue? We must force the image to update its mask. Looking at the source code of TRasterImage, an ancestor of TBitmap, I found the procedure ReleaseMaskHandle. This sounds promising, and, in fact, when I call this at the begin of the OnClick procedure, the second upward line does appear when the form is clicked:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormClick(Sender: TObject);
  2. begin
  3.   with Image1 do
  4.   begin
  5.     Picture.Bitmap.ReleaseMaskHandle;
  6.     Canvas.Pen.Color := clRed;
  7.     Canvas.Pen.Style := psSolid;
  8.     Canvas.Pen.Width := 5;
  9.     Canvas.MoveTo(0,Height-1); // draw  a second line on BGImg from bottom left to top right ...
  10.     Canvas.LineTo(Width-1,0);    // ... when I click somewhere on the form
  11.   end;
  12. end;
« Last Edit: May 22, 2024, 12:31:21 pm by wp »

rvk

  • Hero Member
  • *****
  • Posts: 6592
Re: Transparent tImage problem
« Reply #2 on: May 22, 2024, 12:29:58 pm »
Why are you using TImage ???
If you are just drawing yourself it might be better to use TPaintBox.

After initial creation of the TImage, I don't think you are allowed to touch the TImage.Canvas (or at least it doesn't do anything).
There is a BgImg.Picture.Bitmap created which is then used.

For example, if you change the "with BgImg do" in the OnClick to "with BgImg.Picture.Bitmap.Canvas do" you see what I mean and that it works (besides that the brush and color is reset).


KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: Transparent tImage problem
« Reply #3 on: May 22, 2024, 12:38:19 pm »
I like to jump also into this topic with a different approach how-to-create-transparent images:
uses ... FPImage, FPCanvas, FPImgCanv ...
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   LImage: TFPCustomImage;
  4.   LCanvas: TFPCustomCanvas;
  5.   CurrentX, CurrentY: Integer;
  6. begin
  7.   LImage := TFPMemoryImage.Create(200, 200);
  8.   try
  9.     LCanvas := TFPImageCanvas.Create(LImage);
  10.     try
  11.       for CurrentY := 0 to Pred(LImage.Height) do
  12.         for CurrentX := 0 to Pred(LImage.Width) do
  13.           begin
  14.             // paint a frame while rest gets full transparent
  15.             if ((CurrentY = 5) or (CurrentX = 5) or
  16.                 (CurrentY = LImage.Height - 5) or (CurrentX = LImage.Width - 5)) then
  17.               LCanvas.Colors[CurrentX, CurrentY] := colMagenta
  18.             else
  19.               LCanvas.Colors[CurrentX, CurrentY] := colTransparent;
  20.           end;
  21.       Image2.Picture.Assign(LImage);
  22.     finally
  23.       LCanvas.Free;
  24.     end;
  25.   finally
  26.     LImage.Free;
  27.   end;
  28. end;
On image you see 2 x TImage, once in background with water, once in foreground with a rectangle.
The TImage(s) I just made client aligned, nothing else changed.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

wp

  • Hero Member
  • *****
  • Posts: 12476
Re: Transparent tImage problem
« Reply #4 on: May 22, 2024, 12:47:29 pm »
I agree with rvk, using a TPaintbox for painting is much easier to understand than using a TImage where so much is running in the background. The only problem with TPaintbox is that the painting is not persistent when you do not draw in the OnPaint event. This requires some reconsideration of the drawing strategy because usually people draw in OnClick events or so.

Of course, you can provide a custom buffer bitmap which is drawn in the Paintbox's OnPaint event. A bitmap is persistent and you can draw to at any time. So, in the OnClick event you draw into the bitmap and request the paintbox to redraw itself.

That's how I would have approached the drawing process of this post. But - I noticed the same issue as reported: the second line does not appear. Following the discussion in my previous post, however, it is clear: The mask is not updated in the OnClick. But here again: Add ReleaseMaskHandle to solve the issue

Code: Pascal  [Select][+][-]
  1. type
  2.   TForm1 = class(TForm)
  3.     PaintBox1: TPaintBox;
  4.     procedure FormClick(Sender: TObject);
  5.     procedure FormCreate(Sender: TObject);
  6.     procedure FormDestroy(Sender: TObject);
  7.     procedure PaintBox1Paint(Sender: TObject);
  8.   private
  9.     FBuffer: TBitmap;
  10.   public
  11.   end;
  12. ...
  13. procedure TForm1.FormCreate(Sender: TObject);
  14. begin
  15.   FBuffer := TBitmap.Create;
  16.   with FBuffer do
  17.   begin
  18.     SetSize(Paintbox1.Width, Paintbox1.Height);
  19.     TransparentMode := tmFixed;
  20.     TransparentColor := clSilver;
  21.     Transparent := true;
  22.     Canvas.Brush.Color := clSilver;
  23.     Canvas.FillRect(0, 0, Paintbox1.Width, Paintbox1.Height);
  24.     Canvas.Pen.Color := clLime;
  25.     Canvas.MoveTo(0,0);
  26.     Canvas.LineTo(Width-1, Height-1);
  27.   end;
  28. end;
  29.  
  30. procedure TForm1.FormDestroy(Sender: TObject);
  31. begin
  32.   FBuffer.Free;
  33. end;
  34.  
  35. procedure TForm1.FormClick(Sender: TObject);
  36. begin
  37.   with FBuffer do
  38.   begin
  39.     ReleaseMaskHandle;
  40.     Canvas.Pen.Color := clRed;
  41.     Canvas.MoveTo(Random(Width), Random(Height));
  42.     Canvas.LineTo(Random(Width), Random(Height));
  43.   end;
  44.   Paintbox1.Invalidate;
  45. end;
  46.  
  47. procedure TForm1.PaintBox1Paint(Sender: TObject);
  48. begin
  49.   Paintbox1.Canvas.Draw(0, 0, FBuffer);
  50. end;
« Last Edit: May 22, 2024, 12:49:46 pm by wp »

Rik

  • Jr. Member
  • **
  • Posts: 74
Re: Transparent tImage problem
« Reply #5 on: May 23, 2024, 08:50:38 am »
Thanks to all who replied.
Using Picture.Bitmap.ReleaseMaskHandle as suggested by wp solves my problem.
I tried TPaintBox before but, but struggled with the persistency.

Rik

 

TinyPortal © 2005-2018