Stretch/Zoom Image Displayed?

yttrium

Active Member
Licensed User
Longtime User
setBackgroundImage for Panels by default stretches the image to fit the panel. Is there any way to "zoom" it like WinForms does, so it retains the proper aspect ratio (with padding)?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can use this code to resize the image and retain the aspect ratio:
B4X:
Sub ResizeImage(original As Bitmap, TargetX As Int, TargetY As Int) As Bitmap
    Dim origRatio As Float = original.Width / original.Height
    Dim targetRatio As Float = TargetX / TargetY
    Dim scale As Float
    
    If targetRatio > origRatio Then
        scale = TargetY / original.Height
    Else
        scale = TargetX / original.Width
    End If
    
    Dim c As Canvas
    Dim b As Bitmap
    b.InitializeMutable(TargetX, TargetY)
    c.Initialize2(b)
    'set the background
    c.DrawColor(Colors.LightGray)
    Dim r As Rect
    Dim w = original.Width * scale, h = original.Height * scale As Int
    r.Initialize(TargetX / 2 - w / 2, TargetY / 2 - h / 2, TargetX / 2 + w / 2, TargetY / 2+ h / 2)
    c.DrawBitmap(original, Null, r)
    Return b
End Sub
TargetX / TargetY are the width and height of the ImageView.
 
Upvote 0

yttrium

Active Member
Licensed User
Longtime User
Thanks Erel, works great, though I think that should be a configurable property for the component.

Any way to change the sampling scale (from nearest neighbor to perhaps bicubic)? It would probably involve another snippet of code for resizing the image.
 
Last edited:
Upvote 0

yttrium

Active Member
Licensed User
Longtime User
Firefox-18-Soon-to-Be-Aurora-Adds-Better-Image-Scaling-CSS3-Flexbox-and-Retina-Display-Support-2.jpg


That shows the difference between nearest neighbor (left) and bilinear/bicubic (right).
Of course, since that version, the changes have been merged down to stable Firefox so you can't easily compare without downloading an older version (<18).

Simply put, nearest neighbor displays one key pixel per every x pixels, x changing based on scale. At 100%, x = 1. Resolution is also factored into this. Of importance is that only one original pixel is displayed.

With bicubic, pixels are combined before displaying, in order to acquire averages and display those instead (so the missing pixels aren't entirely lost and do affect the image).

The outcome is easily shown below.

bic_ex.jpg
bil_ex.jpg

fan_ex.jpg
nn_ex.jpg


I believe either nearest neighbor or bilinear (as displayed) is used by default for a Canvas.
 
Last edited:
Upvote 0

yttrium

Active Member
Licensed User
Longtime User
You should use ABExtDrawing library and call Paint.setFilterBitmap (True).

Thanks - now that I had the chance to look into it, I can't quite figure out what I would do to replace ResizeImage with the ABExtDrawing library variant.

Could you rewrite it to fit? I don't think rects will work out.
 
Upvote 0

yttrium

Active Member
Licensed User
Longtime User
The code should be almost identical. You should use ABExtDrawing.drawBitmap instead of Canvas.DrawBitmap and pass the Paint object.
I'm aware, my issue is this:

ExtDraw.drawBitmap has four variants (1, 2, 3, 4):
mCanvas, bitmap, SrcRect, DestRect, and paint (1)
mCanvas, bitmap, left (Float), right (Float), and paint (2)
mCanvas, colors() (Int), offset (int), stride (int), x (int), y (int), width (int), height (int), hasAlpha (boolean), and paint (3)
mCanvas, bitmap, Matrix (ABMatrix), and paint (4)

When I do the following (1):

B4X:
Dim ExtDraw As ABExtDrawing
Dim paint As ABPaint
paint.setFilterBitmap(True)
paint.SetAntiAlias(True)
ExtDraw.drawBitmap(C, original, Null, R, paint)
return b

I get:

B4X:
An error has occurred in sub: main_resizeimage (java line: 1301)
java.lang.NullPointerException
Continue?

EDIT: Nevermind, I simply had to add the following line:
B4X:
paint.Initialize()
After declaring paint, and then it works as expected. Thanks Erel!
 
Last edited:
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
I get this error with large project. Ok with small projects

B4X:
Sub ResizeImage(original As Bitmap, TargetX As Int, TargetY As Int) As Bitmap
    Dim origRatio As Float = original.Width / original.Height
    Dim targetRatio As Float = TargetX / TargetY
    Dim scale As Float
    
    If targetRatio > origRatio Then
        scale = TargetY / original.Height
    Else
        scale = TargetX / original.Width
    End If
    
    Dim c As Canvas
    Dim b As Bitmap
    b.InitializeMutable(TargetX, TargetY)
    c.Initialize2(b)
    'set the background
    c.DrawColor(Colors.LightGray)
    Dim r As Rect
    Dim w = original.Width * scale, h = original.Height * scale As Int
    r.Initialize(TargetX / 2 - w / 2, TargetY / 2 - h / 2, TargetX / 2 + w / 2, TargetY / 2+ h / 2)
    'c.DrawBitmap(original, Null, r)
   
   Dim ExtDraw As ABExtDrawing
   Dim paint As ABPaint
   paint.Initialize
   paint.setFilterBitmap(True)
   paint.SetAntiAlias(True)
   ExtDraw.drawBitmap(c, original, Null, r, paint)

    Return b
End Sub


B4X:
Parsing code.                           1.21
Compiling code.                         0.79
Compiling layouts code.                 0.01
Generating R file.                      4.66
Compiling generated Java code.          Error
B4A line: 1563
End Sub
javac 1.6.0_26
src\Scantech\CarGaugePro\main.java:21497: cannot find symbol
symbol  : class AB
location: class Scantech.CarGaugePro.com
com.AB.ABExtDrawing.ABExtDrawing _extdraw = null;
   ^
1 error
 
Last edited:
Upvote 0

Scantech

Well-Known Member
Licensed User
Longtime User
Now it works. Just what I was looking for. Thanks Erel and yttrium. Thanks
 
Last edited:
Upvote 0
Top