I'm trying to show a saved image in SQL Server but it gives me an error that says "parameter is not valid".
While oDataReader.Read()
TextBox1.Text = oDataReader("nombre")
Dim imagenbyte As Byte()
imagenbyte = oDataReader("imagen")
Dim mStream As New IO.MemoryStream()
mStream.Write(imagenbyte, 0, Convert.ToInt32(imagenbyte.Length))
Dim bm As Bitmap = New Bitmap(mStream, True)
PictureBox1.Image = bm
End While
You can consolidate that code down to this:
While oDataReader.Read()
TextBox1.Text = oDataReader("nombre")
Dim mStream As New IO.MemoryStream(oDataReader("imagen"))
PictureBox1.Image = Image.FromStream(mStream)
End While
The main fix here is using Image instead of Bitmap. And if you know you'll only have one record, you should change While to If. If you might have more than one record, you need to completely re-think some things in your user interface.
Related
my code is to read the image file path in every row and display it in the datagridview "Image" Column.
.....
what's the problem with my code? please help me fix this.
UPDATE
this is the updated code but it displays nothing.
Dim dbdataset As New DataTable
Try
con.Open()
query = "Select * FROM [svfmemberlist]"
cmd = New OleDbCommand(query, con)
da.SelectCommand = cmd
da.Fill(dbdataset)
dgvSearch.RowTemplate.Height = 150
source.DataSource = dbdataset
dgvSearch.DataSource = source
Dim img As New DataGridViewImageColumn()
dgvSearch.Columns.Add(img)
img.HeaderText = "Image"
img.Name = "img"
img.ImageLayout = DataGridViewImageCellLayout.Zoom
dgvSearch.Columns("img").DataGridView.AutoGenerateColumns = False
dgvSearch.Columns("Name").AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill
dgvSearch.Columns("img").Width = 150
For Each row As DataGridViewRow In dgvSearch.Rows
If Not row.Cells("imgPath").FormattedValue.ToString = Nothing Then
Dim str As String = row.Cells("imgPath").FormattedValue.ToString
Dim inImg As Image = Image.FromFile(str)
row.Cells("img").Value = inImg
Else
img.Image = Nothing
End If
Next
con.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
The following example does not match how you are loading data and images but with a little effort will work within your current code.
I created two columns in the DataGridView via the IDE, one Text and one Image DataGridViewColumn.
The first line in form load sets ImageLayout, second line of code sets alignment to top-left for appearances. Next I set auto-size mode for all columns followed by setting the row height for each row.
Next (these lines are to load images from a folder one level below the app folder).
Setup the path to the images.
Add images using FileImageBytes function (which I would place into a separate class or code module but works just fine in your form).
Yes everything is hard-wired so it's easy to see how everything works.
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CType(DataGridView1.Columns("PictureColumn"), DataGridViewImageColumn).ImageLayout = DataGridViewImageCellLayout.Normal
DataGridView1.Columns.Cast(Of DataGridViewColumn).Select(Function(col) col).ToList _
.ForEach(Sub(col) col.CellTemplate.Style.Alignment = DataGridViewContentAlignment.TopLeft)
DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells
DataGridView1.RowTemplate.Height = 222
Dim imagePath As String = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images")
DataGridView1.Rows.Add(New Object() {"Car1", FileImageBytes(IO.Path.Combine(imagePath, "Car1.bmp"))})
DataGridView1.Rows.Add(New Object() {"Car2", FileImageBytes(IO.Path.Combine(imagePath, "Car2.jpg"))})
End Sub
Public Function FileImageBytes(ByVal FileName As String) As Byte()
Dim fileStream As IO.FileStream = New IO.FileStream(FileName, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read)
Dim byteArray(CInt(fileStream.Length - 1)) As Byte
fileStream.Read(byteArray, 0, CInt(fileStream.Length))
Return byteArray
End Function
End Class
If a user selects an image it will save the image as per the below code:
PictureBox1.Image.Save(PicFile, System.Drawing.Imaging.ImageFormat.Jpeg)
Now if the user decides not to select an image, is there a way to skip this code? I currently get the following error:
Additional information: Object reference not set to an instance of an object.
This is what I've tried:
Dim opf As New OpenFileDialog
opf.Filter = "Choose Image(.jpg;.png;*.gif)|*.jpg;*.png;*.gif"
If opf.ShowDialog = DialogResult.OK Then
PictureBox1.Image = Image.FromFile(opf.FileName)
End If
Try
Dim ms As New MemoryStream
PictureBox1.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim img As Byte()
img = ms.ToArray()
DataGridView1.Rows.Add(img)
Catch ex As Exception
MessageBox.Show(ex.Message.ToString())
End Try
Now if the user decides not to select an image, is there a way to skip this code?
If by this you mean the user selects Cancel, then yes. Simply place the Try[...]Catch block into your If statement and it will only attempt the code if the user selects Open.
Something like this:
Dim opf As New OpenFileDialog
opf.Filter = "Choose Image(.jpg;.png;*.gif)|*.jpg;*.png;*.gif"
If opf.ShowDialog = DialogResult.OK Then
PictureBox1.Image = Image.FromFile(opf.FileName)
Try
Dim ms As New MemoryStream
PictureBox1.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim img As Byte()
img = ms.ToArray()
DataGridView1.Rows.Add(img)
Catch ex As Exception
MessageBox.Show(ex.Message.ToString())
End Try
End If
If you only wanted to skip certain bits of code you could do a check on opf.FileName. As an example:
If opf.FileName <> "" Then
PictureBox1.Image = Image.FromFile(opf.FileName)
End If
Can anyone help me with this one? The scenario is that when I click any columns in a datagridview it will display the image to a picturebox
Private Sub DataGridView1_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick
If e.RowIndex >= 0 Then
Dim row As DataGridViewRow
row = Me.DataGridView1.Rows(e.RowIndex)
lblProperty.Text = row.Cells("Column1").Value.ToString
txtType.Text = row.Cells("Column2").Value.ToString
txtPrice.Text = row.Cells("Column3").Value.ToString
txtBed.Text = row.Cells("Column4").Value.ToString
txtBath.Text = row.Cells("Column5").Value.ToString
txtFootages.Text = row.Cells("Column6").Value.ToString
txtStatus.Text = row.Cells("Column7").Value.ToString
txtYear.Text = row.Cells("Column8").Value.ToString
txtDesc.Text = row.Cells("Column9").Value.ToString
Dim bytes As [Byte]() = row.Cells("Column10").Value
Dim ms As New MemoryStream(bytes)
pbImage.Image = Image.FromStream(ms)
txtDate.Text = row.Cells("Column11").Value.ToString
txtAddress.Text = row.Cells("Column12").Value.ToString
txtStories.Text = row.Cells("Column13").Value.ToString
End If
End Sub
It has an error Unable to cast object of type 'System.String' to type 'System.Byte[]'.
Dim bytes As Byte() = Datagridview1.CurrentRow.Cells(5).Value
Using ms As New MemoryStream(bytes)
Picturebox1.Image = Image.FromStream(ms)
End Using
Maybe you are over thinking it, there is a function to easily draw bitmaps.
I would suggest using the DrawToBitmap on the DataGridView by using the ColumnBounds
example this:
Dim GridBitmap as new Bitmap(DataGridView1.GetColumnDisplayRectangle(row.Cells("Column10").ColumnIndex,false).width,DataGridView1.GetColumnDisplayRectangle(row.Cells("Column10").ColumnIndex,false).height)
DataGridView1.DrawToBitmap(GridBitmap,DataGridView1.GetColumnDisplayRectangle(row.Cells("Column10").ColumnIndex,false))
pbImage.Image = GridBitmap
It might need to be adapted to your DataGridView.
Note, Instead of this:
Dim bytes As [Byte]() = row.Cells("Column10").Value
Dim ms As New MemoryStream(bytes)
pbImage.Image = Image.FromStream(ms)
Still having problem? Try this:
New project.
Add a DataGridView (DataGridView1) to your form.
Add some random columns to your gridview.
Add a Picture Box to your form (PictureBox1)
Make sure the Picture box property "SizeMode" is set to auto size.
Add an event forDataGridView1.MouseDown.
Add this code to the event.
Dim GridBitmap As New Bitmap(DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Width + DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Left, DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Height)
Dim GridColRectangle As New Rectangle(0, 0, DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Width + DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Left, DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Height + DataGridView1.GetColumnDisplayRectangle(e.ColumnIndex, True).Top)
DataGridView1.DrawToBitmap(GridBitmap, GridColRectangle)
PictureBox1.Image = GridBitmap
You may need to adjust it to your own application.
I have a form that I am trying to populate with a control for each item on my database (SQLCe). Problem is that one of the items I am trying to return from the database is an image. However, my original code gave me an error:
Value of type "Byte' cannot be converted to 'System.Drawing.Image'
Here is my original code
Private Sub btnCategories_Click(sender As Object, e As EventArgs) Handles btnCategories.Click
Dim dt As DataTable = ProducT_CATEGORYTableAdapter.GetData
For Each row As DataRow In dt.Rows
Dim btn As New btnCategoryTabs()
btn.lblCategoryName.Name = DirectCast(row("Category_Name"), String)
btn.lblCategoryName.Text = btn.lblCategoryName.Name
btn.picPCategoryPicture.Image = DirectCast(row("Image"), Byte) 'Error Here'
'Add categories to the Panel
flpMainPanel.Controls.Add(btn)
Next
End Sub
I am sure that I have to convert the image, so I started messing around with this bit of code:
Dim Stream As New MemoryStream()
Dim image As Byte() = CType('Can't figure out what to put here), Byte())
Stream.Write(image, 0, image.Length)
Dim bitmap As New Bitmap(Stream)
Any help will be appreciated.
Thanks.
If you have stored image data in your database then it would be a Byte() i.e. and array, not just a single Byte. You then have to convert that Byte array to an Image. You're on the right track. Here's one I prepared earlier:
Dim connection As New SqlConnection("connection string here")
Dim command As New SqlCommand("SELECT Picture FROM MyTable WHERE ID = 1", connection)
connection.Open()
Dim pictureData As Byte() = DirectCast(command.ExecuteScalar(), Byte())
connection.Close()
Dim picture As Image = Nothing
'Create a stream in memory containing the bytes that comprise the image.'
Using stream As New IO.MemoryStream(pictureData)
'Read the stream and create an Image object from the data.'
picture = Image.FromStream(stream)
End Using
http://www.vbforums.com/showthread.php?469562-Saving-Images-in-Databases&highlight=
In your case specifically, that becomes:
'Create a stream in memory containing the bytes that comprise the image.'
Using stream As New IO.MemoryStream(DirectCast(row("Image"), Byte()))
'Read the stream and create an Image object from the data.'
btn.picPCategoryPicture.Image = Image.FromStream(stream)
End Using
what is the problem of this code?? i got a error for the GDI+ and i dont know to solve.
Private Sub saveEmployee()
Dim ms As New MemoryStream
PictureBox1.Image.Save(ms, PictureBox1.Image.RawFormat)--i got error in this line..A generic error occurred in GDI+.
Dim arrPic() As Byte = ms.GetBuffer()
Dim cmdEmp As New MySqlCommand
Dim sqlEmp As String
sqlEmp = "update tbl_employee set emPic=#emPic where emID='" & lbl_empID.Text & "'"
With cmdEmp
.Parameters.AddWithValue("#emPic", arrPic)
.ExecuteNonQuery()
End With
End Sub
Try replacing that line with this :
Dim bm as Bitmap = new Bitmap(PictureBox1.Image)
bm.Save(ms, PictureBox1.Image.RawFormat)
The reason could be that the Image is being used by the PictureBox. Its also good practice to have the following instead :
Using ms As MemoryStream = New MemoryStream()
Dim bm as Bitmap = new Bitmap(PictureBox1.Image)
bm.Save(ms, PictureBox1.Image.RawFormat)
Dim arrPic() As Byte = ms.GetBuffer()
Dim cmdEmp As New MySqlCommand
Dim sqlEmp As String
sqlEmp = "update tbl_employee set emPic=#emPic where emID=#emID"
With cmdEmp
.Parameters.AddWithValue("#emPic", arrPic)
.Parameters.AddWithValue("#emID", int.Parse(lbl_empID.Text))
.ExecuteNonQuery()
End With
End Using
This way the MemoryStream will get Disposed after being used. And adding #emID as a parameter is safer.
RESOLVED!!!
Bind picture box to the datasource field using the Advance tab in the DataBindings section. Use the ImageLocation property instead of image. Then change the Update mode to NEVER. but how abt the update ??? Use a textbox and hide behind the Picture box [with visible = true]. Bind textbox to same datasource. THAT IS!!!
image displays directly in picture box whilst the textbox TextChanged property handles whether there is UPDATE or Not. took me a while but it works fine now. good luck as u code... ~ SAM, GHANA