BGRABitmap + BCRoundedImage + .TextOut = garbage lazarus / 39-Graphics ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 01:53 Hi everyone! I use BCRoundedImage to display graphics I create in BGRABitmap, everything goes smoothly till I use .TextOut. Using .TextOut makes the graphics very defective (pic #1). On Windows it happens even without using .TextOut (pic #2). I create the component dynamically: 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 var bubble: TBCRoundedImage;begin  bubble:=TBCRoundedImage.Create(Self);  bubble.Parent:=ChatsTab;  bubble.Style:=isSquare;  bubble.Top:=60*(ChatsTab.ControlCount-1);  bubble.Left:=0;  bubble.Width:=ChatsTab.ClientWidth;  bubble.Height:=60;  bubble.Tag:=ChatsTab.ControlCount;  bubble.Picture.Assign(ChatListBubble(bubble.Width,bubble.Height,'Some text',IntToStr(bubble.Tag),StrToTime('16:00')));end;   and that's how I draw the image 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 var  TBit: TBitmap;  Lmargin: integer =5;  Rmargin: integer =5;  Tmargin: integer =3;  Bmargin: integer = 0; begin  TBit := TBitmap.Create;  TBit.PixelFormat := pf24bit;  TBit.Width := w;  TBit.Height := h;   bmp:=TBGRABitmap.Create(w,h,BGRA(0,0,0,0));  bmp.draw(TBit.Canvas, 0,0,true);  bmp.RoundRect(Lmargin, Tmargin, w-Rmargin, h-Bmargin, 15, 15, $00FF9900, BGRA(128,128,128,255), dmDrawWithTransparency, 8192);  bmp.RoundRect(Lmargin+5, Tmargin+5, 55, 55, 15,15, $00FF9900,dmDrawWithTransparency,32768);  bmp.FontHeight:=15;  bmp.FontStyle:=[fsBold];  bmp.textout(Lmargin+5+50+10, Tmargin+10, name, $cccccc,);  bmp.FontHeight:=14;  bmp.FontStyle:=[fsItalic];  bmp.TextOut(Lmargin+5+50+10, h-Bmargin-10-bmp.TextSize(lastmsg).cy , lastmsg, $cccccc);  Result:=bmp;end;         Am I doing something wrong or what's the problem? thanks in advance for any clue. ---------------------------------------------------------------------- circular · 2022-06-07 05:30 Hi! The code seems incomplete so it is not easy to analyze what happens. How you transfer the image is important in this case. Can you provide more code, something that one could try to run? I am wondering what is the TBit object for. Note that setting the PixelFormat property is a bit buggy as far as I know. Also I don't understand the need for a TBCRoundedImage if you set it to square. I would presume that you would like to draw an opaque bitmap with gray background inside this component, and let the component make the rounded borders. When you do bubble.Picture.Assign it doesn't seem like the original image object is freed. ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 13:56 The Tbit is just remnants of my trials with Timage. I removed it right after I posted it, but it didn't change anything. I need RoundedImage only to display BGRABitmap directly, not through 'On' events. You example from the previous post works perfectly but I'd have to generate images on events and it makes things a bit different. here I create the RoundedImage dynamically: 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 TApp.BCLabel4Click(Sender: TObject);var bubble: TBCRoundedImage;begin  bubble:=TBCRoundedImage.Create(Self);  bubble.Parent:=ChatsTab;  bubble.Style:=isSquare;  bubble.Top:=60*(ChatsTab.ControlCount-1);  bubble.Left:=0;  bubble.Width:=ChatsTab.ClientWidth;  bubble.Height:=60;  bubble.Tag:=ChatsTab.ControlCount;  bubble.Picture.Assign(ChatListBubble(bubble.Width,bubble.Height,'Some text',IntToStr(bubble.Tag),StrToTime('16:00'),msNone));  bmp.Free;end;       ChatListBubble generates the needed image, and it's like: 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 function ChatListBubble(w: integer; h: integer; name: string; lastmsg: string; time: TDateTime; status: TMsgStatus):TBGRABitmap;var  bmp:   TBGRABitmap;  Lmargin: integer =5;  Rmargin: integer =5;  Tmargin: integer =3;  Bmargin: integer = 0; begin  bmp:=TBGRABitmap.Create(w,h,BGRA(0,0,0,0));  bmp.RoundRect(Lmargin, Tmargin, w-Rmargin, h-Bmargin, 15, 15, $00FF9900, BGRA(128,128,128,255), dmDrawWithTransparency, 8192);  bmp.RoundRect(Lmargin+5, Tmargin+5, 55, 55, 15,15, $00FF9900,dmDrawWithTransparency,32768);  bmp.FontHeight:=15;  bmp.FontStyle:=[fsBold];  bmp.textout(Lmargin+5+50+10, Tmargin+10, name, $cccccc);  bmp.FontHeight:=14;  bmp.FontStyle:=[fsItalic];  bmp.TextOut(Lmargin+5+50+10, h-Bmargin-10-bmp.TextSize(lastmsg).cy , lastmsg, $cccccc);  Result:=bmp;end;             QuoteAlso I don't understand the need for a TBCRoundedImage if you set it to square I don't need my image to be rounded, I use this component as a substitute for TImage since I didn't get it to be transparent. ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 15:23 I've just tried TImage again and it works perfectly....  both, Linux Qt5 and Windows... ---------------------------------------------------------------------- circular · 2022-06-07 17:08 Cool. Just one remark, I think there is a memory leak here: 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 bubble.Picture.Assign(ChatListBubble(bubble.Width,bubble.Height,'Some text',IntToStr(bubble.Tag),StrToTime('16:00'),msNone)); What you would need to do here would be: 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 tempBgra := ChatListBubble(bubble.Width,bubble.Height,'Some text',IntToStr(bubble. Tag),StrToTime('16:00'),msNone);bubble.Picture.Assign(tempBgra);tempBg ra.Free; This may cause some problem. If you don't really need transparency, like with a solid background, you could do: 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 tempBgra := ChatListBubble(bubble.Width,bubble.Height,'Some text',IntToStr(bubble.Tag),StrToTime('16:00'),msNone);tempBmp := tempBgra.MakeBitmapCopy(clBlack); // the background colortempBgra.Free;bubble.Picture.Assign(tempBmp);tempBmp.Free; If you need transparency, you can assign the bitmap to a TBGRAGraphicControl like this: 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 tempBgra := ChatListBubble(bubbleGraphicControl.Width,bubbleGraphicControl.Height, 'Some text',IntToStr(bubble.Tag),StrToTime('16:00'),msNone);bubbleGrap hicControl.Bitmap.Assign(tempBgra);bubbleGraphicControl.Invalidate;tem pBgra.Free; In fact, thinking about it, the last method is probably the best. ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 19:34 QuoteWhat you would need to do here would be:it's still giving the same result :| Quote If you don't really need transparency, like with a solid background, you could do:I do need transparency. As a matter of fact I have more issues with transparency. TBCPanel is beautifully transparent on Linux but not on Windows, but I guess it's a topic for a separate post QuoteIf you need transparency, you can assign the bitmap to a TBGRAGraphicControl like this:this solution works perfectly. Thank you! ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 20:09 ...and a question, not completely related to the topic... how could I squeeze a photo (let's say from a file) into that rounded square? I'm trying to round it in BDRoundedImage and copy to that BGRABitmap but no success so far :| ---------------------------------------------------------------------- winni · 2022-06-07 21:07 Quote from: r.lukasiak on June 07, 2022, 10:09:31 pm...and a question, not completely related to the topic... how could I squeeze a photo (let's say from a file) into that rounded square? I'm trying to round it in BDRoundedImage and copy to that BGRABitmap but no success so far :| Hi! All that component-stuff .... * Load your photo-file into a BGRAbitmap * Resample it to the destination size: BGRAreplace (MyPhoto, MyPhoto.resample (NewWidth, NewHeight)); * Create a temporary transparent BGRAbitmap of the same size, we call it tmp * tmp.RoundRectAntialias(......, MyPhoto, ........); * Draw tmp on any canvas you like OR do a putimage on a BGRAbitmap * free the tmp Done Winni ---------------------------------------------------------------------- circular · 2022-06-07 22:01 Indeed, you don't need to go through components. As winni suggests, you can pass an image instead of a color to any drawing function and it will fill using the image. You can use temporary images to do things, apply masks etc. In this simple case, you can adjust the position of the image by changing the ScanOffset property of the image, and use it to draw directly. In your ChatListBubble bubble, you could do: 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 squeezedPhoto := originalPhoto.Resample(20, 20);squeezedPhoto.ScanOffset := Point(-10, -10);bmp.RoundRectAntialias(10, 10, 10 + 20 - 1, 10 + 20 - 1, 5, 5, squeezedPhoto);squeezedPhoto.Free; ---------------------------------------------------------------------- r.lukasiak · 2022-06-07 23:20 thank you both! I tried it and indeed, it's rounded but the pic is not exactly inside the "frame", it looks like the picture is the frame itself. There was missing one parameter for RoundRectAntialias, "w" - I assume it the "frame" thickness. First I set it to 1 (pic #1) and then to 25 (pic #2) My code including you solution: 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 function ChatListBubble(w: integer; h: integer; name: string; lastmsg: string; time: TDateTime; status: TMsgStatus):TBGRABitmap;var  Lmargin: integer =5;  Rmargin: integer =5;  Tmargin: integer =3;  Bmargin: integer = 0;  squeezedPhoto: TBGRABitmap;  originalPhoto: TBGRABitmap;begin  bmp:=TBGRABitmap.Create(w,h,BGRA(0,0,0,0));   originalPhoto:=TBGRABitmap.Create('gfx/nophoto.jpeg');  squeezedPhoto:=TBGRABitmap.Create(40,40);  squeezedPhoto := originalPhoto.Resample(40, 40);  squeezedPhoto.ScanOffset := Point(-10, -10);   bmp.RoundRect(Lmargin, Tmargin, w-Rmargin, h-Bmargin, 15, 15, $00FF9900, BGRA(128,128,128,255), dmDrawWithTransparency, 8192);   bmp.RoundRectAntialias(10, 10, 10 + 40 - 1, 10 + 40 - 1, 5, 5, squeezedPhoto, 25); <-it was asking for an extra parameter   originalPhoto.Free;  squeezedPhoto.Free;    //bmp.RoundRect(Lmargin+5, Tmargin+5, h-5, h-5, 15,15, $00FF9900,dmDrawWithTransparency,32768);   bmp.FontHeight:=15;  bmp.FontStyle:=[fsBold];  bmp.textout(Lmargin+5+(h-5), Tmargin+5, name, $cccccc);  bmp.FontHeight:=14;  bmp.FontStyle:=[fsItalic];  bmp.TextOut(Lmargin+5+(h-5), h-Bmargin-5-bmp.TextSize(lastmsg).cy , lastmsg, $cccccc);  Result:=bmp;end; ---------------------------------------------------------------------- r.lukasiak · 2022-06-08 00:38 I followed @winni's instruction and I got it, however there is something I had noticed when I was playing around with RoundedImage, the "rounding" is different. The picture and the frame are set to 15 but they don't match (pic #1). How comes? My "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 function ChatListBubble(w: integer; h: integer; name: string; lastmsg: string; time: TDateTime; status: TMsgStatus):TBGRABitmap;var  Lmargin: integer =5;  Rmargin: integer =5;  Tmargin: integer =3;  Bmargin: integer = 0;  squeezedPhoto: TBGRABitmap;  originalPhoto: TBGRABitmap;begin  bmp:=TBGRABitmap.Create(w,h,BGRA(0,0,0,0));   originalPhoto:=TBGRABitmap.Create('gfx/nophoto.jpeg');  BGRAreplace(originalPhoto,originalPhoto.Resample(37,37));   squeezedPhoto:=TBGRABitmap.Create(37,37,BGRA(0,0,0,0));  squeezedPhoto .RoundRectAntialias(0,0,36,36,15,15,originalPhoto,0,originalPhoto);   bmp.RoundRect(Lmargin, Tmargin, w-Rmargin, h-Bmargin, 15, 15, $00FF9900, BGRA(128,128,128,255), dmDrawWithTransparency, 8192);  bmp. PutImage(Lmargin+5,Tmargin+5,squeezedPhoto,dmDrawWithTransparency);   originalPhoto.Free;  squeezedPhoto.Free;   bmp.RoundRect(Lmargin+5, Tmargin+5, Lmargin+5+36, Tmargin+5+36, 15,15, $00FF9900,dmDrawWithTransparency,32768);   bmp.FontHeight:=15;  bmp.FontStyle:=[fsBold];  bmp.textout(Lmargin+5+(h-5), Tmargin+5, name, $cccccc);  bmp.FontHeight:=14;  bmp.FontStyle:=[fsItalic];  bmp.TextOut(Lmargin+5+(h-5), h-Bmargin-5-bmp.TextSize(lastmsg).cy , lastmsg, $cccccc);  Result:=bmp;end;       ------------------ Edit: RoundRectAntialias and RoundRect produce different rounding shape. ---------------------------------------------------------------------- winni · 2022-06-08 14:12 Hi! Perhaps it has to do with the different positions of integer and floating points. Read this for the basic definitions: https://wiki.freepascal.org/BGRABitmap_tutorial_13 And for BGRA(0,0,0,0) there is a constant defined in BGRAbitmapTypes called BGRAPixelTransparent Winni ---------------------------------------------------------------------- r.lukasiak · 2022-06-09 03:27 Quotehttps://wiki.freepascal.org/BGRABitmap_tutorial_13ohh cool, it's interesting 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 BGRAPixelTransparentit's good to know. I'll try it next time, even though BGRA(0,0,0,0) is kinda easier to type thank you very much for all the help! ---------------------------------------------------------------------- circular · 2022-06-09 20:05 Oops it is FillRoundRectAntialias instead