Android Code Snippet [B4X][XUI] Image to JPEG byte array with resize/quality options

OliverA

Expert
Licensed User
Originally posted a B4J/inline Java version of this in the B4J Code Snippets (https://www.b4x.com/android/forum/t...byte-array-with-resize-quality-options.91746/). @Erel pointed out though that the XUI library had the functionality that I was doing with Java, so I decided to rewrite the routine. This routine uses 100% B4X basic syntax, no inline Java, not even any #If conditionals. Unlike the Java version, this version does not throw any exceptions (on purpose), but instead returns an empty byte array if it finds/encounters any issues (which are Log()'ed).

B4X:
' Converts image to JPEG byte array. Ability to resize and adjust JPEG quality.
' Negative width and height values = %, such that -50 = 50% and -200 = 200%
' Positive width and height values = pixel dimensions
' If one value (either width or height) are 0, then the other value is proportionally
'  calculated from the first.
' If both width and height are 0 or -100, no resizing takes place
' If quality = -1, use default quality of 75
' Will return a zero length byte array if something is wrong with the parameters
Sub XUIImageToJPEGByteArray(aImage As Object, width As Int, height As Int, quality As Int) As Byte()
   'Sanity check quality
   If (quality < -1 And quality > 100) Then
       Log("Parameter quality not in range (-1..100)")
       Return Array As Byte ()
   End If
   If quality = -1 Then quality = 75

   'Sanity check incoming image
   Try
       Dim image As B4XBitmap = aImage
   Catch
       Log(LastException)
       Return Array As Byte ()
   End Try
  
   'Sanity check incoming image dimensions
   Dim oldWidth As Int = image.Width
   Dim oldHeight As Int = image.Height
   If (oldWidth = 0 And oldHeight = 0 ) Then
       Log("Source image with incorrect dimensions")
       Return Array As Byte ()
   End If

   'See if were resizing the image
   Dim  resize As Boolean = True
   If ((width = 0 And height = 0) Or (width = -100 Or height = -100)) Then resize = False
  
   'Resize if necessary
   If (resize) Then
       Dim newWidth As Int = width
       Dim newHeight As Int = height
       'Calculate new dimensions
       If (newWidth < 0) Then newWidth = -1 * oldWidth * newWidth / 100
       If (newHeight < 0) Then newHeight = -1 * oldHeight * newHeight / 100
       If (newWidth = 0) Then newWidth = oldWidth * newHeight / oldHeight
       If (newHeight = 0 ) Then newHeight = oldHeight * newWidth / oldWidth
       image = image.Resize(newWidth, newHeight, False)
   End If
  
   'Convert image to JPEG byte array
   Dim out As OutputStream
   out.InitializeToBytesArray(0)
   image.WriteToStream(out, quality, "JPEG")
   out.Close
  
   'Done
   Return out.ToBytesArray
End Sub
Example
B4X:
Dim bImage As Image
bImage.Initialize(File.DirAssets, "b.png")
Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content
BytesToFile(File.DirApp, "b.jpg", c)
Resource used:
Dim bImage As Image bImage.Initialize(File.DirAssets, "b.png") Dim c() As Byte = ImageToJPEGByteArray(bImage, -50, 0, 50) 'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content BytesToFile(File.DirApp, "b.jpg", c)
 
Last edited:

Alexander Stolte

Well-Known Member
Licensed User
I try it out and if i compile it with B4J then i run into an Error:

B4X:
B4J Version: 6.01
Parsing code.    (0.00s)
Compiling code.    (0.16s)
   
ObfuscatorMap.txt file created in Objects folder.
Compiling layouts code.    (0.00s)
Organizing libraries.    (0.00s)
Compiling generated Java code.    Error
B4J line: 51
Dim image As B4XBitmap = aImage
javac 1.8.0_151
src\b4j\example\main.java:137: error: package android.graphics does not exist
_image.setObject((android.graphics.Bitmap)(_aimage));
                                  ^
1 error
Attached is the project, maybe i missed something.
 

Attachments

OliverA

Expert
Licensed User
_image.setObject((android.graphics.Bitmap)(_aimage));
I've just opened your project and it complained about the missing xui library. That should not happen in B4J 6.01, since it has a version of the XUI library included, it's called jXUI. Looks like your using the Android version of the XUI library instead of B4J's internal XUI library (jXUI).

BTW: Thanks for including a test project. That gave me the clue as to what is going on.
 
Last edited:

Anser

Well-Known Member
Licensed User
May I know which Library is to be used for the type Image in the code "Dim bImage As Image"

B4X:
Dim bImage As Image
bImage.Initialize(File.DirAssets, "b.png")
Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content
BytesToFile(File.DirApp, "b.jpg", c)
 

klaus

Expert
Licensed User
Replace:
B4X:
Dim bImage As Image
bImage.Initialize(File.DirAssets, "b.png")
Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content
BytesToFile(File.DirApp, "b.jpg", c)
By:
B4X:
Dim bImage As B4XBitmap
bImage = xui.LoadBitmap(File.DirAssets, "b.png")
Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
'https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#content
BytesToFile(xui.DefaultFoler, "b.jpg", c)
And it becomes XUI.
 

Anser

Well-Known Member
Licensed User
B4X:
Dim bImage As B4XBitmap
bImage = xui.LoadBitmap(File.DirAssets, "b.png")
Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
BytesToFile(File.DirDefaultExternal, "b.jpg", c)
The file created using BytesToFile(File.DirDefaultExternal, "b.jpg", c) is corrupted. Any idea why is it so. ?

I pick a file from Gallery, then resize and write it to File.DirDefaultExternal, unfortunately the file written is corrupted
Here is the code that I use
B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Private cc As ContentChooser
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Profile")
    If FirstTime Then
        cc.Initialize("cc")
    End If
 
End Sub

Sub LblFromGallery_Click
    cc.Show("image/*", "Choose image")
End Sub

Sub cc_Result (Success As Boolean, Dir As String, FileName As String)
    Dim realPath As String = GetPathFromContentResult(FileName)

    Dim xIV As B4XView = ivProfilePic 'ivProfilePic is an ImageView
    Dim bImage As B4XBitmap
    Dim myXui As XUI
    bImage = myXui.LoadBitmap(Dir, FileName)
 
    Dim c() As Byte = XUIImageToJPEGByteArray(bImage, -50, 0, 50)
    'When I physicall check this file on File.DirDefaultExternal, it is corrupted
    BytesToFile(File.DirDefaultExternal, "MyProfilePic.jpg", c)
 
    xIV.SetBitmap( LoadBitmapResize(File.DirDefaultExternal, "MyProfilePic.jpg", 332dip, 232dip, True ))
 
End Sub

Sub BytesToFile (Dir As String, FileName As String, Data() As Byte)
    Dim out As OutputStream = File.OpenOutput(Dir, FileName, False)
    out.WriteBytes(Data, 0, Data.Length)
    out.Close
End Sub

Sub FileToBytes (Dir As String, FileName As String) As Byte()
    Return Bit.InputStreamToBytes(File.OpenInput(Dir, FileName))
End Sub
Later I use the FileToBytes to read the image file and then write the image to a BLOB column in MySQL
B4X:
Dim c() As Byte = FileToBytes(File.DirDefaultExternal, "MyProfilePic.jpg")
 
Last edited:

OliverA

Expert
Licensed User
If you upload your project, or at least enough of your project that replicates this issue, I’ll take a look at it
 

Alexander Stolte

Well-Known Member
Licensed User
I use this in a Non-Ui Project, on my local machine, it works good, but on my server (ubuntu) i have this error:
B4X:
java.lang.RuntimeException: java.lang.NoClassDefFoundError: javafx/scene/image/Image
I use openjdk version 1.8.9_191 on the server.

do you know something about it?
 

OliverA

Expert
Licensed User
Looks like the OpenJDK distribution you used did not include JavaFX. That seems to be a common issue. You may want to install a different alternative.
I think that developers who needs bundled JavaFX (OpenJFX) can use below distributions.
* Azul ZuluFX: https://www.azul.com/downloads/zulu/zulufx/
* BellSoft Liberica JDK: https://www.bell-sw.com/java.html
* Amazon Corretto: https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-8-ug/downloads-list.html
ZuluFX and Liberica are supported JDK 8/11, Corretto is now JDK 8 only and in preview.
Source: https://github.com/AdoptOpenJDK/openjdk-build/issues/577#issuecomment-452144377
Notes:
1) On the BellSoft site, scroll all the way down to see other versions of their Liberica JDK
2) Amazon Corretto: https://aws.amazon.com/corretto/
 
Top