Jump to content
Sign in to follow this  
Gustav Schubert

ImageWrapMode.Original and Dpi-Support PerMonitorV2

Recommended Posts

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 by Gustav Schubert

Share this post

Link to post

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 by Gustav Schubert

Share this post

Link to post

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. :classic_rolleyes:

Share this post

Link to post

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;
  if FCurrentBitmap <> nil then
    MyDrawBitmap(Canvas, LocalRect, FCurrentBitmap, AbsoluteOpacity);

//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);
  LBitmap: TBitmap;
  LBitmap := GetBitmap;
  if LBitmap <> nil then

function TImage.GetBitmap: TBitmap;
  Item: TCustomBitmapItem;
  Result := nil;
  // Return the most appropriate non-empty picture
  // ?


Share this post

Link to post

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:


    FScale: single;
    BitmapWidth: Integer;
    BitmapHeight: Integer;
    Image: TImage;

procedure TForm1.FormCreate(Sender: TObject);
  Bitmap: TBitmap;	
  FScale := Handle.Scale;

  { nominal bitmap size, fixed at time of creation }
  BitmapWidth := 800;
  BitmapHeight := 800;
  Bitmap := TBitmap.Create(Round(BitmapWidth * FScale), Round(BitmapHeight * FScale));

  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;

{ g = Image.Bitmap.Canvas }
procedure TForm1.DrawToCanvas(g: TCanvas);
  g.Offset := TH.Offset; // transform helper
  if g.BeginScene then
    g.SetMatrix(TMatrix.CreateScaling(FScale, FScale));
    // ...


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 by Gustav Schubert

Share this post

Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this