In update 13 of the SVG control package, functionality is added to support DPI aware applications.
Scaling, without loss of quality, is of course one of the major benefits of SVG graphics, so they lend themselves well for this kind of application
Delphi VCL
The VCL controls in the SVG Package: TSVG2Control, TSVG2Image and TSVG2LinkedImage will now scale the containing SVG graphic if your application is DPI aware en the DPI settings change.
Here is a bit of technical background how scaling in TSVG2Control is implemented, this is more or less the same for TSVGImage and TSVGLinkedImage:
- A “Scale” property is added to the control
- The “ChangeScale” method from TControl is overridden and will set a new value for “Scale”
- Following a change in size of the control, the embedded “render context” of the control is also resized (this was already the case in previous versions).
- If the SVG renderer draws on the render context, the coordinates are multiplied by “Scale”
- If the SVG renderer needs to find the element on a particular coordinate of the render context, the coordinates are divided by “Scale”
What about the SVG image list?
The TSVG2ImageList, TSVG2LinkedImageList and TSVG2Graphic are not derived from TControl but are just components. These have no parent control and will not scale automatically when DPI settings change (this is the same as with Delphi’s standard TImageList).
To respond to DPI changes, you could write a procedure that updates the size of the images in the SVG image list when this is required. This is something you would have to put into your application yourself, since I can’t implement it in the TSVG2ImageList component.
This procedure could look like this:
procedure TForm1.ImageListScale(aImageList: TSVG2ImageList; M, D: Integer); begin if M <> D then begin aImageList.BeginUpdate; try aImageList.Width := MulDiv(aImageList.Width, M, D); aImageList.Height := MulDiv(aImageList.Height, M, D); finally aImageList.EndUpdate end; end; end;
This procedure must be called, one time when the application starts…
procedure TForm1.FormCreate(Sender: TObject); begin ImageListScale(SVG2ImageList1, CurrentPPI, GetDesignDPI); end;
… and every time the monitor dpi setting changes.
procedure TForm1.FormBeforeMonitorDpiChanged(Sender: TObject; OldDPI, NewDPI: Integer); begin ImageListScale(SVG2ImageList1, NewDPI, OldDPI); end;
If you do this with a normal TImageList, the bitmaps will be stretched, witch degrades the quality of the image. The difference with the SVG image list is that a change in bitmap size will trigger a re-render of the image, which will keep the quality unchanged.
There is of course a performance penalty for the re-render, this will depend on the amount of images in the image list and the complexity of the svg graphics.
An alternative solution is to use multiple image lists with pre-rendered images and then switch between these image lists by updating the image list property of the linked controls.
I updated the VCL version of the SVG viewer demo application so it is DPI aware. So the images in the SVG image list and any SVG graphics that are loaded or added will be scaled according to the monitor settings.
Delphi FMX
The controls in FMX already support scaling, so no extra functionality is added to the FMX SVG controls to support DPI awareness.
The image list in FMX also supports scaling, it isn’t based on fixed sized bitmaps as in VCL but allows for different sized bitmaps, here also nothing had to be changed.
So on the control/component level, there seems to be nothing extra that has to be done.
The only thing we can do, is just check how the application behaves if we declare it DPI aware.
So I checked the “Per Monitor V2” setting in the manifest of the FMX viewer application and gave it a run.
What didn’t work:
- Any controls that have the “ControlType” property on “Platform” won’t scale right, these I had to change to “Styled”
- The application did not respond to change in monitor DPI settings while running.
What did work:
- Starting the application, after changing the monitor scale settings, seems to work o.k.
(Image is from OpenClipart.org “blue-butterfly”)
Conclusion
- The VCL components in the SVG control package will scale automatically in response to any scaling of there parent control
- The VCL components, TSVG2ImageList, TSVG2LinkedImageList, TSVG2Graphic will not scale automatically, you have to deal with that in your application.
- The FMX controls in the SVG control package already support scaling, but although you can declare an FMX application DPI aware, it seems that change in DPI settings while running is not yet supported.
Apart from these changes in update 13, a number of bugs are fixed and the performance for SVG mouse events is much improved, see the change log for a full list.