Picture Mask: Wrong Resolution

Hello,

I create a HiDPI application in which I want to draw an image with a mask. It is simply a matter of drawing a graphic in a RoundRect. The image is available in Low-Res and Hi-Res. Unfortunately the masked image always uses the low-res image. I have created a sample project in which both images are drawn next to each other. Where is the error?

[code]PictureMask = New Picture(Note.Width, Note.Height, 32) ’ Note = ImageSet

’ masked pics start all white
PictureMask.Graphics.ForeColor = &c00000000
PictureMask.Graphics.FillRoundRect(0, 0, PictureMask.Width, PictureMask.Height, 16, 16)

Picture = New Picture(Note.Width, Note.Height, 32)
Picture.ApplyMask(PictureMask)
Picture.Graphics.DrawPicture(Note, 0, 0)[/code]

direct link:
https://www.dropbox.com/s/fm6s785unp5w2h4/Picture%20Mask.zip?dl=1

Martin:
the two images are… white (as far as I can tell) and the project was built with 19r2.

The ImageSet defines three images…

Nope, the project was built with 2019.011
And the pictures aren’t white, the have a structure. The third image is only needed on Windows, I’m on macOS.

Doh !

Xojo 2019r1.1, on run, tells me that !

This project was saved with a newer version of Xojo (version 2019.02). Xojo will convert your project to work with this version (version 2019.011). This could result in data loss should you choose to save your project.

This is not a problem if you say so.

I’m on macOS too.

I download it once more.

The images seems to be empty on the web site too. Can you check ?

Weird! It’s 2019r1.1.

I’ve checked it and the pictures (Note.png, NoteSmall.png) are in the Zip Folder.

So, it is in my computer !

Sorry to bother you.

note.width and note.height are the only things you really use from the note image

and you create a single, 72 DPI picture from that for the mask, on line 1, and picture you’re going to draw, on line 7

why would you expect your code to do anything else ?

Note is an ImageSet. My understanding of ImageSets is that they automatically output the correct image for the correct screen resolution. In case of

' HiDPI Picture g.DrawPicture(Note, 250, 20)
that’s how it works. But apparently the Width/Height property of the ImageSet only returns the Width/Height of the first image in it.
Norman, can you tell me what needs correcting?

they do
but you created an 1x image on the lines I noted
IF you want a 2x then you should create the correctly sized image AND set the horizontal & vertical resolution to 144
basically use note.height * whatever the windows scale factor is
same for the width
and set the mask and image horizontal & vertical resolutions too their original values * window scale factor

that should do what you need
however its hard to tell from your sample since the note is just a white rectangle

logically ALL the images in the image set ARE the same size :slight_smile:
64 x 64 @ 72 DPI is the same drawn size as 128 x 128 @ 144
the pixels in the 128 x 128 are twice as dense meaning the actual drawn size is 1/2 that size :slight_smile:
and in a 3 x the pixels are 3x as dense so the image is 1/3 that size when drawn

Like this? As you can see in the screenshot, this does not lead to the desired result. The edges of the rounded rectangle always show the wrong resolution. I just want the image to be 360x332 in HiDPI mode and 180x166 in Low-Res mode. As you can see, if I draw note directly via DrawPicture in the Paint-Event, the correct image will be selected automatically, depending on the screen resolution.

Norman, I don’t understand your suggestions. Would you please be kind enough to modify my project so that I can see exactly where the changes are needed?

[code]’ PictureMask = New Picture(Note.Width, Note.Height, 32)
PictureMask = New Picture(Note.Width * 2, Note.Height * 2, 32)

’ masked pics start all white
PictureMask.Graphics.ForeColor = &c00000000
PictureMask.Graphics.FillRoundRect(0, 0, PictureMask.Width, PictureMask.Height, 16, 16)

’ Picture = New Picture(Note.Width, Note.Height, 32)
Picture = New Picture(Note.Width * 2, Note.Height * 2, 32)
Picture.ApplyMask(PictureMask)
Picture.Graphics.DrawPicture(Note, 0, 0)[/code]

PictureMask = New Picture(Note.Width * TrueWindow.ScaleFactor, Note.Height * TrueWindow.ScaleFactor, 32)
PictureMask.HorizontalResolution = PictureMask.HorizontalResolution * TrueWindow.ScaleFactor
PictureMask.VerticalResolution = PictureMask.VerticalResolution * TrueWindow.ScaleFactor

' masked pics start all white
PictureMask.Graphics.ForeColor = &c00000000
PictureMask.Graphics.FillRoundRect(0, 0, PictureMask.Width, PictureMask.Height, 16, 16)

Picture = New Picture(Note.Width * TrueWindow.ScaleFactor , Note.Height * TrueWindow.ScaleFactor, 32) 
Picture.HorizontalResolution = PictureMask.HorizontalResolution * TrueWindow.ScaleFactor
Picture.VerticalResolution = PictureMask.VerticalResolution * TrueWindow.ScaleFactor

Picture.ApplyMask(PictureMask)

Picture.Graphics.DrawPicture(Note, 0, 0)

should create a picture that is @wx on and @2x screen and a 1x on a 1x screen

that said the rounded corners may always be a bit jaggy

Thanks Norman! I compared your code in Low-Res and HiDPI-Mode. There are still differences, please look:
Low-Res Mode

HiDPI Mode

I’m writing this code off the top of my head in the forums so it is “close” at best

make sure you also put in the corners arc being mutiplied by the scale as well
other wise they end up smaller in the hi dpi version

PictureMask.Graphics.FillRoundRect(0, 0, PictureMask.Width, PictureMask.Height, 16 * TrueWindow.ScaleFactor, 16* TrueWindow.ScaleFactor)

remember that on a HI DPI scree things are many times DENSER (more pixels per inch) so to get an apparent 64 by 64 image on a 2x screen you draw a 128 x 128
and also if you want a corner arc of 16 then it has to be 32 x 32

The rounded rectangle now draws correctly in Low-Mode and HiDPI Mode. But the Picture Mask in HiDPI is still to small and looks like it will draw the Low-Res Note picture. Why?

[code]Dim width As Integer = Note.Width * TrueWindow.ScaleFactor
Dim height As Integer = Note.Height * TrueWindow.ScaleFactor

PictureMask = New Picture(width, height, 32)
PictureMask.HorizontalResolution = PictureMask.HorizontalResolution * TrueWindow.ScaleFactor
PictureMask.VerticalResolution = PictureMask.VerticalResolution * TrueWindow.ScaleFactor

’ masked pics start all white
PictureMask.Graphics.ForeColor = &c00000000
PictureMask.Graphics.FillRoundRect(0, 0, PictureMask.Width, PictureMask.Height, 16 * TrueWindow.ScaleFactor, 16 * TrueWindow.ScaleFactor)

Picture = New Picture(width , height, 32)
Picture.HorizontalResolution = Picture.HorizontalResolution * TrueWindow.ScaleFactor
Picture.VerticalResolution = Picture.VerticalResolution * TrueWindow.ScaleFactor

Picture.ApplyMask(PictureMask)

Picture.Graphics.DrawPicture(Note, 0, 0)[/code]
HiDPI Mode

you mean the VERY LAST line ?
drawpicture doesnt select one of a multi image as far as I know
you might have to programmatically find the one in there that is 2x and draw that

Exactly.

[quote=459926:@Norman Palardy]drawpicture doesnt select one of a multi image as far as I know
you might have to programmatically find the one in there that is 2x and draw that[/quote]
I don’t think so, because in the Window1.Paint event it does:

[quote=459886:]My understanding of ImageSets is that they automatically output the correct image for the correct screen resolution. In case of

' HiDPI Picture g.DrawPicture(Note, 250, 20)
that’s how it works.[/quote]
If you take a close look at the Note and NoteSmall images, you will see that Note.png is automatically selected on the right side. Admittedly, due to the barely visible structure on the picture it is difficult, but you can still see it. On the right the structure is much finer than on the left.

you’re not drawing to a graphics object that came from a screen but to an in memory picture you created dynamically
this is relevant

I see no difference in how I mask the image whether I do

Dim notePic As picture = note
For i As Integer = 0 To notePic.ImageCount - 1
 if notePic.IndexedImage(i).HorizontalResolution = picture.HorizontalResolution then
 Picture.Graphics.DrawPicture(notepic.IndexedImage(i), 0, 0)
 End If
Next

or

Picture.Graphics.DrawPicture(note, 0, 0)

but then I have no idea what you’re looing at and seeing when you say

I see two white boxes
one with round corners & one with square corners
if theres more detail there I’m missing it completely

try this
I put some detail on the small and large JUST so differences could be shown end are easier to see http://great-white-software.com/miscellaneous/Picture%20Mask.zip

in this case its much easier to see that NOT grabbing the right indexed image does indeed draw the low rez version
and that you can work around it by grabbing and drawing the one that is the right DPI