paraJdox1
paraJdox1

Reputation: 993

Why is my image (from database) not displaying properly in my pictureBox?

I save my image like this:

//This is in my ImageConverter class:
public static byte[] ConvertImageToByteArray(Image userImage) //Get bytes of the image
{
    using (MemoryStream ms = new MemoryStream())
    using (Bitmap tempImage = new Bitmap(userImage))
    {        
        tempImage.Save(ms, userImage.RawFormat);
        return ms.ToArray();
    }
}       

//this is in my save button:
sqlCmd.Parameters.Add("@user_image", SqlDbType.VarBinary, 8000).Value = 
    ImageConverter.ConvertImageToByteArray(pictureBox1.Image);

I retrieve my image by clicking on the datagridview like this:

private void dgvEmpDetails_CellClick(object sender, DataGridViewCellEventArgs e)
{
    try
    {
        if (e.RowIndex != -1)
        {
            //Display user image
            using (SqlConnection con = new SqlConnection(connectionStringConfig))
            using (SqlCommand sqlCmd = new SqlCommand(
                "SELECT user_image FROM dbo.Employee_Image 
                 WHERE employee_id=@employee_id", con))
            {
                con.Open();
                sqlCmd.Parameters.Add("@employee_id", 
                    SqlDbType.NVarChar).Value = EmployeeId;

                using (SqlDataReader reader = sqlCmd.ExecuteReader())
                {
                    if (reader.HasRows)
                    {
                        reader.Read();
                        pictureBox1.Image = ImageConverter.
                            ConvertByteArrayToImage((byte[])(reader.GetValue(0)));
                    }
                    else
                    {
                        pictureBox1.Image = null;
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show($"Something is wrong with the selected record! 
            \nError: { ex.Message  }");
    }
}       

//This is in my ImageConverter class:
public static Image ConvertByteArrayToImage(byte[] buffer) //Get image from database
{
    using (MemoryStream ms = new MemoryStream(buffer))
    {
        return Image.FromStream(ms);
    }
}      

NOTE: I don't display my image's binary data in my datagridview.

Saving and updating the image (with the users records) works fine.

After saving an image to the database, it does not display properly. But when I load it using OpenFileDialog the image displays just fine.

Loading the image using OpenFileDialog:

enter image description here

When I click a datagridview row to view a user record this is what the pictureBox looks like:

enter image description here

Why is this split in some sort? I have not seen any similar problem/solution about this. Most of them is about "Loading image from the database to pictureBox". But I have already done that.

Upvotes: 1

Views: 1196

Answers (3)

Sayed M. Idrees
Sayed M. Idrees

Reputation: 1408

This is my approach for getting images from database

// This method use to update the form.
private void loadFormWithID(int ID)
{
    dbServer conn = new dbServer(sysController.getConn);
    DataTable tbl = conn.getQueryList("SELECT * FROM Products WHERE ID = " + ID);
    DataRow row = tbl.Rows[0];      
    // This is how i update the Picture Box
    pictureBoxItem.Image = row["Image"] == DBNull.Value ? pictureBoxItem.InitialImage : ImageController.bytesToImage((byte[])row["Image"]);  
 }

This is my dbserver class which communicates with database.

public class dbServer
{
    public string _connectionLink;

    public dbServer(string connectionString)
    {
        _connectionLink = connectionString; 
    }

    public DataTable getQueryList(string sqlQuery)
    {
         DataTable tbl = new DataTable();

       using (SqlConnection conn = new SqlConnection(_connectionLink))
       {
           using (SqlCommand cmd = new SqlCommand(sqlQuery, conn))
            {
               conn.Open();
               SqlDataReader reader = cmd.ExecuteReader();
               tbl.Load(reader);
            }
        }
        return tbl;
    }
}

This is what I used for my database image retriever.

class ImageController
{
    public static byte[] ImageToBytes(PictureBox pb)
    {
        MemoryStream ms = new MemoryStream();
        pb.Image.Save(ms, pb.Image.RawFormat);
        return ms.GetBuffer();
    }

    public static byte[] ImageToBytes(Image pb)
    {
        MemoryStream ms = new MemoryStream();
        pb.Save(ms, pb.RawFormat);
        Console.WriteLine(ms.Length);
        return ms.GetBuffer();
    } 

    public static Image bytesToImage(byte[] imageRaw)
    {
        MemoryStream ms = new MemoryStream(imageRaw);
        return Image.FromStream(ms);
    }
}

Upvotes: 0

It all makes cents
It all makes cents

Reputation: 5009

Here's a complete solution, which seems to work with SQL Server Express/SQL Server:

Note: When the table in the database is created, column User_Image should be created as varbinary(MAX)

Read image from file and return as byte[]:

Note: I've included 3 different ways to read an image file and return a byte[]. GetImageFromFile seems to produce a byte array that has the same number of bytes as the original (tested with .jpg), whereas, GetImageFromFilev2 and GetImageFromFilev3, have fewer bytes. See How to convert image to byte array for more information.

public static byte[] GetImageFromFile(string filename)
{
    byte[] rawData = null;

    try
    {
        if (!String.IsNullOrEmpty(filename) && System.IO.File.Exists(filename))
        {
            using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
            {
                //get length of file - in bytes
                int fileLength = (int)fs.Length;

                //create new byte array
                rawData = new byte[fileLength];

                //read data into byte array (rawData)
                fs.Read(rawData, 0, fileLength);
                fs.Flush();

                Debug.WriteLine("rawData.Length: " + rawData.Length);
            }
        }
    }
    catch (Exception ex)
    {
        //ToDo: log message
        throw ex;
    }

    return rawData;
}

public static byte[] GetImageFromFilev2(string filename)
{
    byte[] rawData = null;

    try
    {
        if (!String.IsNullOrEmpty(filename) && System.IO.File.Exists(filename))
        {
            using (Image image = Image.FromFile(filename))
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    image.Save(ms, image.RawFormat);
                    rawData = ms.ToArray();
                }
            }
        }
    }
    catch (Exception ex)
    {
        //ToDo: log message
        throw ex;
    }

    return rawData;
}

public static byte[] GetImageFromFilev3(string filename)
{
    byte[] rawData = null;

    try
    {
        if (!String.IsNullOrEmpty(filename) && System.IO.File.Exists(filename))
        {
            using (Image image = Image.FromFile(filename))
            {
                ImageConverter ic = new ImageConverter();

                rawData = (byte[])ic.ConvertTo(image, typeof(byte[]));
                Debug.WriteLine("rawData.Length: " + rawData.Length);
            }   
        }
    }
    catch (Exception ex)
    {
        //ToDo: log message
        throw ex;
    }

    return rawData;
}

Read image data from database:

public static System.Drawing.Bitmap GetImageFromTblEmployeeImageBitmap(string employee_id)
{
    System.Drawing.Bitmap image = null;
    byte[] imageData = GetImageFromTblEmployeeImageByte(employee_id);

    //convert to Bitmap
    if (imageData != null)
    {
        using (System.IO.MemoryStream ms = new System.IO.MemoryStream(imageData))
        {
            image = new System.Drawing.Bitmap(ms);
            ms.Flush();
        }
    }

    return image;
}

public static byte[] GetImageFromTblEmployeeImageByte(string employee_id)
{ 
    byte[] imageData = null;

    try
    {
        using (SqlConnection cn = new SqlConnection(ConnectStr))
        {
            string sqlText = "Select user_image from Employee_Image where employee_id = @employee_id";

            //open connection to db
            cn.Open();

            using (SqlCommand cmd = new SqlCommand(sqlText, cn))
            {
                cmd.Parameters.Add("@employee_id", SqlDbType.NVarChar).Value = employee_id;

                //execute
                SqlDataReader dr1 = cmd.ExecuteReader();

                bool result = dr1.Read();

                if (result)
                {
                    imageData = (byte[])dr1["User_Image"];
                }

                Debug.WriteLine("result: " + result);
            }
        }
    }
    catch (SqlException ex)
    {
        //ToDo: log message
        throw ex;
    }
    catch (Exception ex)
    {
        //ToDo: log message
        throw ex;
    }

    return imageData;
}

Save image data to database

public static string SaveImageToTblEmployeeImage(string employee_id, string filename)
{
    return SaveImageToTblEmployeeImage(employee_id, GetImageFromFile(filename));
}

public static string SaveImageToTblEmployeeImage(string employee_id, byte[] user_image)
{
    string status = string.Empty;

    using (SqlConnection cn = new SqlConnection(ConnectStr))
    {
        string sqlText = "INSERT INTO Employee_Image(Employee_Id, User_Image) VALUES (@employee_id, @user_image)";

        //open connection to db
        cn.Open();

        using (SqlCommand cmd = new SqlCommand(sqlText, cn))
        {
            //add parameters
            cmd.Parameters.Add("@employee_id", System.Data.SqlDbType.NVarChar).Value = employee_id;

            //for varbinary(max) specify size = -1, otherwise there is an 8000 byte limit
            //see https://learn.microsoft.com/en-us/dotnet/api/system.data.sqldbtype?view=netframework-4.8
            cmd.Parameters.Add("@user_image", System.Data.SqlDbType.VarBinary, -1).Value = user_image;

            //execute
            int numRowsAffected = cmd.ExecuteNonQuery();
            status = "Data inserted into table 'Employee_Image'";

            Debug.WriteLine("numRowsAffected: " + numRowsAffected);
        }
    }

    return status;
}

Upload image to database

using (OpenFileDialog ofd = new OpenFileDialog())
{
    ofd.Filter = "Image Files (*.bmp;*.gif;*.jpg;*.jpeg;*.png)|*.bmp;*.gif;*.jpg;*.jpeg;*.png|All Files (*.*)|*.*";

    if (ofd.ShowDialog() == DialogResult.OK)
    {
        SaveImageToTblEmployeeImage("12345", ofd.FileName);
    }
}

To display image in PictureBox (ex: pictureBox1)

Bitmap image = GetImageFromTblEmployeeImageBitmap("12345");

if (image != null)
{
    pictureBox1.Image = image;
    pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage; //fit to size
    pictureBox1.Refresh();

}

Resources:

Upvotes: 0

AwiringCameron
AwiringCameron

Reputation: 640

Try using the MemoryStream.Write method.

Change this:

//This is in my ImageConverter class:
public static Image ConvertByteArrayToImage(byte[] buffer) //Get image from database
{
    using (MemoryStream ms = new MemoryStream(buffer))
    {
        return Image.FromStream(ms);
    }
} 

to this:

//This is in my ImageConverter class:
public static Image ConvertByteArrayToImage(byte[] buffer) //Get image from database
{
    using (MemoryStream ms = new MemoryStream)
    {
        ms.Write(buffer.ToArray(), 0, buffer.Length);
        return Image.FromStream(ms);
    }
} 

Upvotes: 0

Related Questions