Android Question How to stretch a picture non rectangular?

Gunther

Active Member
Licensed User
Longtime User
How can I stretch a picture to a non rectangular shape?

Like, one have the 4 coordinates of the 4 corner points which may not form a rect but has 4 sides.

Not a standard streching or scaleing.
 
Last edited:

MarkusR

Well-Known Member
Licensed User
Longtime User
i believe u will save the picture aspect ratio,true?
i used this to fit a picture inside a rectangle area.
it modified the imageview x,y,width,height so it works once else u need reset to default pos,size.

B4X:
Sub AdjustImageView(Imv As ImageView, bmp As Bitmap)

    'MR 09.09.2018 (from vb6)

    Dim bx1 As Long
    Dim by1 As Long
   
    Dim bx2 As Long
    Dim by2 As Long
   
    Dim f1 As Float
    Dim f2 As Float

    Dim ox,oy,oxx,oyy As Float

    ox = Imv.Left
    oy = Imv.Top
   
    oxx = Imv.Width
    oyy = Imv.Height
 
    bx1 = bmp.Width
    by1 = bmp.Height
   
    bx2 = oxx
    by2 = oyy

    If bx1 = 0 Or by1 = 0 Then 'größe wie PictureBox
        bx1 = bx2
        by1 = by2
    End If
   
    f1 = 1.0
    f2 = 1.0
 
    If bx1 <> bx2 Then 'ohne ZOOM > mit ZOOM <>
        f1 = bx2 / bx1
    End If
    If by1 <> by2 Then
        f2 = by2 / by1
    End If
 
    If f2 < f1 Then f1 = f2

    Imv.Gravity = Bit.Or( Gravity.FILL,Gravity.CENTER)
 
    Imv.Left = ox + oxx / 2.0 - (bx1 * f1) / 2.0
    Imv.Top = oy + oyy / 2.0 - (by1 * f1) / 2.0
 
    Imv.Width = f1 * bx1
    Imv.Height = f1 * by1
 
    Imv.Bitmap = bmp
 
End Sub
 
Last edited:
Upvote 0

Gunther

Active Member
Licensed User
Longtime User
Thanks for that answer but a rectangular picture should be streched so that is not any more rectangular

Like left side is 80% right side 60% of the 100% as it was in the source.
 
Last edited:
Upvote 0

MarkusR

Well-Known Member
Licensed User
Longtime User
if u using the both anchors <-> the image view fits the activity screen and the image is stretched by default into this area.
if u will have space at border u can set size in ui designer script also.
it means if the imageview is a square, the image into is a square too because its stretched or shrinked at x or y axis.
B4X:
'All variants script
AutoScaleAll
ImageView1.SetLeftAndRight(10%x,90%x)
ImageView1.SetTopAndBottom(10%y,90%y)
 
Last edited:
Upvote 0

Gunther

Active Member
Licensed User
Longtime User
Well, the left and right borders are still parallel but the top and bottom borders are not.
It will not be a rectangle afterwards. Just a Trapez.
 
Upvote 0

Gunther

Active Member
Licensed User
Longtime User
Yes, well easy:

Perspective.PNG


Exactly, the transform of the picture from the original rect to the to new shape. So, not how to convert the corner points - this is of no question, the transform of the content picture to the new shape it the question behind this post.
 
Last edited:
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
You can apply transforms to the Android Views that hold the bitmaps (scale, rotateX, rotateY, rotateZ...) and can get all kind of perspectives. However, the inverse problem is difficult: predefining the coordinates of the transformed view and then figuring out the needed operations is not obvious.

Second approach is to apply the desired transform to the content bitmap and leave the container ImageView 'flat', and place it in an ImageView the dimensions of which are the bounding box of the transformed bitmap.

Screenshot_2018-11-07-14-28-04.png

This is an example code of the 2nd approach using inline Java. Note that you can define the distortion points :)
B4X:
Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
   
    Dim W0 As Int = Activity.Width/3        ' Original dimensions for a square bitmap
   
    '***************************************************************
    ' Will draw something. Can also load a picture
    '***************************************************************
    Dim B0 As Bitmap
    B0.InitializeMutable(W0,W0)
    Dim c As Canvas
    c.Initialize2(B0)

    Dim mRect As Rect
    mRect.Initialize(0,0,B0.Width,B0.Height)
    c.DrawRect(mRect, Colors.Blue,True, 2dip)   
    c.DrawCircle(W0/2,W0/2,W0/2,Colors.Yellow,True,4)
    Dim IV As ImageView
    IV.Initialize("")
    Activity.AddView(IV,Activity.Width/2-W0/2, Activity.Height/4-W0/2,W0,W0)
    IV.Bitmap = B0
   
    '***************************************************************
    ' Source points are the boundaries of the original picture   
    '***************************************************************
    Dim srcPoints() As Float = Array As Float( _
        0   , 0   , _
        W0-1, 0   , _
        W0-1, W0-1, _
        0   , W0-1 _
    )
   
    ' Here we define the 4 distorted edges (pairs of coordinates, that are the edges in clockwise order). For reference, keep the first at origin.
    ' We are defining it to be 2*W0 width, the same height on first vertical side, 2*W0/3 on the second,
    ' and skewed. Can be changed at will.
    Dim dstPoints() As Float = Array As Float( _
        0     , 0   , _
        2*W0, -W0/3  , _
        2*W0,   W0/3, _
        0     , W0 _
    )   

    '***************************************************************
    ' Create the distorted version, according to defined points
    '***************************************************************
    Dim J As JavaObject
    J.InitializeContext
    Dim B1 As Bitmap = J.RunMethod("distortBitmap", Array(B0,srcPoints, dstPoints))
   
#if 0   
    ' Tried with JavaObject but get a Runtime Error regarding createBitmap, it does not accept JM (Null) works)
    Dim JM As JavaObject = J.InitializeNewInstance("android.graphics.Matrix",Null)
    Dim res As Boolean = JM.RunMethod("setPolyToPoly", Array( srcPoints, 0, dstPoints, 0, 4))
    Dim JB As JavaObject = J.InitializeStatic("android.graphics.Bitmap")
    B1 = JB.RunMethod("createBitmap",Array(B0,0,0,W0,W0,JM,True))
#end if   

    '***************************************************************
    ' Now we get an ImageView as large as B1 bounds. 
    ' Will draw it centered on the second half of our portrait display
    '***************************************************************
    Dim W1 As Int = B1.Width
    Dim H1 As Int = B1.Height
    Dim IV2 As ImageView
    IV2.Initialize("")
    Activity.AddView(IV2,Activity.Width/2-W1/2, 3*Activity.Height/4-H1/2,W1,H1)
    IV2.Bitmap = B1
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

#if JAVA
import android.graphics.Bitmap;
import android.graphics.Matrix;

public Bitmap distortBitmap(Bitmap B0, float[] src,float[] dst) {

    Matrix M = new Matrix();
    M.setPolyToPoly(src,0,dst,0,4);
    Bitmap B1 = Bitmap.createBitmap(B0,0,0,B0.getWidth(),B0.getHeight(), M, true);
    return B1;
}
#End If
 
Upvote 0
Top