Android Code Snippet [B4X] Server picture File to B4XImageView VIA SQL Server

Thought I would share this. Sometimes it is just easier to go SQL direct rather than a jrdc server. I can get binary files from the server usually directly, but not always and enabling SMB1 is required and a security risk some clients aren't willing to go for.

This solution is designed for LOCAL networks and works both wired and wireless.

Below is an SQL Server Function that will return a BLOB when passed a filespec and B4X code that will turn that BLOB into an image.
Also, the T-SQL function has not been ESCAPED for quotes, Single quotes, etc. SO if the FileSpec has these characters it will probably fail. We don't allow our customers to use these characters so it is not an issue for us
Note what I have is B4J and B4A. Haven't done B4i.
Code:
USE [SkDataDemo44]
GO

/****** Object:  StoredProcedure [dbo].[GetDocFileBinary]    Script Date: 8/14/23 11:45:26 PM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE [dbo].[GetDocFileBinary] @FileName NVARCHAR(255)
AS
BEGIN
    --SET @FileName  = 'D:\New folder\YourFile.bmp'     --For Testing
    --SET @FileName = 'D:\YourDir\YourFile.bmp'     --For Testing

BEGIN TRY
    DECLARE @Pic varbinary(max)
    DECLARE @SQL NVARCHAR(1000) = '(SELECT @Pic2 = CAST(bulkcolumn AS varbinary(MAX)) FROM OPENROWSET(BULK ''' + @FileName + ''', SINGLE_BLOB) AS ROW_SET)'
    EXEC sp_executesql @SQL,  N'@Pic2 varbinary(max) OUTPUT', @Pic2 = @Pic OUTPUT;
    SELECT 'SUCCESS' Result, @Pic Picture --, LEN(@Pic);
END TRY
BEGIN CATCH
SELECT
    'Failed' Result,
    ERROR_NUMBER() AS ErrorNumber,
    ERROR_STATE() AS ErrorState,
    ERROR_SEVERITY() AS ErrorSeverity,
    ERROR_PROCEDURE() AS ErrorProcedure,
    ERROR_LINE() AS ErrorLine,
    ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
END
GO

You can test this in management studio with:
Code:
GetDocFileBinary 'D:\YourFilePath\YourFileName.bmp';
YOU MUST MAKE SURE YOU HAVE SQL SERVER RIGHTS TO THE FILES!
If it fails you will get something like this:
SQL:
Cannot bulk load. The file "D:\YourFilePath\YourFileName.bmp" does not exist or you don't have file access rights.    4860    1    16    NULL    1
Success will look like this:
SQL:
SUCCESS    0x424DB6F00400000000003600000028000000190100002001000001002000000000.........
Note that it is my habit in Server Side functions that return small amounts of data to ALWAYS make the first column 'Result' and return either SUCCESS or Failed, or the error message. Makes it easy to know what to do. I ALWAYS return one record. Sometimes it is 'Failed' and column 2 is 'No Data'

Below is the B4A/B4J code to set a B4XImageView. You will need to write your own code to retrieve the data, I have my own way of doing things. I have a routine that gets the data and returns it as a list of maps. This gives me the equivalent of a forward and backwards recordset.
The Important thing is Res As JdbcResultSet .... Res.GetBlob("Picture")

B4X:
Class_Globals
    Private TravPic As B4XImageView

.
.
'You will need to modify this code to get the data
Wait For (MP.Ethernet.Getdata("GetDocFileBinary", Array("D:\YourFilePath\YourFileName.JPG"))) Complete (DataRows As List)
If Not(DataRows.Get(0).As(String).Contains("Request Failed")) Then
    Dim TMap As Map = DataRows.Get(0)
    If TMap.Get("Result").As(String).EqualsIgnoreCase("SUCCESS") Then
'here is where your Res.GetBlob("Picture")
         Dim Buffer() As Byte  = TMap.Get("Picture")   'here is where your Res.GetBlob("Picture") should go
        Dim InputStream1 As InputStream
        InputStream1.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
        #If B4J
            Dim Bmp As Image
            Bmp.Initialize2(InputStream1)
        #Else
            Dim Buffer() As Byte  = TMap.Get("Picture")
            Dim InputStream1 As InputStream
            InputStream1.InitializeFromBytesArray(Buffer, 0, Buffer.Length)
            Dim Bmp As Bitmap
            Bmp.Initialize2(InputStream1)
            InputStream1.Close
        #End If
        TravPic.Bitmap = Bmp
        TravPic.ResizeMode = "FIT"
        TravPic.mBase.Visible = True
    End If
End If

Hope someone finds this useful.
If you spot a better way to do any of this I am all ears. Seems like there ought to be a way to turn a BLOB into an image without the #If B4.
 
Last edited:

Magma

Expert
Licensed User
Longtime User
@MrKim Thanks for sharing :)

Another great way... is using websocket (ofcourse not possible to upload binary data - so you must turn them to base64 string)

Check Erel's way with b4a code - you need also run your webserver (jserver) - it is also great if you don't want sql server:

If you have many BLOB uploads at sql server database make sure that files are small.... because the database and the records will be huge and difficult to manage it... but for sure is a great way for many things.

TIPs (for all members) for security and speed... think everytime different
* Sometimes binary files are big, so it is not a great option to read them at once, better to make them pieces (if you know your bandwidth will be better to use the half of it or 75% for every piece) ---> big files can timeout your server or crash it.... and need restart
* You can create your own gateway to your server with your imagination... for example use MQTT or better use UDP and specific port, or TCP... or JSERVER.. if you can play with ports in runtime... that will give extra security... a simple motif...
* Don't forget to encrypt data (b4xencyption will do it easily for you) - I will say that will be better not only encrypt files, but any data travelling at the internet...
* Also sometimes is better to keep them in databases encrypted or the files encrypted... and not decrypt when keep the at server... especially when server is not yours and in your place... (vps, shared hosting, etc)
* do not forget to ask for username and pass at your "gateway" every time.... may be need to create a token for the client too... to recognize him... that will add extra security
* Compress before send...
* An SSL will also help
 

MrKim

Well-Known Member
Licensed User
Longtime User
@MrKim Thanks for sharing :)

Another great way... is using websocket (ofcourse not possible to upload binary data - so you must turn them to base64 string)

Check Erel's way with b4a code - you need also run your webserver (jserver) - it is also great if you don't want sql server:
I am aware, and use these as well. We have clients who don't or won't run a separate server, and some are so small it is a waste of time and resources, this method is fine. We also restrict the file size. Our clients need a thumbnail of a part, not a detailed map of the known universe.

And some have learned the hard way what happens when you save large file. 🤪
 

Magma

Expert
Licensed User
Longtime User
Thanks for sharing... and sorry if feel some-interfere with my post (didn't want that)... actually i wanted to share Erel's way (if someone don't want sql server) and then my mouth/hands/fingers didn't stop typing :)
 

MrKim

Well-Known Member
Licensed User
Longtime User
Thanks for sharing... and sorry if feel some-interfere with my post (didn't want that)... actually i wanted to share Erel's way (if someone don't want sql server) and then my mouth/hands/fingers didn't stop typing :)
No worries.
 
Top