Android Question Activity screenshot not showing rounded panel

Marvel

Active Member
Licensed User
I have a problem with taking screenshots. I have a B4ximageview inside a rounded panel. It shows well in-app, the problem occurs when I take the screenshot of the activity, the bitmap I get does not show the image in the rounded panel, it basically just shows the square image.

I replicated it in a small project attached. The rounded panel is shown on top and the screenshot of the activity is shown below.
Screenshot_2021-03-05-16-07-00-401_com.imagetest.jpg
 

Attachments

  • ImageScreenshot.zip
    24.9 KB · Views: 153

JordiCP

Expert
Licensed User
Longtime User
There are a couple of SO post talking about this: losing corner radius when taking screenshots programmatically (this does not happen when you take a real screenshot)
https://stackoverflow.com/questions...dius-when-taken-a-screenshot-programmatically
https://stackoverflow.com/questions...nded-corners-are-not-showing-up-in-screenshot

Didn't go deep into the posts even though they seem to point ways to solve it, but the straightforward solution in this case is to make the bitmap really round using THIS , and changing a couple of lines in your code
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")

    ' B4XImageView1.Bitmap = LoadBitmap(File.DirAssets, "random-dice.jpg")      '<-- Remove this line...
    
    B4XImageView1.Bitmap = CreateRoundBitmap(xui.LoadBitmap(File.DirAssets, "random-dice.jpg"), B4XImageView1.mBase.Width)    '<-- ...and add this

End Sub
and remove the Views corners in the designer

This would only work for this specific case.
 
Upvote 0

Marvel

Active Member
Licensed User
There are a couple of SO post talking about this: losing corner radius when taking screenshots programmatically (this does not happen when you take a real screenshot)
https://stackoverflow.com/questions...dius-when-taken-a-screenshot-programmatically
https://stackoverflow.com/questions...nded-corners-are-not-showing-up-in-screenshot

Didn't go deep into the posts even though they seem to point ways to solve it, but the straightforward solution in this case is to make the bitmap really round using THIS , and changing a couple of lines in your code
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")

    ' B4XImageView1.Bitmap = LoadBitmap(File.DirAssets, "random-dice.jpg")      '<-- Remove this line...
   
    B4XImageView1.Bitmap = CreateRoundBitmap(xui.LoadBitmap(File.DirAssets, "random-dice.jpg"), B4XImageView1.mBase.Width)    '<-- ...and add this

End Sub
and remove the Views corners in the designer

This would only work for this specific case.

Thanks @JordiCP Using actual round bitmaps solves the issue
 
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
B4X:
    B4XImageView1.ResizeMode = "NONE" 'Size Original
    B4XImageView1.RoundedImage = True
    B4XImageView1.Load(File.DirAssets, "random-dice.jpg")

Code for B4A in B4XImageView
Dim jo As JavaObject = mBase
jo.RunMethod("setClipToOutline", Array(mRound Or mCornersRadius > 0))
 
Last edited:
Upvote 0

TILogistic

Expert
Licensed User
Longtime User
Solution @JordiCP very good:

B4X:
    Panel1.SetBitmap(CreateRoundBitmap(xui.LoadBitmap(File.DirAssets, "random-dice.jpg"), Panel1.Height))
    
    B4XImageView2.ResizeMode = "FIT"
    B4XImageView2.RoundedImage = True
    B4XImageView2.Load(File.DirAssets, "random-dice.jpg")
    
    
Sub TakeScreenshot As Bitmap
    Dim jo As JavaObject
    jo.InitializeContext
    Dim decor As JavaObject = jo.RunMethodJO("getWindow", Null).RunMethod("getDecorView", Null)
    Dim decorChild As JavaObject = decor.RunMethod("getChildAt", Array(0))
    decorChild.RunMethod("setDrawingCacheEnabled", Array(True))
    decorChild.RunMethod("buildDrawingCache", Null)
    Dim bmp As Bitmap = decorChild.RunMethod("getDrawingCache", Array(True))
    bmp.Initialize3(bmp)
    decorChild.RunMethod("setDrawingCacheEnabled", Array(False))
    Return bmp
End Sub


'xui is a global XUI variable.
Sub CreateRoundBitmap (Input As B4XBitmap, Size As Int) As B4XBitmap
    If Input.Width <> Input.Height Then
        'if the image is not square then we crop it to be a square.
        Dim l As Int = Min(Input.Width, Input.Height)
        Input = Input.Crop(Input.Width / 2 - l / 2, Input.Height / 2 - l / 2, l, l)
    End If
    Dim c As B4XCanvas
    Dim xview As B4XView = xui.CreatePanel("")
    xview.SetLayoutAnimated(0, 0, 0, Size, Size)
    c.Initialize(xview)
    Dim path As B4XPath
    path.InitializeOval(c.TargetRect)
    c.ClipPath(path)
    c.DrawBitmap(Input.Resize(Size, Size, False), c.TargetRect)
    c.RemoveClip
    c.DrawCircle(c.TargetRect.CenterX, c.TargetRect.CenterY, c.TargetRect.Width / 2 - 2dip, xui.Color_Transparent, False, 0dip) 'comment this line to remove the border
    c.Invalidate
    Dim res As B4XBitmap = c.CreateBitmap
    c.Release
    Return res
End Sub

image 1 Panel
image 2 B4XImageView

1614977717230.png
 
Upvote 0

Biswajit

Active Member
Licensed User
Longtime User
If your app has min SDK target set to 24 (Android N) you can use the new PixelCopy API to capture screenshot,
Example:
Private Sub Button1_Click
    Dim r As RuntimePermissions
    Dim Out As OutputStream
    Out = File.OpenOutput(r.GetSafeDirDefaultExternal("/"), "Test2.png", False)
    wait for (TakeScreenshot(Root)) Complete(result As Bitmap)
    result.WriteToStream(Out, 100, "PNG")
    Out.Close
    Panel2.SetBitmap(LoadBitmap(r.GetSafeDirDefaultExternal("/"), "Test2.png").Resize(Panel2.Width, Panel2.Height, True))
End Sub

Sub TakeScreenshot(v As View) As ResumableSub
    Dim jv As JavaObject = v
    Dim loc(2) As Int:jv.RunMethod("getLocationInWindow",Array(loc))
    Dim rect As Rect:rect.Initialize(loc(0),loc(1),loc(0)+v.Width,loc(1)+v.Height)
    Dim b As Bitmap:b.InitializeMutable(v.Width,v.Height)
   
    Dim jo As JavaObject:jo.InitializeContext
    Dim PixelCopy As JavaObject
    PixelCopy=PixelCopy.InitializeStatic("android.view.PixelCopy")
    Dim listener As Object = PixelCopy.CreateEvent("android.view.PixelCopy.OnPixelCopyFinishedListener","OnPixelCopyFinished",Null)
    PixelCopy.RunMethod("request",Array(jo.RunMethod("getWindow", Null),rect,b,listener,jo.InitializeNewInstance("android.os.Handler",Null)))
   
    Wait For OnPixelCopyFinished_Event (MethodName As String, Args() As Object)
    Return b
End Sub

Result:
test.png
 
Upvote 0

Marvel

Active Member
Licensed User
Solution @JordiCP very good:

B4X:
    Panel1.SetBitmap(CreateRoundBitmap(xui.LoadBitmap(File.DirAssets, "random-dice.jpg"), Panel1.Height))
   
    B4XImageView2.ResizeMode = "FIT"
    B4XImageView2.RoundedImage = True
    B4XImageView2.Load(File.DirAssets, "random-dice.jpg")
   
   
Sub TakeScreenshot As Bitmap
    Dim jo As JavaObject
    jo.InitializeContext
    Dim decor As JavaObject = jo.RunMethodJO("getWindow", Null).RunMethod("getDecorView", Null)
    Dim decorChild As JavaObject = decor.RunMethod("getChildAt", Array(0))
    decorChild.RunMethod("setDrawingCacheEnabled", Array(True))
    decorChild.RunMethod("buildDrawingCache", Null)
    Dim bmp As Bitmap = decorChild.RunMethod("getDrawingCache", Array(True))
    bmp.Initialize3(bmp)
    decorChild.RunMethod("setDrawingCacheEnabled", Array(False))
    Return bmp
End Sub


'xui is a global XUI variable.
Sub CreateRoundBitmap (Input As B4XBitmap, Size As Int) As B4XBitmap
    If Input.Width <> Input.Height Then
        'if the image is not square then we crop it to be a square.
        Dim l As Int = Min(Input.Width, Input.Height)
        Input = Input.Crop(Input.Width / 2 - l / 2, Input.Height / 2 - l / 2, l, l)
    End If
    Dim c As B4XCanvas
    Dim xview As B4XView = xui.CreatePanel("")
    xview.SetLayoutAnimated(0, 0, 0, Size, Size)
    c.Initialize(xview)
    Dim path As B4XPath
    path.InitializeOval(c.TargetRect)
    c.ClipPath(path)
    c.DrawBitmap(Input.Resize(Size, Size, False), c.TargetRect)
    c.RemoveClip
    c.DrawCircle(c.TargetRect.CenterX, c.TargetRect.CenterY, c.TargetRect.Width / 2 - 2dip, xui.Color_Transparent, False, 0dip) 'comment this line to remove the border
    c.Invalidate
    Dim res As B4XBitmap = c.CreateBitmap
    c.Release
    Return res
End Sub

image 1 Panel
image 2 B4XImageView

View attachment 109158
It works great, I ended up using this
 
Upvote 0

Marvel

Active Member
Licensed User
If your app has min SDK target set to 24 (Android N) you can use the new PixelCopy API to capture screenshot,
Example:
Private Sub Button1_Click
    Dim r As RuntimePermissions
    Dim Out As OutputStream
    Out = File.OpenOutput(r.GetSafeDirDefaultExternal("/"), "Test2.png", False)
    wait for (TakeScreenshot(Root)) Complete(result As Bitmap)
    result.WriteToStream(Out, 100, "PNG")
    Out.Close
    Panel2.SetBitmap(LoadBitmap(r.GetSafeDirDefaultExternal("/"), "Test2.png").Resize(Panel2.Width, Panel2.Height, True))
End Sub

Sub TakeScreenshot(v As View) As ResumableSub
    Dim jv As JavaObject = v
    Dim loc(2) As Int:jv.RunMethod("getLocationInWindow",Array(loc))
    Dim rect As Rect:rect.Initialize(loc(0),loc(1),loc(0)+v.Width,loc(1)+v.Height)
    Dim b As Bitmap:b.InitializeMutable(v.Width,v.Height)
  
    Dim jo As JavaObject:jo.InitializeContext
    Dim PixelCopy As JavaObject
    PixelCopy=PixelCopy.InitializeStatic("android.view.PixelCopy")
    Dim listener As Object = PixelCopy.CreateEvent("android.view.PixelCopy.OnPixelCopyFinishedListener","OnPixelCopyFinished",Null)
    PixelCopy.RunMethod("request",Array(jo.RunMethod("getWindow", Null),rect,b,listener,jo.InitializeNewInstance("android.os.Handler",Null)))
  
    Wait For OnPixelCopyFinished_Event (MethodName As String, Args() As Object)
    Return b
End Sub

Result:
View attachment 109159
Thanks, I'll try this method
 
Upvote 0
Top