Subscribe for automatic updates: RSS icon RSS

Login icon Sign in for full access | Help icon Help
Advanced search

Pages: [1]
  Reply  |  Print  
Author Topic: Accessing device camera from within a Genero Mobile application  (Read 838 times)
Richard M.
Posts: 14


« on: October 10, 2024, 02:26:40 pm »


Hi,

We need our current mobile app to be able to open the device camera in response to a user request, take a photo and reference it in the database for later upload to the back-end DB.

We have not done any significant development work for a while so would appreciate some help on where to look for examples on how to do this.
I presume its via a 'frontcall' somehow(?)

Bit of a broad question perhaps, but i'm not sure where to start looking....


Thanks
Scott B.
Four Js
Posts: 27


« Reply #1 on: October 10, 2024, 05:10:18 pm »

Hi Richard:

While I expect others to reply with more examples, I wanted to point you to the BDL documentation topic "Images on mobile devices" at https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_images_dynamic_images.html#c_fgl_images_dynamic_images__mobile_images

Richard M.
Posts: 14


« Reply #2 on: October 10, 2024, 05:47:23 pm »

That's great

Thanks Scott
Richard M.
Posts: 14


« Reply #3 on: October 17, 2024, 05:42:48 pm »

Hi,

Thought i was on the right track with this but am getting an error at the 'CALL security.Base64.FromByte' line below,
saying 'Forms Statement Error -15701 Invalid Parameter'.

Can anyone help plz?    Thanks


FUNCTION LIB_CHT_GET_PHOTO()                      #REMPHOTOS

CONSTANT l_vm_fn = "mypic.tmp"
DEFINE l_md_fn     STRING,
       l_image     BYTE,
       l_photos    RECORD LIKE photos.*,
       b64string   STRING

    --CALL LIB_CHT_TAKE_PHOTO() RETURNING l_filename
    TRY -- This front call may fail if the front-end is not a mobile device:
       CALL ui.Interface.frontCall( "mobile", "takePhoto", [], [l_md_fn] )
    CATCH
       MESSAGE "Cannot take photo: ", STATUS, " ", err_get(STATUS)
       LET l_md_fn = NULL
    END TRY
   
    IF l_md_fn IS NOT NULL THEN

        CALL fgl_getfile(l_md_fn, l_vm_fn)
        LOCATE l_image IN FILE l_vm_fn
        CALL security.Base64.FromByte(l_image) RETURNING b64string
 
        INITIALIZE l_photos TO NULL

        LET l_photos.photo_id   = NULL
        LET l_photos.filename   = l_md_fn
        LET l_photos.photo      = b64string
        LET l_photos.sync       = "1"
   
        INSERT INTO photos VALUES l_photos.*

        LET l_photos.photo_id = LIB_SYS_GET_ID("photos")

    END IF

END FUNCTION

Richard M.
Posts: 14


« Reply #4 on: October 19, 2024, 11:42:24 pm »

The below code now works.


-----------------------------;

FUNCTION LIB_CHT_GET_PHOTO(l_drop_id)                      #REMPHOTOS

CONSTANT l_vm_fn = "mypic.png"
DEFINE l_drop_id    INTEGER

DEFINE l_md_fn     STRING,
       l_image,
       l_byte      BYTE,
       l_photos    RECORD LIKE photos.*,
       b64string   STRING,
       l_text      TEXT

    --CALL LIB_CHT_TAKE_PHOTO() RETURNING l_filename
    TRY -- This front call may fail if the front-end is not a mobile device:
       CALL ui.Interface.frontCall( "mobile", "takePhoto", [], [l_md_fn] )
    CATCH
       MESSAGE "Cannot take photo: ", STATUS, " ", err_get(STATUS)
       LET l_md_fn = NULL
    END TRY
   
    IF l_md_fn IS NOT NULL THEN

        CALL fgl_getfile(l_md_fn, l_vm_fn)
        CALL security.Base64.LoadBinary(l_vm_fn) RETURNING b64string
 
        LOCATE l_text IN MEMORY
        LET l_text = b64string
       
        INITIALIZE l_photos TO NULL

        LET l_photos.photo_id   = NULL
        LET l_photos.drop_id    = l_drop_id
        LET l_photos.filename   = l_md_fn
        LET l_photos.photo      = l_text
        LET l_photos.sync       = "1"
   
        INSERT INTO photos VALUES l_photos.*

        LET l_photos.photo_id = LIB_SYS_GET_ID("photos")

    END IF

END FUNCTION
Richard M.
Posts: 14


« Reply #5 on: October 19, 2024, 11:46:09 pm »

Plus you need to;

IMPORT security
Reuben B.
Four Js
Posts: 1114


« Reply #6 on: October 20, 2024, 02:35:14 am »

Re your error with security.base64.FromByte, note the Important tip in the documentation https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_SecurityBase64_FromByte.html

Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero
Sebastien F.
Four Js
Posts: 545


« Reply #7 on: October 21, 2024, 08:21:54 am »

Hello Richard,

Can you please provide the context (Genero version, Front-ends type and version, DB servers type and version, OSes type and version, etc) - We can better help if we know the context and such "details".

I was wondering why you need to convert the image data to base64.
I assume this is to send the images as plain text to the server?

About using IMPORT security:

While security.Base64.FromByte() needs the BYTE to be located in memory, DISPLAY BY NAME needs the BYTE to be located in a file:
https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_images_dynamic_images.html
Section "Displaying images contained in BYTE variables"

Since Genero BDL 2.51, we have util.Strings methods to encode/decode in base64.

https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_ext_util_Strings_methods.html

Except if you really need other APIs of the "security" module in your mobile app, I would just use the "util" package.

How to you plan to upload the photos to the central database?
Using RESTful Web Services?

What is the SQL CREATE TABLE DDL for the local mobile l_photos table and its equivalent on the server side to store photos?

Seb
Sebastien F.
Four Js
Posts: 545


« Reply #8 on: October 21, 2024, 04:28:35 pm »


Attached a sample using takePhoto / choosePhoto front calls and displaying the photo.

If someone has a better way to do this for mobile apps, suggestions are welcome.

Seb

* form.per (0.55 KB - downloaded 23 times.)
* main.4gl (1.42 KB - downloaded 24 times.)
Sebastien F.
Four Js
Posts: 545


« Reply #9 on: October 22, 2024, 08:24:00 am »


Note that when running on mobile, you can directly display the opaque filename returned by the takePhoto or choosePhoto front call.

Warning: you must remove UNBUFFERED mode in the main.4gl sample, otherwise the BYTE variable automatic display will take place.

Code
  1.        ON ACTION take_photo_disp
  2.           CALL ui.Interface.frontCall("mobile","takePhoto",[],filename)
  3.           IF filename IS NOT NULL THEN
  4.              INITIALIZE rec.* TO NULL
  5.              LET rec.name = filename
  6.              DISPLAY filename TO photo
  7.           END IF

But that opaque filename is only valid during the lifetime of the app instance.

If you want to store the images in the local database to keep it persistent, you have to store the BYTE data (or the TEXT in base64, if there is any good read for that)

Seb
Roland W.
Posts: 22


« Reply #10 on: October 22, 2024, 09:05:24 am »

Sebastien,

are there any substantial differences between the routines of the util.Strings and security.Base64 packages? What's the (dis)advantage of using one of the two packages?
I wasn't aware that both packages contain the same routines. Couldn't the documentation of the security.Base64 package point out to use the routines from util.Strings?

Apart from that, the parameters are described differently in the two packages. For example, the security.Base64.LoadBinary() (https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_SecurityBase64_LoadBinary.html) function specifies the parameter “path”, while the util.Strings.base64Encode() (https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_ext_util_Strings_base64Encode.html) function is called with the parameter “filename”. With the latter, it is not explicitly pointed out that the filename can also access network resources. Perhaps the documentation of the two packages could be standardized accordingly..

Kind regards
Roland
Sebastien F.
Four Js
Posts: 545


« Reply #11 on: October 22, 2024, 10:08:55 am »

Hello Roland,

Quote
are there any substantial differences between the routines of the util.Strings and security.Base64 packages? What's the (dis)advantage of using one of the two packages?

There should be no differences regarding pure base64 encoding/decoding. However, as mentioned by Reuben, there is a constraint with security.Base64.FromByte()/ToByte() requiring the BYTE to be located in memory.

I see an advantage on using util.Strings because there are less dependencies to other libs, if you need only to do base64 conversions.

Here the deps of the security.so library on my Linux box:

Code
  1. $ ldd -r $FGLDIR/lib/security.so
  2. linux-vdso.so.1 (0x00007ffcb99cd000)
  3. libfglutils.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfglutils.so (0x00007fa30a200000)
  4. libfglsecurity.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfglsecurity.so (0x00007fa309e00000)
  5. libfglgws.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfglgws.so (0x00007fa309a00000)
  6. libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3 (0x00007fa309400000)
  7. libfgl.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfgl.so (0x00007fa309000000)
  8. libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa30a8f0000)
  9. libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa308c00000)
  10. libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa30a811000)
  11. libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa30a5e0000)
  12. libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa30a01f000)
  13. libiconv.so.2 => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libiconv.so.2 (0x00007fa308800000)
  14. libssl.so.3 => /lib/x86_64-linux-gnu/libssl.so.3 (0x00007fa30a537000)
  15. libfgltransport.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfgltransport.so (0x00007fa308400000)
  16. libfglxml.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libfglxml.so (0x00007fa308000000)
  17. libxml2.so.2 => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libxml2.so.2 (0x00007fa307c00000)
  18. libxslt.so.1 => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libxslt.so.1 (0x00007fa307800000)
  19. libwrtl.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libwrtl.so (0x00007fa307400000)
  20. libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa30a808000)
  21. /lib64/ld-linux-x86-64.so.2 (0x00007fa30a912000)
  22. libxmlsec1-openssl.so.1 => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libxmlsec1-openssl.so.1 (0x00007fa307000000)
  23. libxmlsec1.so.1 => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libxmlsec1.so.1 (0x00007fa306c00000)
  24.  

Versus libfgl.so, where the IMPORT util package is built-in:

Code
  1. $ ldd -r $FGLDIR/lib/libfgl.so
  2. linux-vdso.so.1 (0x00007ffce853e000)
  3. libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2745ca0000)
  4. libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2745bc1000)
  5. libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2745bbc000)
  6. libwrtl.so => /home/sf/genero/software/fglgws-5.00.03-NB/lib/libwrtl.so (0x00007f2745400000)
  7. libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f274521f000)
  8. /lib64/ld-linux-x86-64.so.2 (0x00007f2745cc0000)
  9.  

Quote
I wasn't aware that both packages contain the same routines. Couldn't the documentation of the security.Base64 package point out to use the routines from util.Strings?

I will talk to the doc team about that, but usually we want to keep things independent.
You should be able to find all pages related to base64 support by using the doc search field.
Just try with "base64".

Quote
Apart from that, the parameters are described differently in the two packages. For example, the security.Base64.LoadBinary() (https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_gws_SecurityBase64_LoadBinary.html) function specifies the parameter “path”, while the util.Strings.base64Encode() (https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_ext_util_Strings_base64Encode.html) function is called with the parameter “filename”. With the latter, it is not explicitly pointed out that the filename can also access network resources. Perhaps the documentation of the two packages could be standardized accordingly..

You make a good, point but this is not a doc problem but rather an implementation problem:
The signature these methods uses different parameter names
You can see this by using code completion in vim, GST or VSCode.

Best regards,
Seb
Richard M.
Posts: 14


« Reply #12 on: October 22, 2024, 06:34:57 pm »

Hello Richard,

Can you please provide the context (Genero version, Front-ends type and version, DB servers type and version, OSes type and version, etc) - We can better help if we know the context and such "details".

I was wondering why you need to convert the image data to base64.
I assume this is to send the images as plain text to the server?

About using IMPORT security:

While security.Base64.FromByte() needs the BYTE to be located in memory, DISPLAY BY NAME needs the BYTE to be located in a file:
https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_images_dynamic_images.html
Section "Displaying images contained in BYTE variables"

Since Genero BDL 2.51, we have util.Strings methods to encode/decode in base64.

https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_ext_util_Strings_methods.html

Except if you really need other APIs of the "security" module in your mobile app, I would just use the "util" package.

How to you plan to upload the photos to the central database?
Using RESTful Web Services?

What is the SQL CREATE TABLE DDL for the local mobile l_photos table and its equivalent on the server side to store photos?

Seb

Thanks Seb,

The image is indeed converted to base64 so it can be sent as text via Web Services. 

I altered my code to use util.Strings.base64Encode and it works fine.

One additional issue/question;

I want to use the path returned from ui.Interface.frontCall( "mobile", "takePhoto", [], [path] ) to delete the picture held on the Android device after it has been processed.

An example of the path returned is 'content://media/external_primary/images/media/457?name=JPEG_GMA_20241022_170235.jpg&ext=jpg'

I was hoping to use os.Path.delete() to remove the picture, but the path above is invalid.

Any ideas on how to do this?

Thanks
Sebastien F.
Four Js
Posts: 545


« Reply #13 on: October 23, 2024, 10:57:02 am »

Hello Richard,

Regarding os.Path.delete() of a filename returned by takePhoto / choosePhoto:

I cannot help I am not expert for GMA/GMI internals.

Seb
Pages: [1]
  Reply  |  Print  
 
Jump to:  

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines