Android Question Save an image from the smartphone gallery in the database and upload it to a listview.

WebQuest

Active Member
Licensed User
Hi, I'm new to the forum and I'm a beginner. I'm trying to load an image from the smartphone gallery and then save it in the database and then upload it to a listview. But I keep getting errors !. At the fristtime I open the gallery of the smartphone I select an image and I return the message (Image Added) that makes me deduce that the rescue in the db has been successful. But when I restart the app it returns me this error: java.lang.NullPointerException: Attempt to get length of null array.


B4X:
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("ImageHome")
    LoadSystem
    LoadListImage
   
End Sub

B4X:
Sub ImageViewAggImage_Click
    Dim Chooser As ContentChooser
    Chooser.Initialize("chooser")
    Chooser.Show("image/*", "Select an image")
   
End Sub
B4X:
Sub chooser_Result (Success As Boolean, Dir As String, FileName As String)
If Success Then


Dim b() As Byte = ImageToBytes(xui.LoadBitmap(Dir,FileName))

s.ExecNonQuery("INSERT INTO Image (Picture) VALUES('" & b.Length & "')")
ToastMessageShow("Image Added",True)

Else
ToastMessageShow("No image selected", True)
End If
End Sub[[/CODE]


B4X:
Sub chooser_Result (Success As Boolean, Dir As String, FileName As String)

Sub LoadSystem
  
    Dim ruta As String
    If File.ExternalWritable Then
        ruta = File.DirInternal
    Else
        ruta = File.DirInternal
    End If
    If  File.Exists(File.DirInternal,"dbi.db")= False Then
        File.Copy(File.DirAssets,"dbi.db",File.DirInternal,"dbi.db")
    End If
    s.Initialize(ruta,"dbi.db",True)
    Log("dbi Inizializzato")
    init
End Sub


[CODE]Sub ImageToBytes( image As Bitmap) As Byte()
Dim out As OutputStream

out.InitializeToBytesArray(100)
image.WriteToStream(out,100,"JPG")
    Return out.ToBytesArray
End Sub
B4X:
Sub LoadListImage
 
    Dim Cursor1 As Cursor
    Dim Name As String
    Dim Buffer() As Byte
    Dim IpSt As InputStream
    Dim Bitmap1 As Bitmap
    Cursor1 = s.ExecQuery("SELECT  name,Picture FROM Image")
 
    For i = 0 To Cursor1.RowCount - 1
        Cursor1.Position = i
        Name =Cursor1.GetString("name")
        Buffer = Cursor1.GetBlob("Picture")
        IpSt.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
        Bitmap1.Initialize2(IpSt)
        IpSt.Close
        ListViewImage.AddTwoLinesAndBitmap(Name,"",Bitmap1)
        Cursor1.Close
       
    Next
   
    SetDivider(ListViewImage, Colors.LightGray, 1dip)
 
End Sub
 

WebQuest

Active Member
Licensed User
As the buffer fills up if the Choose_Result is (Success) to the load of the activity without this (if) it gives me an error. The main thing is this (1- through a (buttonAdd) I open the galleryImage of the device 2 -select an image and save it in the database 3 - Load the image in the (Listview) If in the Sub (LoadListImage) I put everything before the next it returns me an error.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
One big mistake you were making in your earlier For/Next loops was closing the cursor inside the For/Next loop. You should have closed it after the For/Next loop. That and the incorrect storage of the image/name is what gave you the Null error statements.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
B4X:
Sub chooser_Result (Success As Boolean, Dir As String, FileName As String)
   If Success Then
      Dim selectedImage As Bitmap = xui.LoadBitmap(Dir, FileName)
      'I'm assuming were saving the image to DB in case the Activity is destroy and has to reload all images
      Dim b() As Byte = ImageToBytes(selectedImage)
      s.ExecNonQuery2("INSERT INTO Image (Name, Picture) VALUES(?,?)", Array As Object(FileName, b))
      log($"Inserted image ${FileName} of size ${b.Length} into DB"$)
      'Let's add the image to the ListView
      ListViewImage.AddTwoLinesAndBitmap(FileName,"",selectedImage)
      'Note: We don't have to call LoadListImage here, since that would just load all images again.
      'We're just adding the picked image
   Else
      Log("No image selected")
   End If
End Sub

B4X:
Sub LoadListImage
 
    Dim Cursor1 As Cursor
    Dim Name As String
    Dim Buffer() As Byte
    Dim IpSt As InputStream
    Dim Bitmap1 As Bitmap
    Cursor1 = s.ExecQuery("SELECT  name,Picture FROM Image")
 
    For i = 0 To Cursor1.RowCount - 1
        Cursor1.Position = i
        Name =Cursor1.GetString("name")
        Buffer = Cursor1.GetBlob("Picture")
        IpSt.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
        Bitmap1.Initialize2(IpSt)
        IpSt.Close
        ListViewImage.AddTwoLinesAndBitmap(Name,"",Bitmap1)
        ;Cursor1.Close '<== Wrong place
       
    Next
    Curser1.Close
    SetDivider(ListViewImage, Colors.LightGray, 1dip)
 
End Sub

Note: Code is untested
 
Upvote 0

WebQuest

Active Member
Licensed User
thanks for the tip, I tried but now I'm returning this error = java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference

B4X:
Sub LoadListImage
    Dim list2 As DataItemsCategoryImage
    Dim Cursor1 As Cursor
    Dim Name As String
    Dim Buffer() As Byte
    Dim IpSt As InputStream
    Dim Bitmap1 As Bitmap
    
    Cursor1 = s.ExecQuery("SELECT  name,Picture FROM Image")
    
    
    For i = 0 To Cursor1.RowCount-1
        Cursor1.Position = i
        Name = Cursor1.GetString("name")
        Buffer = Cursor1.GetBlob("Picture")
        IpSt.InitializeFromBytesArray(Buffer, 0, Buffer.Length) '<wrong
        IpSt.Close
        Bitmap1.Initialize2(IpSt)
        
        list2.FristRow=Name
        list2.ScondRow=""
        list2.Picture=Bitmap1
        ListViewImage.AddTwoLinesAndBitmap2(list2.FristRow,list2.ScondRow,list2.Picture,list2)
        ListViewImage.TwoLinesAndBitmap.ItemHeight = 106dip
        ListViewImage.TwoLinesAndBitmap.ImageView.SetLayout(5dip, 3dip, 100dip, 100dip)
        ListViewImage.TwoLinesAndBitmap.Label.TextSize = 7
        ListViewImage.TwoLinesAndBitmap.ImageView.Gravity =Gravity.FILL
        SetDivider(ListViewImage, Colors.LightGray, 1dip)
        
        
    Next
    Cursor1.Close
    
    
    
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
You need to run your App in Debug mode and let you give the B4A line that it is complaining about. This is also not the code I posted. In your code, you are closing the input stream IpST before Initializing the Bitmap with it! See the code for ReadBlob here (https://www.b4x.com/android/forum/threads/sql-tutorial.6736/).
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Your new code and @DonManfred's recommendation to check for Null, <1 buffer size
B4X:
Sub LoadListImage
    Dim list2 As DataItemsCategoryImage
    Dim Cursor1 As Cursor
    Dim Name As String
    Dim Buffer() As Byte
    Dim IpSt As InputStream
    Dim Bitmap1 As Bitmap
    
    Cursor1 = s.ExecQuery("SELECT  name,Picture FROM Image")
    For i = 0 To Cursor1.RowCount-1
        Cursor1.Position = i
        Name = Cursor1.GetString("name")
        Buffer = Cursor1.GetBlob("Picture")
        If Buffer <> Null And Buffer.Length > 0 Then
           IpSt.InitializeFromBytesArray(Buffer, 0, Buffer.Length) '<wrong
           Bitmap1.Initialize2(IpSt)
           IpSt.Close
           list2.FristRow=Name
           list2.ScondRow=""
           list2.Picture=Bitmap1
           ListViewImage.AddTwoLinesAndBitmap2(list2.FristRow,list2.ScondRow,list2.Picture,list2)
           ListViewImage.TwoLinesAndBitmap.ItemHeight = 106dip
           ListViewImage.TwoLinesAndBitmap.ImageView.SetLayout(5dip, 3dip, 100dip, 100dip)
           ListViewImage.TwoLinesAndBitmap.Label.TextSize = 7
           ListViewImage.TwoLinesAndBitmap.ImageView.Gravity =Gravity.FILL
           SetDivider(ListViewImage, Colors.LightGray, 1dip)
        Else
           Log($"Image named ${Name} had no content stored in the DB"$)
        End If        
    Next
    Cursor1.Close
End Sub
 
Upvote 0

WebQuest

Active Member
Licensed User
Thanks for everything, Solved, the problem is in the version of the db that contained records without images, I reinstalled a new package with empty db and it works, now I wanted to know how I can recover the name of the image no the string.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
That should be a new question (with a little bit more info on what exactly your trying to achieve/need).
 
Upvote 0

Mahares

Expert
Licensed User
Longtime User
Solved, the problem is in the version of the db
All these lines should be outside the loop. They should be done only once, not every record:
B4X:
 ListViewImage.TwoLinesAndBitmap.ItemHeight = 106dip
        ListViewImage.TwoLinesAndBitmap.ImageView.SetLayout(5dip, 3dip, 100dip, 100dip)
           ListViewImage.TwoLinesAndBitmap.Label.TextSize = 7
           ListViewImage.TwoLinesAndBitmap.ImageView.Gravity =Gravity.FILL
           SetDivider(ListViewImage, Colors.LightGray, 1dip)
 
Upvote 0

WebQuest

Active Member
Licensed User
Hi I'm having problems adding images to the db I get this error:
Error occurred on line: 408 (ImageHomeImage)
java.lang.IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.


CODE:
B4X:
Sub BtInsertImage_Click
    Dim selectedImage As Bitmap = TempBitmap
    Dim b() As Byte = ImageToBytes(selectedImage)
    Dim text As String = EditTextTitle.Text       
    Dim Date As String
    Dim Ora As String
    Dim Orario As String
    Dim Nr As Int
    'Variabili Orario
    Dim now As Long
    Dim M, H As String

    DateTime.DateFormat = "dd MMM yyyy"
    Date = DateTime.Date(DateTime.now)
        
    H = DateTime.GetHour(DateTime.Now)
    M = DateTime.GetMinute(DateTime.Now)
    Ora = H & ":" & M
        
    Orario = Date &"    "& Ora
    
    s.ExecNonQuery2("INSERT INTO Image (name,Picture,Date) VALUES (?,?,?) ", Array As Object(text,b,Orario))
    ToastMessageShow("Image Added",True)
    
    Dim list2 As DataItemsCategoryImage
    Dim Cursor1 As Cursor
    Dim Name As String
    Dim DataOrario As String
    Dim Buffer() As Byte
    Dim IpSt As InputStream
    Dim Bitmap1 As Bitmap
    Cursor1 = s.ExecQuery("SELECT  name,Picture,Date FROM Image")
    
    
    For i = 0 To Cursor1.RowCount - 1
        Cursor1.Position = i
    Next
    Name =Cursor1.GetString("name") '<<< this 408 line
    Buffer = Cursor1.GetBlob("Picture")
    DataOrario=Cursor1.GetString("Date")
    IpSt.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
    Bitmap1.Initialize2(IpSt)
    IpSt.Close
    Nr= Nr+1
    list2.FristRow=Name
    list2.ScondRow=DataOrario
    list2.Picture=Bitmap1
    ListViewImage.AddTwoLinesAndBitmap2(list2.FristRow,list2.ScondRow,list2.Picture,list2)
    ListViewImage.TwoLinesAndBitmap.ItemHeight = 106dip
    ListViewImage.TwoLinesAndBitmap.ImageView.SetLayout(5dip, 3dip, 100dip, 100dip)
    ListViewImage.TwoLinesAndBitmap.ImageView.Gravity =Gravity.FILL
            
    ListViewImage.TwoLinesAndBitmap.Label.TextColor=Colors.Green
    ListViewImage.TwoLinesAndBitmap.Label.TextSize = 20
    ListViewImage.TwoLinesAndBitmap.Label.Left= 120dip
    ListViewImage.TwoLinesAndBitmap.SecondLabel.TextColor=Colors.DarkGray
    ListViewImage.TwoLinesAndBitmap.SecondLabel.Left=120dip
    ListViewImage.TwoLinesAndBitmap.SecondLabel.TextSize= 17
    Cursor1.Close
    SetDivider(ListViewImage, Colors.LightGray, 1dip)
        ToastMessageShow("Image added to the protected archive",True)

    PanelInsertImageText.Visible=False
        EditTextTitle.Text=" "

End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Your still doing the same error that you did in post#18 of this thread. Your for/next loop is written incorrectly. You need to look at post#26 for a resolution. You should also take to heart @Mahares post #29.
 
Upvote 0

WebQuest

Active Member
Licensed User
Thanks I looked at the code and now I do not give more error. But I have the problem of the formats currently I can save and upload only jpg images, I added the jpeg library that I found here: Jpeg library.

I'm using this code to convert images to bytes, how can I add the jpeg format?
B4X:
Sub ImageToBytes( image As Bitmap) As Byte()
Dim out As OutputStream

out.InitializeToBytesArray(0)

image.WriteToStream(out,100,"JPEG")
    Return out.ToBytesArray
End Sub
Sub BytesToImage(bytes1() As Byte) As Bitmap
    Dim In1 As InputStream
    In1.InitializeFromBytesArray(bytes1, 0, bytes1.Length)
    Dim bmp1 As Bitmap
    bmp1.Initialize2(In1)
    Return bmp1
End Sub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
But I have the problem of the formats currently I can save and upload only jpg images
I'm using this code to convert images to bytes, how can I add the jpeg format?
What are you trying to say? That JPG and JPEG are different formats (they are not, see https://stackoverflow.com/a/23424447)? What are you using the library for? Resizing? That can be done without the library. See https://www.b4x.com/android/forum/t...byte-array-with-resize-quality-options.91774/. If you are doing a fixed resizing (all pictures 640x480) you don't even need that code, just the resize method of the B4XBitmap class.
 
Upvote 0

WebQuest

Active Member
Licensed User
Hi OliverA thanks for the availability I wanted to tell you that in the end I solved. The problem was in the size of the inserted Blob. So before saving the image in the DB I do a resizing, so I no longer receive errors.
B4X:
'I execute the intent that opens the menu with all the options containing images Drive, Gallery, OneDrive, Camera, etc ...

Sub ImageViewAggImage_Click

    Chooser.Initialize("chooser")
    Chooser.Show("image/Camera", "Select an image")
    ToastMessageShow("Select Image",True)

End Sub

'I declare the sub Result Loading the image in a listView for the preview and check dir, FileName to the variable TempBitmap.

Sub chooser_Result ( Success As Boolean, Dir As String, FileName As String)
    
    If Success Then
        ImageViewResult.Bitmap=LoadBitmap(Dir,FileName)
        ImageViewResult.Gravity=Gravity.FILL
        TempBitmap = LoadBitmap(Dir,FileName)
    Else
            ToastMessageShow("No image selected", True)
        End If
End Sub

'Resize the image

Sub CreateScaledBitmap(Original As Bitmap, NewWidth As Int, NewHeight As Int) As Bitmap
    Dim r As Reflector
       dim Bitmap1 as Bitmap
Bitmap1=r.RunStaticMethod("android.graphics.Bitmap", "createScaledBitmap", _
        Array As Object(Original, NewWidth, NewHeight, True), _
        Array As String("android.graphics.Bitmap", "java.lang.int", "java.lang.int", "java.lang.boolean"))
    Return Bitmap1
End Sub


Sub BtInsertImage_Click
    
'Adding the image in the database.

If EditTextTitle.Text<>"" And ImageViewResult.Bitmap<>Null  Then
Dim selectedImage As Bitmap = TempBitmap
selectedImage=CreateScaledBitmap(selectedImage,1920,1080)
Dim b2() As Byte = ImageToBytes(selectedImage)
        Dim text As String
        
s.ExecNonQuery2("INSERT INTO Image (name,Picture) VALUES (?,?) ", Array As Object(text,b))
ToastMessageShow("Image Added",True)
Else
        If ImageViewResult.Bitmap=Null Then
            ToastMessageShow("Not Image Loding,please exit to form",True)
Else
EditTextTitle.RequestFocus
ToastMessageShow("Enter a name or description",True)
End If
End If
EndSub
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
FYI, if you use the XUI library, your CreateScaledBitmap can be written without using Reflector
B4X:
Sub CreateScaledBitmap(Original As B4XBitmap, NewWidth As Int, NewHeight As Int) As B4XBitmap
   Original.Resize(NewWidth, NewHeight, True)
   Return Original
End Sub
Or you skip this and rewrite
B4X:
Dim selectedImage As Bitmap = TempBitmap
selectedImage=CreateScaledBitmap(selectedImage,1920,1080)
to
B4X:
Dim selectedImage As B4XBitmap = TempBitmap
selectedImage.Resize(1920,1080,True)
Finally, maybe this is just a typo on the posting here, but the image is converted to an byte array named b2
B4X:
Dim b2() As Byte = ImageToBytes(selectedImage)
but the byte array that is stored in the database is named b
B4X:
s.ExecNonQuery2("INSERT INTO Image (name,Picture) VALUES (?,?) ", Array As Object(text,b))
 
Upvote 0
Top