B4J Question Scale images on a video player.

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

I created an encoder to encode particular custom video files.

This encoder encodes audio+video interleaved on same file, in a particular way that microcontrollers can read as fast possible.
After this I created a player for it on desktop side, to inspect the final video before to use on microcontrollers (becuse it is my custom format it cannot play on any default players and I had to develop my custom player).

After some troubles the video player now works well, video+audio are synced.

The problem now is that I want to add the zoom.

I already use the B4XPages_Resize event to resize the panel and the canvas inside it based on form size. I know I have to calculate and mantain the aspect ratio, this is not a big problem now. The problem is that I cannot use LoadBitmapResize or similar, because I don't have saved images, they are just arrays of bytes I read from the file.

I want to know how I can scale that, only bigger size is needed, there is no need to scale smaller, this because the videos are small in resolution, to be adapted to TFT screens, so, the max size of 480x320.

Actually I convert bytes to an Image and use Canvas.DrawBitmap to draw.

May using an ImageView I can get it to work ? But there are ways to adapt it to a Canvas without switch to an ImageView ?

Here some relevant parts of my code:
B4X:
    Try
        FramePos = Video.DataChunkStart + (Video.FrameBlockSize * FrameNumber)
 
        Dim Image(FrameLen) As Byte  ' Redim
        ReadBytes = RAF.ReadBytes(Image, 0, FrameLen, FramePos)
 
        If ReadBytes <> Video.VideoBlockSize Then
            LogError("Different frame read bytes. Read bytes: " & ReadBytes & "  Expected: " & Video.VideoBlockSize)
            Return False
        End If
 
        Dim Rect As B4XRect
        Rect.Initialize(0, 0, Video.Width, Video.Height)
        Canvas1.DrawBitmap(BytesToImage(Image), Rect)
        Canvas1.Invalidate
 
        ...........
        ...........

Sub B4XPage_Resize (Width As Int, Height As Int)
    Panel1.SetSize(Width, Height - lblTime.PrefHeight - Slider1.PrefHeight)
    Canvas1.Resize(Width, Height - lblTime.PrefHeight - Slider1.PrefHeight)
    Clear(xui.Color_Black)
    Canvas1.Invalidate
End Sub
 
Public Sub BytesToImage(bytes() As Byte) As B4XBitmap
    Dim In As InputStream
    In.InitializeFromBytesArray(bytes, 0, bytes.Length)
#if B4A or B4i
   Dim bmp As Bitmap
   bmp.Initialize2(In)
#else
    Dim bmp As Image
    bmp.Initialize2(In)
#end if
    Return bmp
End Sub

Here some code I can use to mantain aspect ratio when form is scaled:
B4X:
Public Sub ResizeWithAspectRatio(newWidth As Int)
    Dim aspectRatio As Float = Video.Width / Video.Height
    Dim newHeight As Int = newWidth / aspectRatio
 
    Dim f As Form = B4XPages.GetNativeParent(Me)
    f.WindowWidth = newWidth + 16
    f.WindowHeight = newHeight + 39 + lblTime.PrefHeight + Slider1.PrefHeight
 
    Panel1.SetLayoutAnimated(0, 0, 0, newWidth, newHeight)
    Canvas1.Resize(newWidth, newHeight)
End Sub
 

Attachments

  • Screenshot 2025-08-01 222445.png
    Screenshot 2025-08-01 222445.png
    85.7 KB · Views: 35
Last edited:

TILogistic

Expert
Licensed User
Longtime User
You have several options for working with images.
BitmapCreator, JavaObject, Python.

BitmapCreator.
You can add the aspect ratio calculation
ex.
B4X:
Private Sub Button1_Click
'    simulate and transform bytes
    Dim img As B4XBitmap = xui.LoadBitmap(File.DirAssets, "1.png")
    Dim ImgBytes() As Byte = ImageToBytes(img)
'    ----------------------

    Dim image1 As B4XBitmap = BytesToImage(ImgBytes)
    Log($"${image1.Width} ${image1.Height}"$)
   
    ImageView1.SetBitmap(image1)
   
    Dim bc As BitmapCreator
    bc.Initialize(600, 600) 'scale
    bc.DrawBitmap(image1, bc.TargetRect, True)
   
    Dim image2 As B4XBitmap = bc.Bitmap
    Log($"${image2.Width} ${image2.Height}"$)
   
    ImageView2.SetBitmap(image2)
End Sub

Public Sub ImageToBytes(Image As B4XBitmap) As Byte()
    Dim out As OutputStream
    out.InitializeToBytesArray(0)
    Image.WriteToStream(out, 100, "JPEG")
    out.Close
    Return out.ToBytesArray
End Sub

Public Sub BytesToImage(bytes() As Byte) As B4XBitmap
    Dim In As InputStream
    In.InitializeFromBytesArray(bytes, 0, bytes.Length)
#if B4A or B4i
   Dim bmp As Bitmap
   bmp.Initialize2(In)
#else
    Dim bmp As Image
    bmp.Initialize2(In)
#end if
    Return bmp
End Sub

1754161295241.png
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Hi @TILogistic thanks for reply and good advices.

I found a solution to work on canvas but with BitmapCreator, here my code:
B4X:
Dim bmp As B4XBitmap = BytesToImage(Image)
Dim zoomedBmp As B4XBitmap = ZoomBitmap(bmp, Canvas1.TargetRect.Width, Canvas1.TargetRect.Height)
Canvas1.DrawBitmap(zoomedBmp, Canvas1.TargetRect)
Canvas1.Invalidate

..............
..............

Sub ZoomBitmap(bmp As B4XBitmap, targetWidth As Int, targetHeight As Int) As B4XBitmap
    Dim bc As BitmapCreator
    bc.Initialize(targetWidth, targetHeight)
    Dim rect As B4XRect
    rect.Initialize(0, 0, targetWidth, targetHeight)
    bc.DrawBitmap(bmp, rect, True)
    Return bc.Bitmap
End Sub

Public Sub BytesToImage(bytes() As Byte) As B4XBitmap
    Dim In As InputStream
    In.InitializeFromBytesArray(bytes, 0, bytes.Length)
#if B4A or B4i
   Dim bmp As Bitmap
   bmp.Initialize2(In)
#else
    Dim bmp As Image
    bmp.Initialize2(In)
#end if
    Return bmp
End Sub
This with B4XPages_Resize scale the bitmap while resize the form, but loss aspect ratio.
The problem now is to rescale the form mantaining aspect ratio for the video. I'm here from 6 hours to do this without success, when I resize the form I search to mantain aspect ratio, but resizing the sub B4XPages_Resize is called recursively. I know that may I have to open another post, but it is the same problem, all works now except the form resize to mantain the aspect ratio. Here my fail code:
B4X:
Dim xForm As Form

Private Sub B4XPage_Created (Root1 As B4XView)
    xForm = B4XPages.GetNativeParent(Me)
    ............
     ...........
End Sub

Sub B4XPage_Resize (Width As Int, Height As Int)
    Dim contentWidth As Int = Width
    Dim contentHeight As Int = Height - lblTime.PrefHeight - Slider1.PrefHeight
    Dim AspectRatio As Float = Video.Width / Video.Height

'    If LastWidth = -1 Then LastWidth = contentWidth
'    If LastHeight = -1 Then LastHeight = contentHeight

    ' Se siamo in fase di resize, ignoriamo questo giro
    If IsResizingWidth Then
        IsResizingWidth = False
        LastWidth = contentWidth
        LastHeight = Round(contentWidth / AspectRatio)
        Return
    End If

    If IsResizingHeight Then
        IsResizingHeight = False
        LastHeight = contentHeight
        LastWidth = Round(contentHeight * AspectRatio)
        Return
    End If

    ' Decidi quale lato è stato modificato
    If contentWidth <> LastWidth Then
        IsResizingWidth = True
        Dim newHeight As Int = Round(contentWidth / AspectRatio)
        Log("Resizing Width to " & contentWidth)
        ResizeTo(contentWidth, newHeight)
        Return
    Else If contentHeight <> LastHeight Then
        IsResizingHeight = True
        Dim newWidth As Int = Round(contentHeight * AspectRatio)
        Log("Resizing Height to " & contentHeight)
        ResizeTo(newWidth, contentHeight)
        Return
    End If

    Clear(xui.Color_Black)
    Canvas1.Invalidate
End Sub

Public Sub ResizeTo(NewWidth As Int, NewHeight As Int)
    xForm.WindowWidth = NewWidth + 16
    xForm.WindowHeight = NewHeight + 39 + lblTime.PrefHeight + Slider1.PrefHeight
 
    Panel1.SetLayoutAnimated(0, 0, 0, NewWidth, NewHeight)
    Canvas1.Resize(NewWidth, NewHeight)
    Log($"ResizeTo: ${NewWidth}x${NewHeight}"$)
End Sub
 
Last edited:
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
You must redraw the canvas to the new dimensions to simulate zooming to the new dimensions, not simply resize the canvas.
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
What you mean ? I have it working but very very bad, when I resize there are artifacts, i see random values returned to B4XPages_Resize, I don't know what happen.
Even with debug it returns random values.
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
What I'm trying to tell you is that when you change dimensions and want to keep the aspect ratio you have to redraw.
B4X:
    DrawingPanel.SetLayoutAnimated(0, 0, 0, Width, Height)
    DrawingCanvas.Resize(Width, Height)
    Drawing
End Sub

?
I imagine it is simulating the video by showing the frames and synchronizing
 
Last edited:
Upvote 0
Top