Deserializing byte to image from sql through memory stream - sql-server

I have convert an image to be saved in SQL Server Database as Binary with column name as "img". I have PictureBox1 ready to show the image.
Now I want to import the binary data back into image, and I'm trying this code in VB.net for example:
Dim queries As String
queries = "SELECT * from StudentData where Std_fname='" & ComboBox1.Text & "'"
Dim com As New SqlCommand(queries, sqlconn)
sqlconn.Open()
Dim ds As New SqlDataAdapter(queries, sqlconn)
Dim dr As SqlDataReader
dr = com.ExecuteReader()
While dr.Read
Std_fnameTextBox.Text = dr("Std_fname")
Std_lnameTextBox.Text = dr("Std_lname")
AgeTextBox.Text = dr("age")
AddressTextBox.Text = dr("address")
StateTextBox.Text = dr("state")
CityTextBox.Text = dr("city")
CountryTextBox.Text = dr("country")
Ic_passportTextBox.Text = dr("ic_passport")
DobDateTimePicker.Text = dr("dob")
PictureBox1.Image = dr("img") 'Here is the problem. If I run it, it ask me to convert Binary to Image first.
End While
sqlconn.Close()
The problem is, I don't know how to convert binary to image in this situation. And yes, I've been googling for it, but can't seem to get the right answer.

dr("img") returns either DBNull.Value, or a byte[]. You can use the stream overload of the Bitmap constructor to load this. In C# (should be easy to translate to VB), you can do it like this:
var imageData = (byte[])dr["img"];
using (var ms = new MemoryStream(imageData))
{
var bmp = new Bitmap(ms);
// Work with bmp
}
As Mark correctly noted, you're supposed to keep the stream open for the whole life-time of the Bitmap - this is actually a bit trickier than it seems, because the Bitmap doesn't even keep a reference to the stream.
The easiest way to handle this is to clone the bitmap after you create it, to remove the dependency on the stream. Unless you can do whatever work you need to do within the using - unlikely if you want to display it in a PictureBox.
You can also use ImageConverter.ConvertFrom directly, but all it does is create the MemoryStream if used on raw byte[] data :)

Related

How to show an image from a DataGridView to a PictureBox?

I'm trying to show an image in my DataGridView in a PictureBox.
I'm using SQL Server as database.
Me.PictureBox2.Image = DataGridView2.Item(10, i).Value
I'm wondering what code I am using.
This is the error says:
Unable to cast object of type 'System.Byte[]' to type 'System.Drawing.Image'.
You need to convert the Blob field Byte array (now a DataGridView cell Value) to an Image object.
A MemoryStream can be used to collect the Byte array and become the Stream source for the Image.FromStream() method.
If DataGridView2(10, 1).Value Is Nothing Then Return
Using ms As MemoryStream = New MemoryStream(CType(DataGridView2(10, i).Value, Byte()))
PictureBox2.Image?.Dispose()
PictureBox2.Image = Image.FromStream(ms)
End Using

Getting MetaData from an image file

We have images stored on a DB and they are being used to replace an image within a Word document - that bit works perfectly, except where the replacement image is portrait and it's replacing a landscape one, so I'm trying to get the metadata to determine how the image is orientated using this function
Public Function GetImageTags(ImageFile() As Byte) As String()
Try
Dim vReturnArray() As String = Nothing
Using MS As New System.IO.MemoryStream(ImageFile)
Dim vDecoder As BitmapDecoder = BitmapDecoder.Create(MS, BitmapCreateOptions.None, BitmapCacheOption.Default)
Dim vFrame As BitmapFrame = vDecoder.Frames(0)
Dim vMetadata As BitmapMetadata = TryCast(vFrame.Metadata, BitmapMetadata)
If vMetadata IsNot Nothing And vMetadata.Keywords IsNot Nothing Then
vReturnArray = vMetadata.Keywords.ToArray()
End If
End Using
Return vReturnArray
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
...but it throws the toys out with...
This codec does not support the specified property.
at System.Windows.Media.Imaging.BitmapMetadata.GetQuery(String query)
at System.Windows.Media.Imaging.BitmapMetadata.get_Keywords()
...at BitMapMetadata.Keywords. Any idea how I can overcome this and get the keywords?
Thank you
================ UPDATE ================
It appears that the error, and I also tried...
vReturnArray = TryCast(vMetadata.GetQuery("System.Keywords"), String())
... is only returned for some images, but all that I tried returned Nothing for the String()
There is a really good EXIF class on Code Project that is easy to implement, either with a string link to the file
Dim vEXIF As New ImageEXIF(ImagePath)
Dim vOrientation As Integer = vEXIF.Orientation
or as BitMap
Dim vOrientation As Integer = 0
Using vBitmap As System.Drawing.Image = System.Drawing.Image.FromStream(New IO.MemoryStream(ImageFile))
Dim vEXIF As New ImageEXIF(vBitmap)
vOrientation = vEXIF.Orientation
End Using
It would not be difficult to add another Sub to the class for Byte(), but the above conversion is quite straightforward and the class should work with all image types.
You could use MetadataExtractor to access the image metadata.
Check for the presence of ExifDirectoryBase.TagOrientation on any of the contained Exif directories.
Something like this (sorry it's C# as I don't know VB.NET):
var orientation = ImageMetadataReader.ReadMetadata(imagePath)
.OfType<ExifSubIfdDirectory>()
.Select(d => d.GetObject(ExifDirectoryBase.TagOrientation))
.First(o => o != null);

Load/split a .txt into multiple listboxes.?

I am trying to figure out a way to load a very large .txt file and thought if I break it into sections (Listboxes) it would load faster and be easier to manipulate with less lag. Or is there a way to OFD with a background worker?
Here is how I am loading the .txt
TextBox1.Text = ""
OpenFileDialog1.Title = "Load File"
OpenFileDialog1.InitialDirectory = "C:temp"
OpenFileDialog1.ShowDialog()
Dim path As String = OpenFileDialog1.FileName
TextBox1.Text = path
Dim lines() As String = IO.File.ReadAllLines(TextBox1.Text)
I can go in and mark every 1/4 of the .txt with a delimiter if that would help?
I was thinking if I iterate through XX amount of lines then Next listbox etc. Maybe some form of items.count in a if not statement? My mind is going in circles please aim me in the best direction. My file is 25.MB and growing slowly. Notepad++ is the only thing handling it well ATM.
ListBox1.Items.Add(lines(1 - 10000))
throws an error ("Outside array index or similar")
ListBox1.Items.Add(lines(10000))
Loads the single line
Probably something along the lines of this. This is not 100% accurate code. But to give you an idea.
Dim dt As New DataTable()
Dim lines As New List(Of [String])()
lines = New List(Of [String])(File.ReadLines(ofDialog.FileName))
Task.Run(Function()
Dim options As New ParallelOptions()
options.MaxDegreeOfParallelism = CInt(1)//Number of threads to spawn
Parallel.ForEach(lines, options, Function(line)
dt.Rows.Add()
End Function)
Me.Invoke(DirectCast(Sub() listview.DataSource = dt, MethodInvoker))
End Function)

Manipulating a database in C++

I apologize if has been asked, and answered somewhere else, but I have been searching like crazy and can't find what I'm looking for.
OleDbConnection^ conn = gcnew OleDbConnection ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Milestone3testdatabase.accdb; Persist Security Info=True");
OleDbCommand^ com = gcnew OleDbCommand();
com->Connection = conn;
com->CommandText = "SELECT *FROM tblcity;";
System::Data::DataSet^ ds = gcnew System::Data::DataSet();
OleDbDataAdapter^ adapt = gcnew OleDbDataAdapter();
adapt->SelectCommand = com;
adapt->Fill(ds,"why");
dataGridView1->DataSource = ds->Tables["why"];
I am trying to figure out how to actually use the data I obtain from the database. I was shown how to put it into a gridview, BUT I don't want a gridview. I want be able to take 1 cell of the table and display it as text.
How do I convert the table into usable data for a C++ forms application?
Either modify your SELECT so that it returns only a single value by using SqlCommand.ExecuteScalar Method or extract the value from your table with the DataTable.Select Method and DataTable.Rows Property
myDataTable->Rows[rowNumber][columnNumber]

Get image from resource dll as MemoryStream

I use WPF and my program has images in a DLL resource file. I have this well working way to read in images from disk:
Private Function GetImageFromFile(ByVal fileName As String) As BitmapImage
Dim buffer As Byte() = IO.File.ReadAllBytes(fileName)
Dim memoryStream As New IO.MemoryStream(buffer)
Dim bitmap As New BitmapImage()
bitmap.BeginInit()
bitmap.StreamSource = memoryStream
bitmap.EndInit()
bitmap.Freeze()
Return bitmap
End Function
Now, how can I get images in this MemoryStream-way from a DLL resource?
The basic problem: If I use simply the "bitmap.UriSource = whatever uri" way and load many images in sequence like an animation it builds up the memory. I tried with the above memorystream way and it worked perfectly fine, but then I store my images in a dll and I don't know how to do this trick. If anybody knows how to read many images from a managed dll without building up the memory pls, let me know.
I found the answer to my question. I put it here for others who may need it. There are more ways to load images from a resource dll file. The easiest way to initialize the BitmapImage and set bi.UriSource=uriPath (where the path looks like I show below) but when you load images in a sequence, as an animation for example, it seems to take a lot of memory. Then you can use a StreamResourceInfo as shown below and just put like bi.StreamSource = sri.Stream. That works, too, but memorywise it has same results. So in practice I found the following way the fastest and most memory efficient way to load hundreds of images in a sequence:
Public Function GetImageFromDLL(ByVal uriPath As String) As BitmapImage
Dim sri As Windows.Resources.StreamResourceInfo = Application.GetResourceStream(New Uri(uriPath, UriKind.Absolute))
Dim binReader As New System.IO.BinaryReader(sri.Stream)
Dim buffer As Byte() = binReader.ReadBytes(sri.Stream.Length)
Dim memoryStream As New IO.MemoryStream(buffer)
Dim bi As New BitmapImage()
bi.BeginInit()
bi.CacheOption = BitmapCacheOption.Default
bi.CreateOptions = BitmapCreateOptions.None
bi.StreamSource = memoryStream
bi.EndInit()
bi.Freeze()
Return bi
End Function
Where the uriPath is something like: "pack://application:,,,/YourDLL;Component/YourImageFile.jpg"

Resources