Android Question Adding a label to an image in Camera2

Cliff McKibbin

Member
Licensed User
Longtime User
I am using Camera2 to take a picture and save it to the download directory using the logic from the Camera2 sample as follows.
Note that I am currently setting the name of the jpg file to the date, time, latitude, and longitude of the picture.

B4X:
Sub TakePicture
  Try
        xErr="Focus and Take Picture"
        Wait For(cam.FocusAndTakePicture(MyTaskIndex)) Complete (Data() As Byte)
        Dim bmp As Bitmap = cam.DataToBitmap(Data)
        ' set name of jpg
        x="LL" & Starter.llnr 
        DateTime.DateFormat="yyyy-MM-dd hh-mm "
        X=x & DateTime.Date (MarkTime)
        X=x & "Lat " & ActLat & " Lg " & ActLg
'        Log ("Actlat " & ActLat)
        X=x & ".jpg"
        xErr="Data to File"
        cam.DataToFile(Data, VideoFileDir, x)

   Catch
        MsgboxAsync (xErr, "Error in Take Picture")
        Return    
    End Try
 End Sub



In
Erel gives a method to add an image of a compass to an image as follows.

B4X:
Dim bmp As B4XBitmap = cam.DataToBitmap(Data)
Dim bmp2 As B4XBitmap = LoadBitmap(File.DirAssets, "android-chrome-192x192.png")
Dim bc As BitmapCreator
bc.Initialize(bmp.Width, bmp.Height)
bc.CopyPixelsFromBitmap(bmp)
Dim r As B4XRect
r.Initialize(20dip, 20dip, 0, 0)
r.Width = bmp2.Width
r.Height = bmp2.Height
bc.DrawBitmap(bmp2, r, False)
Dim mergedbmp As B4XBitmap = bc.Bitmap

I would like to add a label with the latitude and longitude of the location of the picture.
Preferably, the label would be transparent and across the bottom of the picture.
The image with the label would be downloaded.

Any help would be appreciated,
Thanks, Cl;iff McKibbin
 

JohnC

Expert
Licensed User
Longtime User
(below is some of my own code edited by AI for this post)

You can draw the latitude and longitude directly onto the bitmap with a Canvas, then overwrite the original JPEG or save it under a new filename.

I normally draw the text twice: first in black with a slight offset to create a shadow, then again in a lighter color. This keeps the text readable without adding a solid background across the image so that the text can be easily read no matter what color the image pixels may be at that location.

B4X:
Sub AddLocationToImage(Dir As String, FileName As String, Latitude As Double, Longitude As Double)

    Dim iv As ImageView
    iv.Initialize("")
    iv.Bitmap = LoadBitmap(Dir, FileName)

    'The ImageView must have dimensions before initializing the Canvas.
    iv.Width = iv.Bitmap.Width
    iv.Height = iv.Bitmap.Height

    Dim cvs As Canvas
    cvs.Initialize(iv)

    Dim LocationText As String
    LocationText = NumberFormat2(Latitude, 1, 6, 6, False) & _
        ", " & NumberFormat2(Longitude, 1, 6, 6, False)

    Dim TextSize As Float = 16
    Dim LeftPosition As Float = 10dip
    Dim BottomPosition As Float = iv.Height - 10dip

    'Draw a black shadow slightly down and to the right.
    cvs.DrawText(LocationText, _
        LeftPosition + 1dip, _
        BottomPosition + 1dip, _
        Typeface.DEFAULT_BOLD, _
        TextSize, _
        Colors.Black, _
        "LEFT")

    'Draw the visible text over the shadow.
    cvs.DrawText(LocationText, _
        LeftPosition, _
        BottomPosition, _
        Typeface.DEFAULT_BOLD, _
        TextSize, _
        Colors.Yellow, _
        "LEFT")

    'Save the modified image.
    Dim Out As OutputStream
    Out = File.OpenOutput(Dir, FileName, False)
    cvs.Bitmap.WriteToStream(Out, 90, "JPEG")
    Out.Close

End Sub

Call it after DataToFile has saved the picture:

B4X:
cam.DataToFile(Data, VideoFileDir, x)
AddLocationToImage(VideoFileDir, x, ActLat, ActLg)

The overlay itself is transparent because only the text and its shadow are drawn. There is no filled rectangle behind it.

One thing to watch is image scaling. The example sets the ImageView dimensions to the bitmap’s actual pixel dimensions so that the text is drawn onto the full-resolution image rather than a scaled display copy.
 
Last edited:
Upvote 0

Cableguy

Expert
Licensed User
Longtime User
I would also try to add some sort of contrast detection, because black text on dark background will not be visible, and the same applies to white text on light background.
Search the forum... there are some samples swimming around
 
Upvote 0

Cliff McKibbin

Member
Licensed User
Longtime User
Thanks to everyone for the ideas. I finally ended up with this approach.
I added a panel to my screen and made it invisible.
I then passed the 'bmp' from 'TakePicture' to the following sub
note VideoFileDir = "/storage/emulated/0/Download" appears to be the universal dir for the android internal download dir. working so far.

B4X:
Sub AddLocationToImage (bmp1 As Bitmap)
    ' this version uses Erel's merge of two bmps
    
    bmp1=bmp1.Rotate (90)                ' had to rotate it 90
    
    ' Create a canvas for drawing on the panel
    Dim Canvas1 As B4XCanvas
    Canvas1.Initialize(PnlBmp)

   ' create 3 lines on the canvas
    Canvas1.DrawText(xDateTime, 20, 40, lbAct.font, lbAct.textColor, "LEFT")
    Canvas1.DrawText(ActLat, 25, 85, lbAct.font, lbAct.textColor, "LEFT")
    Canvas1.DrawText( ActLg, 25, 130, lbAct.font, lbAct.textColor, "LEFT")
        
    ' Capture the canvas as a bitmap
    Dim bmp2 As Bitmap
    bmp2 = Canvas1.CreateBitmap
    
   ' use Erel's merge of the two bitmaps
    Dim bc As BitmapCreator
    bc.Initialize(bmp1.Width, bmp1.Height)
    bc.CopyPixelsFromBitmap(bmp1)
    Dim r As B4XRect
    r.Initialize(0, bmp1.height-bmp2.height, 0, 0)
    r.Width = bmp2.Width
    r.Height = bmp2.Height
    bc.DrawBitmap(bmp2, r, False)
    Dim mergedbmp As B4XBitmap = bc.Bitmap
    
    ' write the bitmap out
    Dim out As OutputStream = File.OpenOutput(VideoFileDir, VideoFileName & ".jpg", False)
    mergedbmp.WriteToStream(out, 100, "JPEG")   '100 = quality
    out.Close

End Sub

Note the attached file with the date, time, lat, lg.
I wouldn't mind reducing the size of the text but haven't been able to find where to set the size.
 

Attachments

  • LL22695 2026-08-03 1617  41-34-40.734N 070-32-30.666W.jpg
    LL22695 2026-08-03 1617 41-34-40.734N 070-32-30.666W.jpg
    307 KB · Views: 65
Upvote 0

Cliff McKibbin

Member
Licensed User
Longtime User
My solution above had a big problem. Each new photo was overlaying the 'drawtext' so that it was unreadable in the 2nd to nth photo.
When using the create method 'b4xcanvas' there is a 'ClearRect' method that should be able to clear the canvas. I was unable to get it to work.
So, I changed to the create as 'Canvas' and used the 'DrawColor' method as shown. The problem was solved.
The other advantage ef 'Canvas' is that I could change the font size as shown in JohnC's example. I couldn't do that with 'b4xcanvas' in the DrawText command.
Here is the new code using 'Canvas'.

B4X:
Sub AddLocationToImage (bmp1 As Bitmap)
    ' this version uses Erel's merge of two bmps and JohnC's use of dim canvas1 as canvas
    
    bmp1=bmp1.Rotate (90)                                ' had to rotate it 90
    
    ' Create a canvas for drawing
    Dim Canvas1 As Canvas                                  ' had to use the 'canvas' vs b4xcanvas in order to get the drawcolor
    Canvas1.Initialize(PnlBmp)                               ' set up a PnlBmp on the 'page'. adjust the size so my drawtext would fit.
    ' clear the canvas for the 2nd to nth photo
    Canvas1.DrawColor (Starter.lbBackColor)        ' lbbackcolor is Colors.RGB(220,245,245) in my case
    
   ' draw the text   lbact.textcolor was black/adding the size 12, I was able to fit the info on 2 lines
    Canvas1.DrawText(xDateTime, 20, 40, lbAct.typeface, 12., lbAct.textColor, "LEFT")                    ' 40 spaces the line down from the top
    Canvas1.DrawText(ActLat & "  " & ActLg, 20, 85, lbAct.typeface, 12., lbAct.textColor, "LEFT")    ' 85 spaces it down one more line
    
    ' Capture the canvas as a bitmap
    Dim bmp2 As Bitmap
    bmp2=Canvas1.bitmap                                   ' had to change this from canvas1.createbitmap
    
    ' Merge bitmaps
    Dim bc As BitmapCreator
    bc.Initialize(bmp1.Width, bmp1.Height)            ' sets bc to the size of the first pic (bmp1)
    bc.CopyPixelsFromBitmap(bmp1)
    Dim r As B4XRect
    r.Initialize(0, bmp1.height-bmp2.height, 0, 0)    ' places the rect at the bottom of bmp1
    r.Width = bmp2.Width
    r.Height = bmp2.Height
    bc.DrawBitmap(bmp2, r, False)
    Dim mergedbmp As B4XBitmap = bc.Bitmap
    
    ' Write out merged bitmap
    Dim out As OutputStream = File.OpenOutput(VideoFileDir, VideoFileName & ".jpg", False)
    mergedbmp.WriteToStream(out, 100, "JPEG")   '100 = quality
    out.Close

End Sub
 
Upvote 0
Top