Gustav Schubert 25 Posted September 17, 2020 (edited) This is about the result of testing my FMX app on a high resolution screen, Windows platform. ( A TImage component is the central component on my form, I am drawing onto its bitmap, it has a known fixed size. ) Using ImageWrapMode = TImageWrapMode.Original. Using project options - application- manifest - dpi support = PerMonitorV2. Using 10.3.3. Test is done on a 4K Monitor with Scaling of 2.0. The TImage (which I will draw on) will appear half the size.All components are scaled automatically, except TImage. I tried to work around the issue. Depending on Handle.Scale I can make the Image and Bitmap bigger, and then draw with a scaling transform, it works. But then I also need to adapt custom layout code because I am using Width and Height of components to stack them horizontally or vertically. And this is not nice if one component uses different 'units' for Width and Height. I have reverted back to using Dpi-Support of None, since in this mode the scaling of TImage is done automatically. So, all is well now, except that I could spam some site with 125 lines of minimal test form code! Edited September 17, 2020 by Gustav Schubert Share this post Link to post
Gustav Schubert 25 Posted September 19, 2020 (edited) From docwiki: Original - displays the image with its original dimensions. Fit - provides the best fit, keeping image proportions (the ratio between the width and height) for the TImage rectangle. If needed, the image is scaled down or stretched to best fit the rectangle area. This is the default option. In mode original the image should be clipped - ok - but should it not still be scaled according to the sceen scaling factor? Or is the intention really that it appears smaller on a high resolution screen, relative to other controls? Edited September 19, 2020 by Gustav Schubert Share this post Link to post
Gustav Schubert 25 Posted September 20, 2020 Observation 1: If I use PerMonitorV2 then the text of controls like ListView will be sharper. This is why I want to keep using it. Observation 2: I have been able to produce sharp drawings which take advantage of the many pixels of the 4K screen, in PerMonitorV2 mode. Unfortunately the effort is high, in terms of extra code that I need to write for correct layout and manual scaling. At first I thought that the DrawImage method of TImage might have a bug. But by now I have tested out a change - with only partial success. I can make the drawing scale as I want, but it will appear slightly blurred, because it gets upscaled, as with Dpi-Support None. Status: In order to get a sharp drawing I need to leave EMBA code as is and do the additional work. Problem is of course that I cannot and want not do that in in my bigger application for some existing drawings, not now, and maybe never. For now I will go with sharp text and slightly blurred drawings. Share this post Link to post
Gustav Schubert 25 Posted September 21, 2020 I'm off because I had an odd dream about TImage.UpdateCurrentBitmap; and now I need to read more about MultiResImages. overridden procedure TImage.Paint; begin NewUpdateCurrentBitmap; if FCurrentBitmap <> nil then MyDrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity); end; //private procedure TImage.UpdateCurrentBitmap; strictly; ignore; public procedure TImage.NewUpdateCurrentBitmap; possible; abstract; public MyDrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity); virtually; easy; unchanged procedure TImage.SetBitmap(const Value: TBitmap); var LBitmap: TBitmap; begin LBitmap := GetBitmap; if LBitmap <> nil then LBitmap.Assign(Value); end; function TImage.GetBitmap: TBitmap; var Item: TCustomBitmapItem; begin Result := nil; // Return the most appropriate non-empty picture // ? end; Share this post Link to post
Gustav Schubert 25 Posted September 23, 2020 (edited) Progress: Now I have sharp text for the controls AND a sharp drawing on a high resolution screen. I need to scale the drawing - when I do the drawing, and I need to provide a Bitmap which is big enough to show everything. Width and Height of the Image need to be set to the unscaled values: private FScale: single; BitmapWidth: Integer; BitmapHeight: Integer; Image: TImage; procedure TForm1.FormCreate(Sender: TObject); var Bitmap: TBitmap; begin FScale := Handle.Scale; { nominal bitmap size, fixed at time of creation } BitmapWidth := 800; BitmapHeight := 800; Bitmap := TBitmap.Create(Round(BitmapWidth * FScale), Round(BitmapHeight * FScale)); Bitmap.Clear(claWhite); Assert(FScale = Image.Scene.GetSceneScale); { Image Width and Height can change later with alignment or anchoring } Image.Width := BitmapWidth; // unscaled (nominal) value Image.Height := BitmapHeight; Image.Bitmap := Bitmap; Bitmap.Free; // image has copy via assign Image.WrapMode := TImageWrapMode.Original; end; { g = Image.Bitmap.Canvas } procedure TForm1.DrawToCanvas(g: TCanvas); begin g.Offset := TH.Offset; // transform helper if g.BeginScene then try g.SetMatrix(TMatrix.CreateScaling(FScale, FScale)); g.Clear(claWhite); // ... finally g.EndScene; end; end; The TImage is good as is. No bug report and no feature request from me. But I have built myself a significantly more lightweight TOriginalImage control (less than 200 lines), which features a read only Bitmap property. I will no longer provide the Bitmap - only the NominalSize. Whenever I access Image.Bitmap.Canvas to draw on it: the Bitmap will have the correct size for the current monitor I still need to do the scaling via matrix I need to call Image.Repaint after drawing. Moving the form from one monitor to another with different scaling should work, because my new component has a ScaleChangedHandler, as does TImage. The TImage from FMX.Objects works ok, it is just difficult to understand, too much MultiResBitmap stuff which I do not need - when I just want to draw on it. Edited September 23, 2020 by Gustav Schubert Share this post Link to post