Android Question Save image file from byte of array using Base64Con error

Ganiadi

Active Member
Licensed User
Longtime User
hi, i tried to get image from other PC using VB under socket and i could display the image again using the byte of array read from the image file in my PC, when VB sent to b4a AStream received the string completely and equal to the original one,
Issues :
1. When i tried to save using below methods
Where cPackage is the image string that has been decoded back using Decode64

Dim out As OutputStream
aBuff = conv.StringToBytes(cPackage, "UTF8")
out = File.OpenOutput(File.DirRootExternal, "test.jpg", False)
out.WriteBytes(aBuff, 0, aBuff.Length)
out.close

it saved the image, but the image is massy not like the original one.

2. When i tried to save using Base64Con using below method
https://www.b4x.com/android/forum/posts/636126/

Base64Con.DecodeToImage(cPackage) it raised error :

An error has occured in sub:main $ResumableSub_AStreams_NewDataResume(java line:722)
java.lang.NullPointerException:Attempt to invoke virtual method 'byte[] anywheresoftware.b4a.objects.StringUtils.DecodeBase64(java.lang.String)' on a null reference
Continue ?

Any advice, tks
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
1. Why use VB? It will be very simple to do it with B4J. Example: [B4X] Network + AsyncStreams + B4XSerializator

2. Please use [code]code here...[/code] tags when posting code.

3. You shouldn't use File.DirRootExternal unless you properly handle the external storage permission.

4. The only library needed for base 64 encoding is StringUtils.

5. Why send the data encoded as base 64 string? Will be more efficient to send the raw bytes.

6. Don't assume that the data will arrive in a single "packet". It won't (unless you are using prefix mode which you can't with VB).

7. Code to convert an array of bytes to an image: https://www.b4x.com/android/forum/threads/b4x-bytes-to-file.70111/#post-445167
 
Upvote 0

Ganiadi

Active Member
Licensed User
Longtime User
Hi Erel,

Tks for the reply
1. Why use VB? It will be very simple to do it with B4J. Example: [B4X] Network + AsyncStreams + B4XSerializator
I want to interface to current existing application is preset using VB6 aps. and the doc just mention the protocol how to get the information and image via socket, so i simulate it using VB6
2. Please use
B4X:
code here...
tags when posting code.
OK tks
3. You shouldn't use File.DirRootExternal unless you properly handle the external storage permission.
OK i will do
4. The only library needed for base 64 encoding is StringUtils.
currently i use the library.
5. Why send the data encoded as base 64 string? Will be more efficient to send the raw bytes.
If i dont encoded to base 64 string the raw data bytes received wrongly (unknown image-since i tried it before decided to encode to base 64) and when i checked the content of the byte it surprised me since display - (minus) value for ascii greater than 127
6. Don't assume that the data will arrive in a single "packet". It won't (unless you are using prefix mode which you can't with VB).
Understood, so i create a protocol method to indicate which one is data and length, prefix and terminator
and i've checked also that the string received actually the same / equal to the original that sent from VB6
I tried it also, but the result is a massy image ( the same with method 1 ) not like the original one.

pls advice what is wrong.

tks
 
Upvote 0

Ganiadi

Active Member
Licensed User
Longtime User
Do you mean the split the problem in VB ?

This is the steps what i did :
VB6 Side :
1. Read the files from an image file into a array of byte
2. Convert it to String and encode to base64
3. To make sure that this string is correct, i send to a function to decode again and displayed to image object and displayed correctly
4. So im sure that the image string ( encoded base64 ) should be fine
5. I send through the socket to B4A via Astream

B4A side :
1. I received the string via AStream_New
2. i checked the string value and identical with the original one
3. Save to file and checked the file was massy image using the methods above ( it seems shifted )


Tks
 
Upvote 0

Ganiadi

Active Member
Licensed User
Longtime User
Hi Erel,

Here is the code that may give the idea :

From VB Side :
B4X:
Private Sub SendImage(ByVal file_name As String)
   Dim file_length As Long
   Dim fnum As Integer
   Dim Bytes() As Byte
   
   Dim txt As String
   Dim i As Long

    
   file_length = FileLen(file_name)

   fnum = FreeFile
   ReDim Bytes(0 To file_length)

   Open file_name For Binary As #fnum
   Get #fnum, 1, Bytes
   Close fnum
   txt = StrConv(Bytes, vbUnicode)
   'This to make check and make sure that the Bytes and string of image is OK    
   Set Picture1 = Bytes2StdPicture(Bytes)
   '================
   RemoteCnct(Index).SendData Base64EncodeString(txt)  
   RemoteCnct(Index).SendData "PXENDOFIMAGE|"
End Sub

From b4a side :

B4X:
#Region Project Attributes 
[INDENT]#ApplicationLabel: POSSYNCH
#VersionCode: 1
#VersionName: 
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: portrait
#CanInstallToExternalStorage: False[/INDENT]
#End Region

#Region Activity Attributes 
[INDENT]#FullScreen: True
#IncludeTitle: True[/INDENT]
#End Region

Sub Process_Globals
[INDENT]'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.


Dim Socket1 As Socket
Dim AStreams As AsyncStreams[/INDENT]

End Sub

Sub Globals
[INDENT]'These global variables will be redeclared each time the activity is created.
'These variables can only be accessed from this module.'
Dim conv As ByteConverter
Dim Bmp As Bitmap

Private ImageView1 As ImageView

Dim Base64Con As Base64Convert
Dim cIP As String

Dim cCommand As String
Dim cPackage As String[/INDENT]

End Sub

Sub Activity_Create(FirstTime As Boolean)

[INDENT]If FirstTime Then 
[INDENT]Activity.Title="Utility" 
cIP="192.168.10.32"

Socket1.Initialize("Socket1")
Socket1.Connect(cIP, 2519, 10000)

Activity.LoadLayout("Main")[/INDENT]
End If [/INDENT]
End Sub


Sub Activity_KeyPress (KeyCode As Int) As Boolean
' 
End Sub


Sub Activity_Resume
[INDENT]Return True[/INDENT]
End Sub


Sub Activity_Pause (UserClosed As Boolean)
[INDENT]Return True[/INDENT]
End Sub

'----------------------------------SOCKET HANDLING--------------------------------------
Sub Socket1_Connected (Successful As Boolean)
[INDENT]If Successful Then
[INDENT]ToastMessageShow("Connected!", False)
AStreams.Initialize(Socket1.InputStream, Socket1.OutputStream, "AStreams")
'If lLogin Then
' OpenTable(cSQLQuery) 
'End If[/INDENT]
Else
[INDENT]ToastMessageShow("Error while connecting To POS Server !", False)
ErrorConnectionDialog[/INDENT]
End If[/INDENT]
End Sub


Sub AStreams_NewData (Buffer() As Byte)

Dim msg As String
Dim su As StringUtils
Dim aData() As Byte

[INDENT]msg = BytesToString(Buffer, 0, Buffer.Length, "UTF8")

If cCommand="F1" Then
[INDENT]If msg.Contains("PXENDOFIMAGE|") = True Then
[INDENT]'METHOD 1
' USING THIS METHOD IT SAVED THE IMAGE, BUT THE IMAGE DISPLAYED WRONGLY
Dim out As OutputStream
aData = su.DecodeBase64(cPackage)
out = File.OpenOutput(File.DirRootExternal, "newimage.jpg", False)
out.WriteBytes(aData, 0, aData.Length)
out.Close
'===============================================================================
' METHOD 2
' USING THIS METHOD RAISE ERROR
' aData=conv.StringToBytes(cPackage, "UTF8")
' Base64Con.DecodeToImage(cPackage)
'================================================================================
'METHOD 3
' USING THIS METHOD IT SAVED THE IMAGE, BUT THE IMAGE DISPLAYED WRONGLY - SAME RESULT TO METHOD 1
'ImageView1.Bitmap = BytesToImage(aData)

cPackage = ""[/INDENT]
Else
[INDENT]cPackage= cPackage & msg[/INDENT]

End If[/INDENT][/INDENT]


[INDENT]End If[/INDENT]
End Sub

Public Sub BytesToImage(bytes() As Byte) As Bitmap
Dim In As InputStream
[INDENT]In.InitializeFromBytesArray(bytes, 0, bytes.Length)
Dim Bmp As Bitmap
Bmp.Initialize2(In)
Return Bmp[/INDENT]
End Sub

Sub SendData2Socket(cData As String)
Dim Buffer() As Byte
Dim data As String
Dim conv As ByteConverter
Dim su As StringUtils

[INDENT]Try
[INDENT]If AStreams.IsInitialized = False Then
[INDENT]ToastMessageShow("Initializing...",False)
ErrorConnectionDialog[/INDENT]
Else[/INDENT]

[INDENT][INDENT]Buffer=conv.StringToBytes(cData,"UTF8") 
data=su.EncodeBase64( Buffer)
Buffer=data.getbytes("UTF8")
AStreams.Write(Buffer)[/INDENT]
End If[/INDENT]
Catch
[INDENT]ToastMessageShow(LastException.Message, True)[/INDENT]
End Try [/INDENT]
End Sub

Sub AStreams_Error()
'ErrorConnectionDialog

End Sub

Sub AStreams_Terminated()
'ErrorConnectionDialog
End Sub
'-----------------------------------------------------------END OF SOCKET------------------------------------
Sub ErrorConnectionDialog
Dim cStr As String
Dim Id As InputDialog

[INDENT]Id.InputType = Id.INPUT_TYPE_TEXT 
Id.Input = cIP
Id.Hint = ""
Id.HintColor = Colors.ARGB(196, 255, 140, 0)
Bmp.Initialize(File.DirAssets, "stop.png")[/INDENT]

[INDENT]Try
[INDENT]cStr= DialogResponse.CANCEL
cStr= Id.Show( "Connection Error Found On IP " & cIP, "", "Retry", "Cancel", "", Bmp)
If cStr="-1" Then
[INDENT]cIP=Id.Input
Socket1.Close 
Socket1.Initialize("Socket1")
Socket1.Connect(cIP, 2519, 10000)[/INDENT]
End If[/INDENT]
Catch
[INDENT]ToastMessageShow(LastException.Message, True)[/INDENT]
End Try[/INDENT]

End Sub


Sub Button1_Click
[INDENT]cCommand="F1"
cPackage=""
' REQUEST TO DOWNLOAD IMAGE ID0001
SendData2Socket ( "F1|ID0001|" )[/INDENT]

End Sub


Tks
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Base64 encoding encodes binary data to text. Your VB code seems to encode a text string into Base64, that makes no sense.
B4X:
   txt = StrConv(Bytes, vbUnicode)
This is the code that makes no sense. Why are you converting the Bytes to a unicode string? You should be converting the Bytes immediately to a Base64 string. Also,
B4X:
   'This to make check and make sure that the Bytes and string of image is OK   
   Set Picture1 = Bytes2StdPicture(Bytes)
makes no sense to me. All you are checking is that Bytes is a picture, but that is a given. Nowhere does this check that the string of the image is ok, that the variable txt actually contains what you think it contains.

Currently, when you B4A app receives the string, it is not a Base64 encoded image. It's a Base64 encoded Unicode String. In VB, instead of
B4X:
   txt = StrConv(Bytes, vbUnicode)
You need to use whatever VB function/method that exists to convert Bytes to a Base64 encoded string
B4X:
   txt = VBFunctionThatConvertsAByteArrayToABase64String(Bytes)
and then instead of
B4X:
   RemoteCnct(Index).SendData Base64EncodeString(txt)
you just need to do a
B4X:
   RemoteCnct(Index).SendData txt

BTW, you probably should just sent the raw bytes over as @Erel suggested.
If i dont encoded to base 64 string the raw data bytes received wrongly (unknown image-since i tried it before decided to encode to base 64) and when i checked the content of the byte it surprised me since display - (minus) value for ascii greater than 127
In Java, and therefore B4A, Bytes are signed. That does not affect the integrity of the transferred data. If you transfer the bytes of an image, the received data is the same bytes of an image (discounting network/transfer issues).
 
Upvote 0

Ganiadi

Active Member
Licensed User
Longtime User
Wonderful Oliver.
Tks and much appreciated for your info, and it's working now

after deleted below
B4X:
   txt = StrConv(Bytes, vbUnicode)
and changed into
B4X:
   txt = encodeBase64(Bytes)

:):):)
 
Upvote 0

Ganiadi

Active Member
Licensed User
Longtime User
You need to find out where is the problem. First step is to manually copy a text file with the base 64 string and convert it to a bitmap. Once you get it working you move to the next step which is to send the data over the network.
Tks Erel,

it SOLVED now
 
Upvote 0
Top