Trying to read an Image from SQL

LarryLatLarryLat Member Posts: 3
edited 2012-05-31 in SQL General
I have developed a third party integration that pushes data out to SQL staging tables and pulls data from staging tables.

One of the tables I am trying to read from contains a Customer Signature. It is stored as an Image Datatype within SQL and seems to be identical to the way Navision stores BLOB files within Sql.

The third party provider assures me that the file is stored as a Bitmap.

I am trying to pull this data from SQL and store it into a BLOB file in a Navision staging table. I open up the connection to the SQL database, but I cannot seem to figure out how to grab that piece of data. All of my other routines work correctly (grabbing fields with types of Code, Text, Decimal, etc.), but I cannot grab the Image withour receiveing an error.

Any suggestions?

Thanks,

Larry

Comments

  • kinekine Member Posts: 12,562
    Blob must be transfered as files or some form of stream... Because you never knows the size (e.g. one image can have 2TB of data).
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • LarryLatLarryLat Member Posts: 3
    So any assistance on how to do the Streaming or the file transfer?
  • kinekine Member Posts: 12,562
    No, I never did that. It was just a hint in which direction you need to do your "research"...
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • krikikriki Member, Moderator Posts: 9,031
    [Topic moved from Navision forum to SQL General forum]
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!

  • byllebylle Member Posts: 47
    Hi !

    You can use ADO RecordSet to solve this.

    I assume, that you already are using ADO to read records from the mentioned table. If Yes, then you can use ADO RecordSet to read the image.

    There are 2 ways - as already mentioned by kine.

    1) Stream the image to a file and then afterwards import it into the blob.
    The Stream can be done by using ADO Stream.
    Simplified Stream Example:
    
    ADOStream.Open;
    ADOStream.WriteText(ADORecordSet.Fields.Item(FieldName).Value);
    ADOStream.Position:= 0;
    ADOStream.Type := 1;
    ADOStream.SaveToFile('c:\image.bmp',2);
    ADOStream.Close;
    CLEAR(ADOStream);
    

    I guess you know how to import a file into a blob ;-)

    2) Another way is to move/insert the image into your table by using ADO RecordSet. Create 2 connections, one to your image table (ADOConn) and one to the table in Navision (NAVconn) where you want the picture to be inserted. Then "transfer" the Value from one RecordSet to another and Add it.
    Example:
    
    FromRecSet := ADOConn.Execute('SELECT image FROM tableX','',0);
    FromRecSet.MoveFirst;
    
    //The following query is used to get a "blank" recordset, just like a INIT in Navision
    MyQuery := 'SELECT [EntryNo], [Picture] FROM [MyTable] WHERE [EntryNo] = 0';
    
    NewRecSet.Open(MyQuery,NAVconn,1,3,1);
    NewRecSet.AddNew;
    NewRecSet.Fields.Item('Picture').Value := FromRecSet.Fields.Item('image').Value;
    NewRecSet.Update;
    

    Hope this helps :-)
  • kinekine Member Posts: 12,562
    Will the second way work if the NAV Blob field is compressed?
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • bbrownbbrown MAMember Posts: 3,219
    FYI: This image datatype is going away. I'm not sure if it's still supported in SQL 2008.
    There are no bugs - only undocumented features.
  • byllebylle Member Posts: 47
    The second way will not work for NAV compressed BLOB fields. It only works for uncompressed fields.

    If you try it - your code will not fail. Everything will look ok - but when you try to export /read your blob field it will get an error.

    Therefore in case of compressed fields, I would use the first way.

    Btw. I can see, that I have posted a wrong code to the first way... so here is the correct code ;-)
    ADOStream.Type := 1; //1 = Binary
    ADOStream.Open;
    ADOStream.Write(ADORecordSet.Fields.Item(FieldName).Value);
    ADOStream.SaveToFile('c:\tmp.bmp',2); //2 = SaveCreateOverWrite
    ReturnTable.Picture.IMPORT('c:\tmp.bmp');
    ADOStream.Close;
    CLEAR(ADOStream); 
    

    It is important that the Type is set at first or else you will not be able to read the image as a binary file. If Type is set after Open, you will read the image as Text - and this will not always work.
  • nXqdnXqd Member Posts: 39
    thanks bylle for great answer. I helps me a lot in working with ado stream and blob :)
    For one who want to read more about ado stream :
    http://msdn.microsoft.com/en-us/library ... 32(v=vs.85).aspx
  • mtlmonkmtlmonk Member Posts: 47
    Trying to test this with version 2013R2 and up. For testing purposes, I'm trying to extract from a NAV DB but I'm not able to view the file after it's copied into a physical one. The size is also smaller than the initial one that I've uploaded on the item card.
  • krikikriki Member, Moderator Posts: 9,031
    That is because NAV compresses the data in a blob by default. The BLOB fields has a property "Compression" which is default Yes. Change it to No and try again.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!

  • psycho9779psycho9779 Member Posts: 1
    In regards to compression if somebody still needs it,

    save image to file using bcp where dbname is nav database and objexp is a table with one image column - for the export template
    bcp "[dbname].[dbo].[objexp]" format nul -T -n -f C:\temp\testblob.fmt -S localhost\navdemo
    
    bcp "SELECT top 1 [User Code] from [dbname].[dbo].[Object Metadata]" QUERYOUT C:\temp\obj.zip -T -f C:\temp\testblob.fmt -S localhost\navdemo
    

    remove first 8 bytes which are probably the size
    deflate the stream like this (powershell code):
    $i = [System.IO.File]::OpenRead("C:\temp\obj.zip")
        $o = [System.IO.File]::OpenWrite("C:\temp\obj.txt")
        $t = New-Object System.IO.Compression.DeflateStream($i, [System.IO.Compression.CompressionMode]::Decompress)
        $t.CopyTo($o)
        $t.Close()
        $o.Close()
        $i.Close()
    

    since this is all supported in .net, can be done fully in c#
Sign In or Register to comment.