Retrieving multiple images from database - c#

So I'm working on my first project and right now there's something that's driving me a little bit crazy and I've been searching but I can't seem to find an answer.
I have two tables in my database, one is for the employee data (employeedata), and another only with pictures from their house (housepictures) with only three fields (PhotoID,EmployeeID,Photo), using a foreign key to the EmployeeID from the employeedata table.
I'm trying to retrieve the pictures from this table and put them in their respectives PictureBox (there are six in total, since I'm only storing 6 images for employee), but I've only managed to either retrieve the first picture, or the last, or the first picture and repeat it (this same photo) in every PictureBox. This is my current code:
try
{
using (MySqlConnection conn = new MySqlConnection(connDB.connstring))
{
using (MySqlCommand cmd = new MySqlCommand("select HousePicture from Employees.housepictures where EmployeeID='" + id + "'", conn))
{
conn.Open();
using (MySqlDataReader dr = cmd.ExecuteReader())
{
if (dr.Read())
{
PictureBox[] pb = { pictureBoxHouse1, pictureBoxHouse2, pictureBoxHouse3, pictureBoxHouse4, pictureBoxHouse5, pictureBoxHouse6 };
for (int i = 0; i < pb.Length; i++)
{
using (MemoryStream stream = new MemoryStream())
{
if (dr["HousePicture"] != DBNull.Value)
{
byte[] image = (byte[])dr["HousePicture"];
stream.Write(image, 0, image.Length);
Bitmap bitmap = new Bitmap(stream);
pb[i].Image = bitmap;
}
}
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Any suggestions would be very much appreciated!

Try getting your results first, then using while (instead of if) to loop through all those returned records. You can leave most of your code as-is, and increment a counter on each iteration of your loop, in order to set the correct PictureBox in your array.
PictureBox[] pb = { pictureBoxHouse1, pictureBoxHouse2, pictureBoxHouse3,
pictureBoxHouse4, pictureBoxHouse5, pictureBoxHouse6 };
using (MySqlDataReader dr = cmd.ExecuteReader())
{
int i = 0;
while (dr.Read())
{
using (MemoryStream stream = new MemoryStream())
{
if (dr["HousePicture"] != DBNull.Value)
{
byte[] image = (byte[])dr["HousePicture"];
stream.Write(image, 0, image.Length);
Bitmap bitmap = new Bitmap(stream);
pb[i].Image = bitmap;
}
}
i++;
}
}

Related

How to solve Operand type clash: varbinary(max) is incompatible with text

I'm trying to insert documents to a table in a DB, but I continue to get this error:
Operand type clash: varbinary (max) is incompatible with text
any direction would be extremely helpful.
The Document table has many columns, I only picked these two thinking I don't need all 50 columns which majority of them are null; both columns are set as (text, null) as the majority of the columns all (text, null).
I am hoping that I don't need to change anything to the database and that there is a way to change the code so that the files can populate correctly to the Documents table.
Here is my HttpPost:
[HttpPost]
public void UploadFiles()
{
if (!(Request.Files?.Count > 0)) return;
var filesCount = Request.Files.Count;
try
{
for (int i = 0; i < filesCount; i++)
{
var file = Request.Files[i];
var fileName = Path.GetFileName(file?.FileName);
if (fileName != null)
{
var fileBytes = new byte[file.InputStream.Length];
file.InputStream.Read(fileBytes, 0, fileBytes.Length);
file.InputStream.Close();
var cmdStr = "insert into [dbo].[Documents]
(DocumentName, DocumentLink) values(#val,#filename)";
using (var connection = new SqlConnection(con))
{
connection.Open();
var cmd = new SqlCommand(cmdStr, connection);
cmd.Parameters.AddWithValue("#val", fileBytes);
cmd.Parameters.AddWithValue("#filename", fileName);
cmd.ExecuteNonQuery();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}

Code to Insert Image into SQL Server

I want to insert an image into the SQL Server database from my Windows Forms application.
This question looks like it was trying to ask what I wanted to find out, but it was closed:
Insert image into SQL Server
Here is the code I used to do that.
Modify this code as needed for the table that you are going to use by viewing the design of your database in Microsoft Management Studio:
public static void InsertImage(int inventoryID, int businessID, FileInfo file, string sqlConnection)
{
var list = new List<byte>();
using (var stream = file.Open(FileMode.Open))
{
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
list.AddRange(data);
}
var bmp = System.Drawing.Image.FromFile(file.FullName, true);
using (var conn = new SqlConnection(sqlConnection))
{
conn.Open();
var imageId = -1;
var sqlSelect = "SELECT [ImageId] FROM [dbo].[ImageTable] WHERE [InventoryId]=#InventoryId;";
using (var cmd = new SqlCommand(sqlSelect, conn))
{
cmd.Parameters.Add("#InventoryId", System.Data.SqlDbType.Int).Value = inventoryID;
using (var r = cmd.ExecuteReader())
{
if (r.Read())
{
var o = r["ImageId"];
if ((o != null) && (o != DBNull.Value))
{
imageId = (int)o;
}
}
}
}
if (imageId == -1)
{
var sqlCmd = "INSERT INTO [dbo].[ImageTable] " +
"([InventoryId], [ImageFileName], [ImageSize], [ImageWidth], [ImageHeight], [ImageBytes]) " +
"VALUES " +
"(#InventoryId, #ImageFileName, #ImageSize, #ImageWidth, #ImageHeight, #ImageBytes); ";
using (var cmd = new SqlCommand(sqlCmd, conn))
{
cmd.Parameters.Add("#InventoryId", System.Data.SqlDbType.Int).Value = inventoryID;
cmd.Parameters.Add("#ImageFileName", System.Data.SqlDbType.VarChar, 255).Value = file.Name;
cmd.Parameters.Add("#ImageSize", System.Data.SqlDbType.Int).Value = list.Count;
cmd.Parameters.Add("#ImageWidth", System.Data.SqlDbType.SmallInt).Value = bmp.Width;
cmd.Parameters.Add("#ImageHeight", System.Data.SqlDbType.SmallInt).Value = bmp.Height;
cmd.Parameters.Add("#ImageBytes", System.Data.SqlDbType.VarBinary, -1).Value = list.ToArray();
cmd.ExecuteNonQuery();
}
}
}
}
To run/test the code, I created this helper method:
public static string[] GetImages(string fullFolderPath, string searchPattern)
{
var list = new List<String>();
if (Directory.Exists(fullFolderPath))
{
if (String.IsNullOrEmpty(searchPattern))
{
searchPattern = "*.jpg";
}
var dir = new DirectoryInfo(fullFolderPath);
var files = dir.GetFiles(searchPattern);
for (int i = 0; i < files.Length; i++)
{
InsertImage(i + 1, 1, files[i], _sqlConnection);
list.Add(files[i].FullName);
}
}
return list.ToArray();
}
Now, running it from my Console Application is a simple, single call:
static void Main(string[] args)
{
var list = GetImages(#"C:\inetpub\wwwroot\Ads", "*.jpg");
}

Set "NULL" in Empty cells in CsvReader

Here is my code:
using (System.Net.WebResponse tmpRes = tmpReq.GetResponse())
{
using (System.IO.Stream tmpStream = tmpRes.GetResponseStream())
{
using (System.IO.TextReader tmpReader = new System.IO.StreamReader(tmpStream))
{
string fileContents = tmpReader.ReadToEnd();
for (int i = 0; i < fileContents.Length; i++)
{
if (fileContents[i] == "")
{
fileContents[i] = "null";
}
}
using (Stream s = GenerateStreamFromString(fileContents))
{}
}
}
}
this shows error 'string' to 'char' convert implicitly. Is there any other way to set "NULL" in empty fields in CSVReader
You are not using the CsvReader at all. You are also not splitting the string by your delimiter to get "cells". However, you can load a DataTable from the CsvReader and modify that.
Here's an example presuming tab as delimiter:
var tblCSV = new DataTable();
using (System.Net.WebResponse tmpRes = tmpReq.GetResponse())
using (System.IO.Stream tmpStream = tmpRes.GetResponseStream())
using (System.IO.TextReader tmpReader = new System.IO.StreamReader(tmpStream))
using (var csv = new CsvReader(tmpReader, true, '\t', '"', '\0', '\0', ValueTrimmingOptions.All))
{
csv.MissingFieldAction = MissingFieldAction.ParseError;
csv.DefaultParseErrorAction = ParseErrorAction.RaiseEvent;
csv.ParseError += csv_ParseError;
csv.SkipEmptyLines = true;
// load into DataTable
tblCSV.Load(csv, LoadOption.OverwriteChanges, csvTable_FillError);
}
Now loop the rows and columns and modify them accordingly:
foreach(DataRow row in tblCSV.Rows)
{
foreach(DataColumn col in tblCSV.Columns)
{
if(string.IsNullOrWhiteSpace(row.Field<string>(col)))
row.SetField(col, "null");
}
}
Update related to your comment:
I wants to add NULL value in empty cells in sql database when the csv
data Save in database. Is there any other way?
You could simply use the loop above to update your table instead:
using (var con = new SqlConnection("ConnectionString"))
{
con.Open();
foreach (DataRow row in tblCSV.Rows)
{
using (var cmd = new SqlCommand("INSERT INTO table(Col1,Col2) VALUES (#Col1,Col2);", con))
{
string col1 = row.Field<string>("Col1");
if (string.IsNullOrWhiteSpace(col1))
col1 = null;
string col2 = row.Field<string>("Col2");
if (string.IsNullOrWhiteSpace(col2))
col2 = null;
cmd.Parameters.AddWithValue("#col1", col1);
cmd.Parameters.AddWithValue("#col2", col2);
int inserted = cmd.ExecuteNonQuery();
}
}
}

How to transfer an image obtained from a windows phone to a c# picturebox image

I have a windows phone app that takes a picture and sends it to a wcf service which sends it to a database so another app (windows forms app) can check the database and obtain the image.
It's adding data to the database as a byte array but when I check the values, they all say the same numbers, but it seems it works because theirs data there.
When I try to turn that data into an image though, it throws an exception saying the parameter isn't valid. I've searched for how to do this but what i find (even on here) says exactly what I'm doing. So I'm not sure what's wrong.
here's my code for the windows phone:
if (e.TaskResult == TaskResult.OK)
{
var bitImage = new BitmapImage();
bitImage.SetSource(e.ChosenPhoto);
//image is a Image Control in the form
ImageServiceClient client = new ImageServiceClient();
byte[] array;
using(var stream = new MemoryStream())
{
var btmMap = new WriteableBitmap(bitImage.PixelWidth, bitImage.PixelHeight);
// write an image into the stream
btmMap.SaveJpeg(stream, bitImage.PixelWidth, bitImage.PixelHeight, 0, 100);
array = stream.ToArray();
}
client.AddImageAsync(array);
}
the last line calls the add method in my wcf service which looks like:
public void AddImage(byte[] array)
{
var con =
new MySqlConnection(
"server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string h = array.Aggregate(h, (current, b) => current + b);
string text = "INSERT INTO images VALUES (''," + h + ")";
Console.WriteLine(text);
var command = new MySqlCommand(text, con);
var result = command.ExecuteReader();
result.Close();
}
It's good to note that it doesn't matter if I use the passed in array directly or if I turn it into text, they both show up the same in the database.
Then finally, in the app this is sending everything to, I have this:
var con =
new MySqlConnection(
"server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string h = "";
string text = "select Image from images where ImageId=4";
var command = new MySqlCommand(text, con);
var dr = command.ExecuteReader();
var g = new byte[] {};
if(dr.Read())
g = (byte[])dr[0];
dr.Close();
var image = Image.FromStream(new MemoryStream(g));
pictureBox1.Image = image;
but it always breaks on "var image = Image.FromStream(new MemoryStream(g));" saying the parameter is not valid.
I found out it has a big array once it gets the image but the one in the database is only 65 bytes and they all say 57.
Why is it completely disregarding my image's array and replacing it with a 65 byte one of all 57?
What am I doing wrong?
***************EDIT*****************************
I finally found what was wrong after enabling debugger in a wcf app.
http://msdn.microsoft.com/en-us/library/ff649234.aspx (for those who don't know)
I also looked here : http://www.codeproject.com/Articles/9686/Save-An-Image-Into-SQL-Server-2000-Database
to see why it was throwing a "your sql is wrong" type error and changed my sql statement to use the adding method instead of putting the value into the string.
That fixed it finally. The working code looks like this for nayone else comes across this problem:
public void AddImage(byte[] array)
{
var con =
new MySqlConnection("server=instance11297.db.xeround.com;User Id=Admin;Password=nomoredrama2010;port=7692;database=capstone");
con.Open();
string text = "INSERT INTO images (ImageId, Image) VALUES ('',#bytes)";
var command = new MySqlCommand(text, con);
command.Parameters.AddWithValue("#bytes", array);
command.ExecuteNonQuery();
con.Close();
}
I can finally stop beating my head against the wall. :)
you should use something like this.
//---read the data in buffer and write to ms2---
MemoryStream ms2 = new MemoryStream();
ms2.Write(b, 0, b.Lenght);
//---load it in a PictureBox control---
pictureBox2.Image = new Bitmap(ms2);

Saving an Image file to sql Server and converting byte array into image

I am storing images in a database and would like to convert them from byte array to image. I have no problem converting an object to byte array but I get an error of "Parameter is not valid" when trying to convert from byte array to image. The object I am passing to my method is from a dataset row.
Stored procedure
USE [----------------]
GO
/****** Object: StoredProcedure [dbo].[usp_imageloader_add_test] Script Date: 01/16/2012 09:19:46 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[usp_imageloader_add_test]
#p_Image Image
as
INSERT into Test_Images VALUES(#p_Image)
Upload File control /convert Image file to byte array and save data to database
protected void btnUpload_Click(object sender, EventArgs e)
{
if (ctrlUpload.PostedFile != null)
{
if (ctrlUpload.PostedFile.ContentLength > 0)
{
// Get Posted File
HttpPostedFile objHttpPostedFile = ctrlUpload.PostedFile;
// Find its length and convert it to byte array
int ContentLength = objHttpPostedFile.ContentLength;
// Create Byte Array
byte[] bytImg = new byte[ContentLength];
// Read Uploaded file in Byte Array
objHttpPostedFile.InputStream.Read(bytImg, 0, ContentLength);
using (SqlConnection dbConnection = new SqlConnection(app_settings.sql_conn_string_db))
{
try
{
string sql = "usp_imageloader_add_test";
SqlCommand cmd = new SqlCommand(sql, dbConnection);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#p_Image", bytImg).SqlDbType = SqlDbType.Binary;
cmd.Connection.Open();
cmd.ExecuteNonQuery();
cmd.Connection.Close();
}
catch (Exception ex)
{
ex.Message.ToString();
}
}
}
}
}
Table method which calls objToImg method
protected void Page_Load(object sender, EventArgs e)
{
generateTable(false);
}
private Table generateTable(bool flag)
{
Table tb = BuildList(GetData(), flag);
if (imgloadercms != null)
{
PlaceHolder ph = new PlaceHolder();
StringBuilder sb = new StringBuilder();
ph.Controls.Add(new LiteralControl(sb.ToString()));
}
imgloadercms.Controls.Add(tb);
return tb;
}
protected Table BuildList(DataTable tb, bool flag)
{
Table tblImageLibrary = new Table();
tblImageLibrary.BorderStyle = BorderStyle.Solid;
tblImageLibrary.BorderWidth = Unit.Pixel(8);
if (tb.Rows.Count > 0)
{
try
{
if (!flag)
{
tblImageLibrary.BorderColor = Color.Black;
tblImageLibrary.BorderWidth = Unit.Pixel(1);
TableRow tr = new TableRow(); // Table row for header of table
tr.BackColor = Color.LightBlue;
TableCell c1 = new TableCell();
TableCell c2 = new TableCell();
c1.Controls.Add(new LiteralControl("Image Id"));
tr.Cells.Add(c1);
c2.Controls.Add(new LiteralControl("Image"));
tr.Cells.Add(c2);
tblImageLibrary.Rows.Add(tr);
}
int i = 0;
foreach (DataRow r in tb.Rows) // Create new row foreach row in table
{
TableRow tr = new TableRow();
if (i % 2 == 0)
{
tr.BackColor = Color.LightYellow;
}
// Build cells
TableCell c1 = new TableCell();
TableCell c2 = new TableCell();
c2.Width = 300;
c1.Controls.Add(new LiteralControl(r["Image_Id"].ToString()));
tr.Cells.Add(c1);
// Call method to serialize obj to byte array
//System.Drawing.Image dbImg =
ObjToImg(r["Image_File"]);
}
catch (Exception ex)
{
ex.ToString();
}
if (!flag)
{
}
}
return tblImageLibrary;
}
Return Image
private System.Drawing.Image ObjToImg(object obj)
{
//byte[] byteArray = null;
if (obj == null)
return null;
else
{
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj); //now in Memory Stream
ms.ToArray(); // Array object
ms.Seek(0, SeekOrigin.Begin);
//return (System.Drawing.Image)bf.Deserialize(ms);
System.Drawing.Image myImage = (System.Drawing.Image)bf.Deserialize(ms);
return myImage;
}
Whenever I try to add the memory stream object to the image object constructor I get the error message of "Parameter is not valid". Maybe I made a mistake when insert the byte array into the database because I have looked at other code and it doesn't make sense how it's not working.
Try to deserialize the object first from byte array with your BinaryFormatter!
Try to use following two methods:
private System.Drawing.Image ObjToImg(byte[] obj)
{
if (obj == null)
return null;
else
{
BinaryFormatter bf = new BinaryFormatter();
using(MemoryStream ms = new MemoryStream(obj))
{
return (System.Drawing.Image)bf.Deserialize(ms);
}
}
}
private byte[] ImgToObj(System.Drawing.Image obj)
{
if (obj == null)
return null;
else
{
BinaryFormatter bf = new BinaryFormatter();
using(MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, obj);
return ms.ToArray();
}
}
}
I just recently had to do the exact same thing in VB.NET. Here is my code, run through Telerik's Code Converter. It was quite tricky to get working, and is still honestly a pain.
To upload an image:
private bool uploadImage(ref Bitmap p)
{
SqlConnection con = new SqlConnection();
con.ConnectionString = Configuration.ConfigurationManager.ConnectionStrings("ConnStringHere").ConnectionString;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "INSERT INTO Table_Name (File2) VALUES (#File2)"; //I named the column File2 simply because "File" seemed to be a keyword in SQLServer
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
SqlParameter File1 = new SqlParameter("#File2", SqlDbType.Image);
MemoryStream ms = new MemoryStream();
using (Bitmap tempImage = new Bitmap(p))
{
tempImage.Save(ms, p.RawFormat);
}
byte[] data = ms.GetBuffer();
if (!isValidImage(data)) //optional, will include code if requested.
{
return false;
}
File1.Value = data;
cmd.Parameters.Add(File1);
con.Open();
int result = cmd.ExecuteNonQuery();
if (result > 0)
{
// SUCCESS!
con.Close();
return true;
}
else
{
//failure
con.Close();
return false;
}
}
To retrieve an image:
private Bitmap retrieveBitmap()
{
Image image1 = null
if (dt1.Rows.Count > 0)
{
byte[] imageData1 = null;
if (dt1[0].Count > 0)
{
if (!Information.IsDBNull(dt1.CopyToDataTable()[0].Item("File2")))
{
imageData1 = (byte[])dt1.CopyToDataTable()[0].Item("File2");
}
}
if ((imageData1 != null))
{
if (isValidImage(imageData1))
{
using (MemoryStream ms = new MemoryStream(imageData1, 0, imageData1.Length))
{
ms.Write(imageData1, 0, imageData1.Length);
image1 = Image.FromStream(ms, true);
}
return image1;
}
else
{
// "Invalid image on server";
return null;
}
}
}
}
My code may need small formatting changes, please edit whatever has invalid syntax (my C# is a little rusty, and my code was run through a converter).

Categories