ImageList SVG lazarus / 39-Graphics ---------------------------------------------------------------------- lainz · 2020-10-17 21:05 Hi! With @circular we want to make a SVG / LZP image list. We need a bit of help.  Retina display: we have already a solution to this. But we need to pass another parameter to determine the real size of the bitmap.  As well we drawn the image on the fly, so there is in memory only the SVG file. All the resolutions are drawn when needed. The idea is to make if possible backward compatible. And we need our own IDE editor since the current one will have no sense since we need to load only svg and lzp images. If I remember correctly the user wp did most of the new cool changes like multi resolution? So if you can please help us to understand how we can integrate or code. Basically I think we'll be doing our own draw method targeting any desired size. The we need to integrate with current methods. Help ---------------------------------------------------------------------- winni · 2020-10-17 21:15 Hi! Bravo lainz & circular! This is realy needed. For a lot a users the multi resolution imagelist is very confusing. We had the discussion again some days ago in the german forum. A SVG ImageList - that rocks! Good luck! Winni ---------------------------------------------------------------------- wp · 2020-10-17 21:39 Quote from: lainz on October 17, 2020, 11:05:20 pmIf I remember correctly the user wp did most of the new cool changes like multi resolution? So if you can please help us to understand how we can integrate or code. No, the imagelist as well as the high-dpi support were written by Ondrej Pokornej, I've seen him in the forum occasionally, but you should probably contact him directly by PM. Ideally the svg image list should be compatible to the current imagelist and be independent of BGRA. I don't know if this is possible... There are a lot of virtual methods and properties depending on the ppi of the system, e.g. 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 DrawForPPI(ACanvas: TCanvas; AX, AY, AIndex: Integer;      AImageWidthAt96PPI, ATargetPPI: Integer; ACanvasFactor: Double; AEnabled: Boolean = True); overload;    procedure DrawForPPI(ACanvas: TCanvas; AX, AY, AIndex: Integer;      AImageWidthAt96PPI, ATargetPPI: Integer; ACanvasFactor: Double; ADrawEffect: TGraphicsDrawEffect); overload;   property    property Height: Integer read FHeight write SetHeight default 16;    property HeightForPPI[AImageWidth, APPI: Integer]: Integer read GetHeightForPPI;    property HeightForWidth[AWidth: Integer]: Integer read GetHeightForWidth;    property Width: Integer read FWidth write SetWidth default 16;    property WidthForPPI[AImageWidth, APPI: Integer]: Integer read GetWidthForPPI;    property SizeForPPI[AImageWidth, APPI: Integer]: TSize read GetSizeForPPI; In Ondrej's implementation, every control using an ImageList has a property ImagesWidth which defines the image width needed by the control at 96ppt. (by default, this value is 0, which means that the image width is taken from the Width property of the ImageList). This way one control can extract "small" images, another control "large" images from the same image list. ---------------------------------------------------------------------- circular · 2020-10-17 21:53 Our image list won't be independent from BGRABitmap for sure. We want to draw SVG as well as LZP files (which can be vectorial as well). Though we would like it to be compatible with TCustomImageList so that it can be used in existing components. ---------------------------------------------------------------------- lainz · 2020-10-17 22:36 Yes it will be part of bgracontrols as well. Or lazpaint controls if it requires some lazpaint files. I don't see the point of not using bgrabitmap since its mature. Well tested and works in all major operating systems. If we need it installed with lazarus (if that is the reason of don't use BGRA) why not include bgrabitmap into it finally  Edit: I contacted Ondrej ---------------------------------------------------------------------- lainz · 2020-10-18 01:12 I tried with the actual release of the TCustomImageList and seems that I can't override almost nothing. The virtual methods are useless. I don't blame no one for that, is hard sometimes to define what can be overriden and what not.. ---------------------------------------------------------------------- circular · 2020-10-18 02:22 The other option is to fill the image list with images at some definition. Problem is we don't know the scaling factor before the controls are actually created. When the OnShow event of the form is triggered, then the scaling factor is known. So maybe fill the list at that moment. But it would be much simpler to create the image when they are drawn, because at this point we know the scale. At least I suppose we would need GetResolution method to be virtual, so we can override it. If a resolution is queried that does not exist already, then we could create it at this point, computing all images for this resolution. At the moment, the only working solution I can see is to populate the image list with images with the wanted size without canvas scale and double the size as well. With the Scale property to True if I understand correctly. Or am I missing something? ---------------------------------------------------------------------- lainz · 2020-10-18 02:37 Good idea. I like the idea to add the resolutions from the SVG at runtime. The code is more simple, and it can work as well when adding images by code. The image is computed only once not every time it needs to be drawn as well. I think it will be enough since anyways the wanted image size is fixed in some point, the Width property of the ImageList. Edit: I changed my mind, Is compatible if just you can plug it and work with current image lists, no need of fancy IDE plugin, just adding images by code is good enough. And if we need to trigger some event in order to work, because is not automatic, no problem at all as well, just write some wiki explaining it and that' all. Adding a single line of code OnShow is better than rethinking it again for the IDE plugin or because we need to load the images with code. I prefer anyways storing in project options > resources the stuff, and load with LoadFromResource... methods. Just my opinion, the code will be more easy to do and it will work with a bit of effort of putting a single line of code in the OnShow event. ---------------------------------------------------------------------- Ondrej Pokorny · 2020-10-18 07:49 The needed resolutions are generated at run-time in: 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 TCustomImageListResolutions.GetImageLists-->procedure TCustomImageListResolution.AddImages(  AValue: TCustomImageListResolution);  You need your own TCustomImageListResolution class (probably TSVGImageListResolution) that will override the AddImages method (make it virtual protected) and that will generate the bitmap images from the SVG list. You need to register the new class in TSVGImageList.GetResolutionClass (overridden TCustomImageList.GetResolutionClass). --- Just work on it, modify the LCL image list code as you need (shouldn't be too much). I will review and apply the patches. --- As for the SVG imagelist itself. It's a good idea and if it will be based on RGBA then it should be added into the RGBA project/package, or its own. Everybody can install it easily with the OPM. ---------------------------------------------------------------------- PascalDragon · 2020-10-18 09:52 Quote from: winni on October 17, 2020, 11:15:19 pmA SVG ImageList - that rocks! Especially for small icon sizes (e.g. 16x16 or 24x24) using handmade icons results in much better and cleaner icons than relying on some automatic scaling cause this way one can easily discard details that aren't necessary in these small resolutions. Or one can make sure that indeed one pixel wide lines are used instead of lines that are essentially subpixel thanks to the scaling. ---------------------------------------------------------------------- Ondrej Pokorny · 2020-10-18 10:14 Quote from: PascalDragon on October 18, 2020, 11:52:45 amQuote from: winni on October 17, 2020, 11:15:19 pmA SVG ImageList - that rocks! Especially for small icon sizes (e.g. 16x16 or 24x24) using handmade icons results in much better and cleaner icons than relying on some automatic scaling cause this way one can easily discard details that aren't necessary in these small resolutions. Or one can make sure that indeed one pixel wide lines are used instead of lines that are essentially subpixel thanks to the scaling. SVG supports responsive drawing - i.e. you can define different layers/images for different resolutions within one SVG file. The question is if it is supported by RGBA. Anyway: Actually it would be a good idea to add a function(event handler) to TImageList to generate icon resultions externally. In that case you could add bitmap resolutions for 16px and 24px normally (PNGs) and higher resolutions could be generated from SVG. That would be quite easy to do and with this a normal TImageList would support SVG icons itself - just by calling an event handler to generate the needed image resolutions. In that case a TSVGImageList would just need to store a list for the SVG icons and override the rendering of the bigger resolutions. Simple as that. ---------------------------------------------------------------------- circular · 2020-10-18 12:56 Nope responsive drawing isn't handled by BGRA. Though I think it is ok if we design the icons to look ok at low resolutions. For now, I have found this working solution, where GetUnscaledIcons returns an ImageList with images of the requested size (or compute them by stretching them if necessary). On MacOS basically I create both resolutions anyway. Is it how this is supposed to be done with current TImageList? 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     unscaled := GetUnscaledIcons(ASize);    retina := GetUnscaledIcons(ASize*2);    bmpUnscaled := TBitmap.Create;    bmpRetina := TBitmap.Create;     result := TImageList.Create(nil);    result.Width := ASize;    result.Height := ASize;    result.Scaled := true;    result.RegisterResolutions([ASize, ASize*2]);    for i := 0 to unscaled.Count-1 do    begin      unscaled.GetBitmap(i, bmpUnscaled);      retina.GetBitmap(i, bmpRetina);      result.AddMultipleResolutions([bmpUnscaled, bmpRetina]);    end;     bmpUnscaled.Free;    bmpRetina.Free;    unscaled.Free;    retina.Free; That doesn't work for menus though. ---------------------------------------------------------------------- lainz · 2020-10-18 14:59 Looking good, so no need of the SVG image list for now, it's too complex to integrate. ---------------------------------------------------------------------- circular · 2020-10-18 16:21 Going forward, what I really think would be great would be to be able to render the bitmaps on the fly. Basically when the button draws the glyph from the image list, at that point it could be computed with the adequate resolution. ---------------------------------------------------------------------- BeanzMaster · 2020-10-18 16:53 Hi on Delphi a really cool open source project exist https://github.com/EtheaDev/SVGIconImageList perhaps He can inspire you A good article on svg icon https://www.pushing- pixels.org/2011/11/04/about-those-vector-icons.html Regards ---------------------------------------------------------------------- lainz · 2020-10-18 19:03 Quote from: circular on October 18, 2020, 06:21:12 pmGoing forward, what I really think would be great would be to be able to render the bitmaps on the fly. Basically when the button draws the glyph from the image list, at that point it could be computed with the adequate resolution. Not sure what is needed to override. In bgracontrols we use getbitmap but as well can be used the draw method... We definitely need to edit the sources of imagelist for that you need Lazarus trunk installed... ---------------------------------------------------------------------- lainz · 2020-11-14 14:31 I've implemented the BGRA SVG Image List, is not compatible with TImageList, but it will be useful for new SVG controls. ---------------------------------------------------------------------- circular · 2020-11-14 15:48 I am thinking that we can add a function to populate a TImageList. Like a function with an array of sizes. ---------------------------------------------------------------------- lainz · 2020-11-14 16:41 Quote from: circular on November 14, 2020, 04:48:43 pmI am thinking that we can add a function to populate a TImageList. Like a function with an array of sizes. Good idea. ---------------------------------------------------------------------- winni · 2020-11-14 17:01 Hi! I have not yet looked into the code, but more than  an imageList I would like to get an icon of any size on the fly: 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 MyBGRAbitmap := SVGimageList.exportIcon (1,48,48);  Winni ---------------------------------------------------------------------- lainz · 2020-11-15 01:21 Quote from: winni on November 14, 2020, 06:01:47 pmHi! I have not yet looked into the code, but more than  an imageList I would like to get an icon of any size on the fly: 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 MyBGRAbitmap := SVGimageList.exportIcon (1,48,48);  Winni Good idea, thanks, I will implement it. Edit: Done, is used 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 procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  bmp: TBGRABitmap;begin  bmp := BGRASVGImageList1.Get(0, Bitmap.Width, Bitmap.Height);  Bitmap.PutImage(0, 0, bmp, dmDrawWithTransparency);  bmp.Free;end; ---------------------------------------------------------------------- lainz · 2020-11-15 02:46 Quote from: circular on November 14, 2020, 04:48:43 pmI am thinking that we can add a function to populate a TImageList. Like a function with an array of sizes. Done 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 BGRASVGImageList1.PopulateImageList(ImageList1, [16, 20, 24, 32]); ---------------------------------------------------------------------- circular · 2020-11-15 22:20 Great stuff  In order to have the size fully dynamic depending on the DPI, I suggest that the Width / Height of the image list be interpreted relative to a ReferenceDPI property with default value 96. Then the size in pixels for a certain surface will be Round(Width / ReferenceDPI * TargetDPI) and similarly vertically. Following this principle, the Draw function with only x and y parameters would be replaced by a function with x and y parameters and a target DPI. Alternatively, we can have a Draw function with x and y and a target control or provide a function that computes the DPI. Indeed, the target DPI can be computed from the PixelsPerInch and GetCanvasScaleFactor. To let the controls know what is the resulting size, it would be handy to have a function GetSizeOnSurface(ATargetDPI: integer): TSize. So the controls that use the image list can determine the layout to place the image. What do you think? ---------------------------------------------------------------------- lainz · 2020-11-15 22:28 For me it's ok. By default the image list is designed to have at 96, but I'm not sure on macOS. On Windows say I have 16x16, I must provide in the array the values for each zoom factor, or at least the actual, say only 16 or if its 200%, 16 and 32. ---------------------------------------------------------------------- lainz · 2020-12-13 16:00 Tutorial on how to use the SVG Image List https://forum.lazarus.freepascal.org/index.php/topic,52500.msg387077/t opicseen.html Tutorial on how to use the SVG Image List (Wiki) https://wiki.freepascal.org/SVG_Image_List