Android Question Bitmap Density Issue (ImageView vs Canvas)

thedesolatesoul

Expert
Licensed User
Longtime User
I am having some problems in showing and drawing a bitmap.
Basically I load a bitmap, set it in an ImageView. Now I want to draw the same bitmap to a panel using a canvas. But I want to draw only the part visible in the imageview.
However, it seems the bitmap in the imageview is scaled up (I am not sure if it is losing quality scaling up) and the bitmap drawn by the canvas is not.
Now, this may be related to Density and Scaling, however I am not sure what I am supposed to fix.
- Do I set the bitmap density to 160x2, this causes the ImageView to show a smaller bitmap
- Do I draw using the canvas a bigger image by changing the destRect dimensions by 2.

I know how to get around this, but I do not know what the correct solution is.
Is the ImageView misbehaving or the Canvas?

I attached the sample here to demonstrate the issue (my guess is you will only see it with a device with Density <> 1).
 

Attachments

  • BitmapDensityIssue.zip
    292.4 KB · Views: 408

LucaMs

Expert
Licensed User
Longtime User
Perhaps using a less complex picture we could understand better.

I did not understand your text (write Italian, please :D) but I've tried the "app".

The top image, the ImageView, is not complete, it seems to be the central part.
In the panel there is the upper part of the image.

What do you want to achieve? (change image, please :))


[Also, I do not have the screen 600x1000. Need I to scale the screen? Do you work on a device which has those dimensions?]
 
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Yes, the bitmap is upscaled in the ImageView.
I changed in your code:
B4X:
srcRect.Initialize(0,0,Panel1.Width,Panel1.Height)
to
B4X:
Dim scale = 1000dip / 1000
srcRect.Initialize((bmp.Width - Panel1.Width / scale) / 2, (bmp.Height - Panel1.Height / scale) / 2, (bmp.Width + Panel1.Width / scale) / 2, (bmp.Height + Panel1.Height / scale) / 2)
The default gravity for the ImageView is Gravity.NOGRAVITY it centers the bitmap like Gravity.CENTER.
So I defined the source rectangle to
Left = middle of the bitmap minus half width of the Panel devided by the scale.
Top = middle of the bitmap minus half height of the Panel devided by the scale.
Right = middle of the bitmap plus half width of the Panel devided by the scale.
Bottom = middle of the bitmap plus half height of the Panel devided by the scale.

You could also do it that way :
B4X:
Dim bdw As BitmapDrawable
bdw.Initialize(bmp)
bdw.Gravity = Gravity.CENTER
Panel1.Background = bdw
 

Attachments

  • BitmapDensityIssue1.zip
    292.6 KB · Views: 308
Last edited:
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
Thank you Klaus for the example.
So from what I understand you are saying the ImageView is correctly upsampling to display the same image on any device density.
So I need to upsample the image on the canvas as well.

I also want to mention it is possible to set the density on a bitmap using (AcceleratedSurface library):
B4X:
    Dim IU As AS_ImageUtils
    IU.SetDensity(originalBmp, 160 * Density)
But using that, you would downsample the bitmap.

LucaMS,
I think I created some confusion because the imageview always centres the image as klaus said. I didnt really want that.
But I guess you should supply the bitmaps, yours are better :p
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
So from what I understand you are saying the ImageView is correctly upsampling to display the same image on any device density.
So I need to upsample the image on the canvas as well.
That's how I understand it too. To get the same image as in the ImageView I had to devide the width and height of the Panel by the density when using the Canvas.
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
Thank you Klaus for the example.
So from what I understand you are saying the ImageView is correctly upsampling to display the same image on any device density.
So I need to upsample the image on the canvas as well.

I also want to mention it is possible to set the density on a bitmap using (AcceleratedSurface library):
B4X:
    Dim IU As AS_ImageUtils
    IU.SetDensity(originalBmp, 160 * Density)
But using that, you would downsample the bitmap.

LucaMS,
I think I created some confusion because the imageview always centres the image as klaus said. I didnt really want that.
But I guess you should supply the bitmaps, yours are better :p
To solve a density problem with bitmaps, the first thing to do is to replace all LoadBitmap and LoadBitmapSample with LoadScaledBitmap from my Accelerated Surface library. After loading the bitmap Erel sets its density to 160. I don't know why so I wrote my own function to keep the density unchanged and, in the process, I added some code to use less memory and allow to handle yourself the Out of Memory errors, so from my point of view there's no reason to use LoadBitmap or LoadBitmapSample.
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
That's how I understand it too. To get the same image as in the ImageView I had to devide the width and height of the Panel by the density when using the Canvas.
Yes, I am now using your technique to scale it up and it is working well. I will post a demo soon.

To solve a density problem with bitmaps, the first thing to do is to replace all LoadBitmap and LoadBitmapSample with LoadScaledBitmap from my Accelerated Surface library. After loading the bitmap Erel sets its density to 160. I don't know why so I wrote my own function to keep the density unchanged and, in the process, I added some code to use less memory and allow to handle yourself the Out of Memory errors, so from my point of view there's no reason to use LoadBitmap or LoadBitmapSample.
Hi Informatix,
I read your post about this on another thread before as well, and then this confused me more. When LoadBitmap re-sets the density to 160, how come the ImageView shows the image with the correct density? (or it it wrong? (or is it because it is converted to a bitmap drawable (as klaus did above)))
I am using CreateScaledBitmap from your AS library but after loading it with LoadBitmap, I can change it if needed, but at the moment I am trying to understand if the ImageView is correct.

Thank you
 
Upvote 0

Informatix

Expert
Licensed User
Longtime User
how come the ImageView shows the image with the correct density?

What do you mean by "correct density"? The ImageView displays the bitmap with the density set for the bitmap (and it will scale it down or up when its density is different from the screen density). The Canvas, on the contrary, cannot work with anything else than the screen density.

If you force a bitmap to a certain density, you will get the same visual size on all devices if the ImageView is sized in dip units. That's probably what Erel wanted when he wrote LoadBitmap. It's not a bad thing if you create UIs that ignore the device screen size, but it's not the case of most UIs. So if you size your ImageView in % units or if you don't want to have troubles with the canvas, it's better to not force the density (and your ImageView will have less work to do as the scale is 1:1 after loading the file).
 
Upvote 0

thedesolatesoul

Expert
Licensed User
Longtime User
That is a good explanation. I didnt realize the ImageView will scale the bitmap depending on bmpDensity vs ScreenDensity.

Normally I would want the ImageView to automatically scale the image, otherwise it looks too small on higher density devices. However the ImageView is one of the more annoying views where there isnt great control over the scaling+gravity.

I can see the issue with canvas/drawing bitmaps etc, it is up to the designer to add scaling (e.g. in games etc).
 
Upvote 0
Top