[Infos] Transparent bitmap, wiki article lazarus / 39-Graphics ---------------------------------------------------------------------- d7_2_laz · 2023-06-14 21:21 Besides i noticed that on an own custom gradient button having a small bitmap - loaded from a ressource file (not image list) -, that one was not painted with transparent background as i originally intended. Looking on that, and seeing a wiki article about this topic, i was surprised i couldn't solve it by easy means. This is the article (Drawing color transparent bitmaps): https://wiki.lazarus.freepascal.org/Developing_with_Graphics#Drawing_c olor_transparent_bitmaps ... Until i noticed i had to add a Mask creation statement for to make it work perfectly: 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           bmp.Mask(clDefault);  // For me It does not work without this! Maybe some classes did change meanwhile? Don't know, but if i should be right, it could be useful to mentioned this requirement in the wiki code sample. Edit: Windows x64, Lazaraus 2.3.0 Win x64 ---------------------------------------------------------------------- wp · 2023-06-17 23:33 OMG - what crap we have in the wiki! Drawing in the button OnClick event, a windows-only way to access resources when we have a nice cross-platform solution... I took the freedom to update the article. But nevertheless, the code is working. I would ask you to upload the image that did not work for you so that I can have a look. Maybe it was an old paletted image? (Don't know if this plays a role...) I am attaching my test program which is based on the old and new wiki code sample. ---------------------------------------------------------------------- d7_2_laz · 2023-06-18 07:59 Hello wp, thanks! Sure, i think too the palette might not be quite appropriate, as the bitmap had once been created by limited means. Obviously for such cases one must use a Mask creation, and i found it useful to know and to mention in the wiki article. I modified the test project a little bit for to show what i mean. - Run the test project and see the background of the bitmap  // as of image 1 attached - Remove the commenting of the line "bmp.Mask(clDefault);", run again and see   // as of image 2 attached ---------------------------------------------------------------------- wp · 2023-06-18 09:36 Extracted the bitmap from the resource (using XN Resource Editor). It is a 16-color bitmap. Life gets hard with paletted bitmaps in the LCL... At first the good news. When you set bitmap.Transparent = true and do NOT assign a TransparentColor everything works fine: this way the bitmap automatically detects the transparent color from the pixel at the origin (0, 0). But what if that particular pixel is not transparent? Of course: the user should set the bitmap.TransparentColor. What is the transparent color in a paletted image? The palette index, or the RGB value? I opened the image in IrfanView and it showed me that the olive of the background is palette index 2. I tried Bitmap.TransparentColor := 2 - it did not work. Of course: since the LCL takes the image as 32-bit I cannot use the palette index. Tried clOlive (rather than your bmp.Canvas.Pixels[0,0]) - it was working! Reestablished the Pixels[0,0] rather than clOlive - not working. I checked the value of bitmap.TransparentMode - it was tmFixed as it should be. Nevertheless I set it to tmFixed before setting the TansparentColor to bmp.Canvas.Pixels[0,0] - it was working again! Removed setting bitmap.TransparentMode, but moved the call to Bitmap.Transparent after setting the TransparentColor - it was working again! So, I think, it is not necessary to use a Mask for this task (in fact I never have used one), everything is working fine, except for some missing update mechanism within the bitmap class (or its ancestors). ---------------------------------------------------------------------- d7_2_laz · 2023-06-18 12:11 Yes, it's a 16-color bitmap (relict from an old Delphi context). Yes, i had a similar perplexity when i surprisingly needed to struggle with in my original use case. At the end, for me keys for the solution had been both: 1) the "memstream-trick" as originally mentioned in the wiki, and: 2) the bitmap.Mask statement. What i indeed didn't know at that stage: - the Transparent:=true alone (without TransparentColor assignment) would work - or, a  bmp.Transparent:=True assignment _after_ a  bmp.TransparentColor:= bmp.Canvas.Pixels[0,0] would work,  but not in reversed order (because the Transparent:=True triggers an updating which otherwise won't happen) - TransparentColor:=clOlive (in this case) would work, whereas the "Pixels[0,0]" does not (strange) - a PRE stated  TransparentMode:=tmFixed would cure anyway (i had it later, and so removed it then because it had no effect here). Stays somehow curious a bit ... But in this detail level it's surely not suitable for the wiki article. Nevertheless, within this topic here should be enough indications about possible factors and recommended orders how to deal with it now. ---------------------------------------------------------------------- wp · 2023-06-18 13:09 Yes, it is strange. I did try to investigate a bit, but it seems to be quite complicated, in particular because every widgetset may behave a bit differently. So, better to keep my fingers out of this code... Maybe it's sufficient that i added "it is highly recommended to change the Transparent property to true at the end of the assignment sequence" to the wiki article... And I added another section about the much superior alpha-channel transparency:  https://wiki.freepascal.org/Developing_with_Graphics#Drawing_alpha- channel_transparent_bitmaps ---------------------------------------------------------------------- d7_2_laz · 2023-06-18 13:26 QuoteMaybe it's sufficient that i added "it is highly recommended to change the Transparent property to true at the end of the assignment sequence" to the wiki article... Yes, i think this does spend a certain awareness of the possible impact of the statement orders. I'd tried to memorize for myself the 'lessons learned' here via: 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 //bmp.TransparentMode := tmFixed;    // Pre-stated here, it would help //bmp.Transparent := True;           // Should better be placed AFTER the Pixels[0,0] assignment for to force updating //bmp.TransparentColor := clOlive;   // Would work better than Pixels[0,0]  bmp.TransparentColor := bmp.Canvas.Pixels[0,0];   bmp.Transparent := True;    // *Remark: is better placed here, AFTER the Pixels[0,0] assignment for to force updating //bmp.Mask(clDefault);      // Now, no more nneded due to see *Remark ---------------------------------------------------------------------- wp · 2023-06-18 13:48 Quote from: d7_2_laz on June 18, 2023, 03:26:08 pmI'd tried to memorize for myself the 'lessons learned' here via [...] Maybe one more to memorize: Use TransparentColor only when needed, i.e. only if the bottom/left pixel should be opaque (most icons are designed in a way such that is key pixel is transparent!). Setting Transparent=true is enough normally. ---------------------------------------------------------------------- d7_2_laz · 2023-06-18 15:13 Yes, absolutely! As proove that ":=Transparent" already (as you said) does the required job: 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 outputdebugstring(pchar( ColorToString (bmp.Canvas.Pixels[0,0] ))) ;  // ====>  Outputs "clOlive"bmp.Transparent := True;outputdebugstring(pchar( ColorToString( bmp.TransparentColor )));    // ====>  Outputs "clOlive"Nevertheless: the subsequent assignment of the same kills the already existing good result by some reasons (as you told earlier): 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 bmp.TransparentColor := bmp.Canvas.Pixels[0,0];     // Now, the background is not more transparent ..So: originally i thought it's good to make explicit what's intended (the TransparentColor), but that's not always a good idea. But anyway ....  it's really good to be aware such possible impact. ---------------------------------------------------------------------- wp · 2023-06-18 15:51 It looks to me that setting Transparent does some work which is partly undone when the TransparentColor is set afterwards. 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 TRasterImage.SetTransparentColor(AValue: TColor);begin  if FTransparentColor = AValue then exit;  FTransparentColor := AValue;   if AValue = clDefault  then FTransparentMode := tmAuto  else FTransparentMode := tmFixed;   if MaskHandleAllocated  then MaskHandle := 0  else Changed(Self);end;When a predefined color is set (TransparentColor := clOlive) the code goes in the highlighted "if MaskHandleAllocated" to the "else" branch. But when the TransparentColor is determined from the Pixels it seems that a MaskHandle has been allocated by the GetPixels, since the code goes the "then" way which erases the MaskHandle again, and I don't find where the MaskHandle is recreated... On the other hand, when the entire "if maskHandleAllocated" part is commented out except for the "Changed" the code works even when Transparent is set before TransparentColor. Of course, "if MaskHandleAllocated" is here for some reason, and I do not intend to touch it... ---------------------------------------------------------------------- d7_2_laz · 2023-06-18 16:27 Very interesting!!  (I wouldn't intend to have changes here either) And, so, at the end my original solution (bmp.Mask(clDefault)) wouldn't do nothing else than to revert the damage that setting TransparentColor from the Pixel just unnecessarily caused ... Wow, crazy.