Android Question Upload file, e.g. jpg using okHttUtils2

Hanz

Active Member
A service or a server, not B4J server, is accepting the ff. HTTP PUT command.

B4X:
curl -vX PUT http://admin:[email protected]:5984/albums/6e1295ed6c29495e54cc05947f18c8af/artwork.jpg?rev=2-2739352689 --data-binary @artwork.jpg -H "Content-Type:image/jpg"

I tried the sample provided by the link below to implement it in B4A, but I can't get it run.
[Server] Upload files from your B4A app to your B4J server over the internet | B4X Programming Forum

It seems the problem is to get the path to the file. Can someone provide me a sample code how the above should be implemented in B4A? In the example provided by the above link, the command used to upload a file is j.PutBytes but I think based on the other examples I searched here, the PUT is equivalent to j.PutString in B4X and what is being upload here is a binary.

I am getting the image from the android using the ContentChooser and I think this where the problem occurs and how to transfer it using the PUT command.

Thanks!!!
 

Hanz

Active Member
In case you need the source, I post it here. The task that I want to accomplish is to upload an attachment file with couchdb, I know it's not a popular database here but the idea is just to implement the curl command provided above into b4a.

Here is the explanation of the curl command above.
Attachments get their own URL where you can upload data. Say we want to add the album artwork to the6e1295ed6c29495e54cc05947f18c8afdocument (“There is Nothing Left to Lose”), and let’s also say the artwork is in a file artwork.jpg in the current directory

The --data-binary @option tells curl to read a file’s contents into the HTTP request body. We’re using the -H option to tell CouchDB that we’re uploading a JPEG file

Below is my implementation including some related codes.
B4X:
Private Sub btnUpdateProfilePhoto_Click
    'get file location
    cc.Initialize("CC")  'Declared in the Class_Globals as Private cc As ContentChooser
    cc.Show("*/*", "Choose File")
End Sub

'This is to get the file name e.g. IMG101010.JPEG
Sub getFileInfo(uri As String)
    Dim Cur As Cursor
    Dim Uri1 As Uri
    Dim cr As ContentResolver
    cr.Initialize("")
   
    Uri1.Parse(uri)
    Cur = cr.Query(Uri1, Null, Null, Null, Null)
    Cur.Position = 0
   
    Try
        AttachFileName = Cur.GetString("_display_name") 'This "AttacheFileName" is the one used for the file in the j.PutBytes().  This is visible in the whole module
    Catch
        ToastMessageShow("Error Getting File Name", True)
    End Try
End Sub

'This is the actual sending of file to the server and where the problem arises.
Sub CC_Result (Success As Boolean, Dir As String, FileName As String)
    If Success Then
        Dim j As HttpJob
        Dim out As OutputStream
        out.InitializeToBytesArray(0)
        Dim In As InputStream = File.OpenInput(Dir, FileName)
        File.Copy2(In, out)

        getFileInfo(FileName)
       
        Dim su As StringUtils
        Dim j As HttpJob
        j.Initialize("j", Me)
       
        j.Password = "password"
        j.Username = "admin"
       
       'This is the link which is declared at the Class_Global
       'Private link As String = $"http://192.168.1.11:5984/messages/1a41295ed6c29495e54cc05947f18c8af"$

        j.PutBytes(link & "/" & AttachFileName & "?rev=9-230b22af2a8fb9a9288c5947bfa8a00f", _
            out.ToBytesArray)

        Wait For (j) JobDone(j As HttpJob)
       
        If j.Success Then
            Label2.Text = j.GetString
            j.Release
        Else
            Label3.Text = j.ErrorMessage
            j.Release
        End If
       
    End If
End Sub

Now, the upload is not working. The j.ErrorMessage says, "java.net.SocketException: Connection reset." I'm wondering what causes it. I tried it with the curl and it works. I tried also the j.PutString(link, "") and it works but although the attachment appears, the file has 0 bytes and can't be opened. I know I am getting the file because the out has a length which is equal to the size of the file in the image gallery. Any idea how to go over it, even not code is appreciated. Thanks!
 
Upvote 0

Hanz

Active Member
What is the value of link?
Hi Erel, I'm sorry, I don't understand your question. But I hope this is what you are asking about. They are the IpAddressNport/databasename/documentId/filename(jpeg)/?revision
B4X:
Private link As String = $"http://192.168.1.11:5984/messages/1a41295ed6c29495e54cc05947f18c8af/"$
Dim ActualLink As String = $"${link}${AttachFileName}?rev=12-b3a89d25deacd3eb462b2870a2a2917f"$
j.PutBytes(ActualLink, out.ToBytesArray)
j.GetRequest.SetContentType("image/jpg")

The "AttacheFileName" is a jpeg file which I got from ContentChooser. I tried j.PostBytes also and d result is the same. Then, I tried to played around by doing like this:
B4X:
j.PutString(ActualLink, "hello world")

And I get like this...
Screenshot_2.png

The "length" has 11 which is the number of letters of the hello world. But of course it will not open because it's just a text and not the supposed content which is bytes of jpeg file. If I do not put a value just like as follows:

B4X:
j.PutString(ActualLink, "")
It will be posted just like the above image but the "length" is zero just like below:
Screenshot_1.png
 
Upvote 0

Hanz

Active Member
I think the j.PutString() has limits on the size of file for upload. I tried to convert the binary into base64 and tried to send about 200 bytes of it and it worked. But of course, the file will not open accordingly if opened in the browser because it is incomplete. I have seen questions with the same issue. The code went like this:
B4X:
Dim sUtil As StringUtils
Dim s As String = sUtil.EncodeBase64(out.ToBytesArray)
j.PutString(ActualLink, s.SubString2(0, 200))
j.GetRequest.SetContentType("image/jpg")

But if I load the whole string it will generate the above error: Connection reset.
B4X:
Dim sUtil As StringUtils
Dim s As String = sUtil.EncodeBase64(out.ToBytesArray)
j.PutString(ActualLink, s)
j.GetRequest.SetContentType("image/jpg")
 
Upvote 0

Hanz

Active Member
I don't know what is going on, but I tried it again but this time instead of converting the out.ToBytesArray into EncodeBase64 and send it to the server using the j.PutString I used j.PutByte() without converting the out.ToBytesArray into the EncodeBase64 and it worked. But not to all the images. It seems it's in the image's size. What is going on here?
 
Upvote 0

Alex_197

Well-Known Member
Licensed User
Longtime User
I don't know what is going on, but I tried it again but this time instead of converting the out.ToBytesArray into EncodeBase64 and send it to the server using the j.PutString I used j.PutByte() without converting the out.ToBytesArray into the EncodeBase64 and it worked. But not to all the images. It seems it's in the image's size. What is going on here?
Try this approach

B4X:
public Sub UploadMedia
    
    Try
        
        
        Dim MySQL As String
        Dim Cursor1 As ResultSet   
        Dim IsFTPOk As Boolean
        
        MySQL="select ID, FileName from tblNotesMediaFiles "
        MySQL= MySQL & "where PlacementLocalID=? And PlacementID=? And JobDate=? And Shift=? And ifnull(FTPDate,'1/1/1900')='1/1/1900'"
            
        FileName=""
        
        
        Dim files As List,Records As List
        Dim job As HttpJob
        
        files.Initialize
        Records.Initialize
        
        Cursor1=Main.SQL1.ExecQuery2(MySQL,Array As String(Main.SelectedPlacementLocalID, Main.SelectedPlacementID, Main.SelectedDOS,Main.SelectedShift))
                
        Do While Cursor1.NextRow
            
            
            
            FileName=Cursor1.GetString("FileName")
                        
            If FileName<>"" Then
        
                If File.Exists(Main.FileDir,FileName) Then
            
                    RecordID=Cursor1.GetInt("ID")
                    Records.Add(RecordID)
                    
                    Dim fd As MultipartFileData
                    fd.Initialize
                    
                    If FileName.Contains("jpg") Then
                        fd.KeyName = "imagejpg"
                        fd.ContentType = "image/jpg"
                        else if FileName.Contains("png") Then
                        fd.KeyName = "imagepng"
                        fd.ContentType = "image/png"
                    Else
                        fd.KeyName = "audiowav"
                        fd.ContentType = "audio/wav"
                    End If
                    
                    fd.FileName = FileName
                    fd.Dir = Main.FileDir
                    
                    files.Add(fd)
                    
                End If
            End If
            
        Loop
        
        Cursor1.Close
        
        If files.Size>0 Then
                    
            For j=0 To files.Size-1
                
                Dim CurrentFile As List,CurrentRecord As List
                CurrentFile.Initialize
                CurrentRecord.Initialize
            
                CurrentFile.Add(files.Get(j))
                CurrentRecord.Add(Records.Get(j))
                    
                Dim job As HttpJob
                job.Initialize("Upload",Me)
                
                job.PostMultipart(Main.modFun.URL ,CreateMap("action":"upload", "Ticket":Main.Ticket,"RegKey":Main.RegKey,"WhatToDo":"receivefiles","IsIOS":"Yes"),CurrentFile)
        
                Wait For (job) JobDone(job As HttpJob)
        
                If job.Success Then
            
                    Dim response As String
            
                    response=job.GetString
            
                    Log("File " & j & " was uploaded successfully " & job.GetString )
            
                    IsFTPOk=Main.modFun.ApplyUploadConfirmation(response,CurrentFile,CurrentRecord)
            
                    If IsFTPOk=False Then
                        Main.modFun.ShowError("clsRefreshJobs_File upload has failed " & response & CRLF & "Try again later with better connection")
                    End If

                Else
                    Main.modFun.ShowError("clsRefreshJobs_HTTP Upload error " & LastException.Message & CRLF & "Try again later with better connection")
                    IsFTPOk=False
                End If
        
                job.Release
            
            Next
        
        End If
        
        If IsFTPOk=False Then
            Main.TestRet=False
        End If
        
        CallSubDelayed(Me,"UploadMedia_Complete")
                
    Catch
        HUD.ProgressDialogHide
        Log("UploadMedia " &   LastException.description)
        Main.modFun.ShowError("clsRefreshJobs_UploadMedia " &   LastException.description)
    End Try
    
End Sub
 
Upvote 0

Hanz

Active Member
Try this approach

B4X:
public Sub UploadMedia
   
    Try
       
       
        Dim MySQL As String
        Dim Cursor1 As ResultSet  
        Dim IsFTPOk As Boolean
       
        MySQL="select ID, FileName from tblNotesMediaFiles "
        MySQL= MySQL & "where PlacementLocalID=? And PlacementID=? And JobDate=? And Shift=? And ifnull(FTPDate,'1/1/1900')='1/1/1900'"
           
        FileName=""
       
       
        Dim files As List,Records As List
        Dim job As HttpJob
       
        files.Initialize
        Records.Initialize
       
        Cursor1=Main.SQL1.ExecQuery2(MySQL,Array As String(Main.SelectedPlacementLocalID, Main.SelectedPlacementID, Main.SelectedDOS,Main.SelectedShift))
               
        Do While Cursor1.NextRow
           
           
           
            FileName=Cursor1.GetString("FileName")
                       
            If FileName<>"" Then
       
                If File.Exists(Main.FileDir,FileName) Then
           
                    RecordID=Cursor1.GetInt("ID")
                    Records.Add(RecordID)
                   
                    Dim fd As MultipartFileData
                    fd.Initialize
                   
                    If FileName.Contains("jpg") Then
                        fd.KeyName = "imagejpg"
                        fd.ContentType = "image/jpg"
                        else if FileName.Contains("png") Then
                        fd.KeyName = "imagepng"
                        fd.ContentType = "image/png"
                    Else
                        fd.KeyName = "audiowav"
                        fd.ContentType = "audio/wav"
                    End If
                   
                    fd.FileName = FileName
                    fd.Dir = Main.FileDir
                   
                    files.Add(fd)
                   
                End If
            End If
           
        Loop
       
        Cursor1.Close
       
        If files.Size>0 Then
                   
            For j=0 To files.Size-1
               
                Dim CurrentFile As List,CurrentRecord As List
                CurrentFile.Initialize
                CurrentRecord.Initialize
           
                CurrentFile.Add(files.Get(j))
                CurrentRecord.Add(Records.Get(j))
                   
                Dim job As HttpJob
                job.Initialize("Upload",Me)
               
                job.PostMultipart(Main.modFun.URL ,CreateMap("action":"upload", "Ticket":Main.Ticket,"RegKey":Main.RegKey,"WhatToDo":"receivefiles","IsIOS":"Yes"),CurrentFile)
       
                Wait For (job) JobDone(job As HttpJob)
       
                If job.Success Then
           
                    Dim response As String
           
                    response=job.GetString
           
                    Log("File " & j & " was uploaded successfully " & job.GetString )
           
                    IsFTPOk=Main.modFun.ApplyUploadConfirmation(response,CurrentFile,CurrentRecord)
           
                    If IsFTPOk=False Then
                        Main.modFun.ShowError("clsRefreshJobs_File upload has failed " & response & CRLF & "Try again later with better connection")
                    End If

                Else
                    Main.modFun.ShowError("clsRefreshJobs_HTTP Upload error " & LastException.Message & CRLF & "Try again later with better connection")
                    IsFTPOk=False
                End If
       
                job.Release
           
            Next
       
        End If
       
        If IsFTPOk=False Then
            Main.TestRet=False
        End If
       
        CallSubDelayed(Me,"UploadMedia_Complete")
               
    Catch
        HUD.ProgressDialogHide
        Log("UploadMedia " &   LastException.description)
        Main.modFun.ShowError("clsRefreshJobs_UploadMedia " &   LastException.description)
    End Try
   
End Sub
Thanks for your reply Alex. Even though this refers to SQL, I will look into the jHttp portion to solve this malfunction.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Where is the code on how you read the image and place it into an output stream?
 
Upvote 0
Top