I want if user do not set image for picturebox save empy image in table .
my code is :
byte[] arrImage;
if (picperson.Image != null)
{
//convert image to byte
MemoryStream ms = new MemoryStream();
picperson.Image.Save(ms, picperson.Image.RawFormat);
arrImage = ms.GetBuffer();
ms.Close();
}
else arrImage = null;
objcommand.Parameters.AddWithValue("#picture", arrImage);
when he adds null image, exception occurs on line picperson.Image.Save(ms, picperson.Image.RawFormat);
How to add empty imag to table ?
You can't pass a null value for your image parameter, so a work around would be to send in a zero byte array:
if (picperson.Image != null) {
//convert image to byte
} else {
arrImage = new byte[0];
}
Unfortunately, that will not set the field to null.
To set the field to null would probably be handled best with a separate query, for example:
using (SqlCommand q = new SqlCommand("INSERT INTO M (MyImage) VALUES (null)", cn)
...
which does not use parameters.
As far as reading some of the comments are concerned, it sounds like the image format needs to be specified. Try using the actual format that you want the image saved as:
picperson.Image.Save(ms, ImageFormat.Bmp);
// or
picperson.Image.Save(ms, ImageFormat.Jpeg); // or Png, etc.
Related
I serialize images using the following code:
public static string SerializeImage(Image image)
{
using (MemoryStream memoryStream = new MemoryStream())
{
image.Save(memoryStream, image.RawFormat);
return Convert.ToBase64String(memoryStream.ToArray());
}
}
and deserialize the images by doing the following
public static Image DeserializeImage(string serializedImage)
{
byte[] imageAsBytes = Convert.FromBase64String(serializedImage);
using (MemoryStream memoryStream = new MemoryStream(imageAsBytes, 0, imageAsBytes.Length))
{
memoryStream.Write(imageAsBytes, 0, imageAsBytes.Length);
return Image.FromStream(memoryStream, true);
}
}
If I have an image and does
string serializedImage1 = SerializeImage(image);
Image deserializedImage = DeserializeImage(serializedImage1);
string serializedImage2 = SerializeImage(deserializedImage );
Then
serializedImage1 == serializedImage2;
as expected. But it is not always the case.
If I serialize an image on Process 1, and then redeserialize and reserialize it on Process 2, then the result of the reserialization on Process 2 is not the same as on the Process 1. Everything works, but a few bytes in the beginning of the serialization are different.
Worst, if I do the same thing on 2 different dll (or thread, I'm not sure), it seems the serialization result is not the same too. Again, the serialization/deserialization works, but a few bytes are different.
The image the first time is loaded with the following function :
public static Image GetImageFromFilePath(string filePath)
{
var uri = new Uri(filePath);
var bitmapImage = new BitmapImage(uri);
bitmapImage.Freeze();
using (var memoryStream = new MemoryStream())
{
var pngBitmapEncoder = new PngBitmapEncoder();
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapImage));
pngBitmapEncoder.Save(memoryStream);
Image image = Image.FromStream(memoryStream);
return image;
}
}
Note however that it happens even if the image is loaded twice with the DeserializeImage() function.
The tests I have done are with ImageFormat.Jpeg and ImageFormat.Png.
First question, why it does this ? I would have expected the result to be always the same, but I suppose some salt is used when doing the Image.Save().
Second question : I want to have a deterministic way to serialize an image, keeping the image format intact. The goal is to save the image in a DB and also to compare serialized images to know if it already exists in the system where this function is used.
Well, I discovered while trying to solve this that a png or jpeg Image object inside C# has some metadata associated to it and doing what I was doing is just not a reliable way to compare images.
The solution I used was derived from this link
https://insertcode.wordpress.com/2014/05/13/compare-content-of-two-files-images-in-c/
So what I do finally is save the images inside the system with the SerializeImage(Image image) function previously described, and when I want to consume it I deserialize it with the DeserializeImage(string serializedImage) function previously described. But when I want to compare images I use the following functions
public static bool ImagesAreEqual(Image image1, Image image2)
{
string image1Base64Bitmap = GetImageAsBase64Bitmap(image1);
string image2Base64Bitmap = GetImageAsBase64Bitmap(image2);
return image1Base64Bitmap.Equals(image2Base64Bitmap);
}
public static string GetImageAsBase64Bitmap(Image image)
{
using (var memoryStream = new MemoryStream())
{
using (var bitmap = new Bitmap(image))
{
bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
}
That convert the image to raw bitmap before comparing them.
This does a perfect job for me in all my needed cases : the formats of the images are saved/restored correctly, and I can compare them between them to check if they are the same without having to bother with the possibly different serialization.
I've read images in and saved them in a database in byte[] format. Later I want to retrieve the images and convert them into Image format. I've written the following method:
private List<Image> ConvertByteArraysToImages(List<byte[]> byteDataList)
{
List<Image> retVal = new List<Image>();
int counter = 0;
foreach (byte[] byteData in byteDataList)
{
// Something is wrong here
MemoryStream memstr = new MemoryStream(byteData);
Image img = Image.FromStream(memstr);
retVal.Add(img);
memstr.Dispose();// Just added this
// This works fine, the images appear in the folder
System.IO.File.WriteAllBytes(String.Format(#"C:\dev\test{0}.png", counter), byteData);
counter++;
}
return retVal;
}
I'm calling this method from an action which adds the images to the ViewBag to use in the view.
public ActionResult ViewTicket(Incident ticket)
{
//Read the ticket via the web API
string serialisedJSON = JsonConvert.SerializeObject(ticket.ID);
string response = TicketUtilities.JSONRequestToAPI(serialisedJSON, "GetSingleIncident");
Incident retVal = JsonConvert.DeserializeObject<Incident>(response);
//Convert byte[] to Image and add to ViewBag
List<Image> ScreenshotImagesFullsize = ConvertByteArraysToImages(retVal.Screenshots);
ViewBag.Add(ScreenshotImagesFullsize); //Error here
return View(retVal);
}
When I try to add the images to the ViewBag I get the following error in the browser:
Cannot perform runtime binding on a null reference
Writing the byte arrays to file produces the correct output but I'm not getting a list of Images in my return value. Hovering over retVal in debug mode shows the following:
I passed in two byte arrays and I see 2 objects in retVal, but I also I see the error: "Cannot evaluate expression because the code of the current method is optimized". Why does this occur?
Update: I disabled JIT optimization and now I can see the following:
I can see that the object has correctly acquired properties such as the height and width but the actual data is null.
Do not dispose the stream and do keep at least one reference to it as long as you need the image.
"You must keep the stream open for the lifetime of the Image."
https://msdn.microsoft.com/de-de/library/1kcb3wy4(v=vs.110).aspx
Note that there is no need to manually call dispose on a MemoryStream because it does not have unmanaged resources
So I solved this, the problem turned out not to be the conversion but rather adding Image objects to the view. For some reason adding Image objects to the view does not work, to overcome this I converted the image to a Base64 string
using (MemoryStream m = new MemoryStream())
{
retVal.Img.Save(m, retVal.Img.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string imreBase64Data = Convert.ToBase64String(imageBytes);
retVal.ImgB64 = string.Format("data:image/png;base64,{0}", imreBase64Data);
}
So I collect a varbinary(MAX) value from a database where an image is stored.
It gets converted to byte[], then the aim is to display this in an image control.
This is where I read from the database
public TemplateData(SqlDataReader dr)
{
initialiseData();
if (dr.HasRows)
{
Logo = (byte[])dr["Logo"];
//Logo = dr["Logo"].ToString();
TemplateId = dr["TemplateId"].ToString();
Comment = dr["Comment"].ToString();
SchemeCode = dr["SchemeCode"].ToString();
Version = dr["Version"].ToString();
}
}
This is where the values are displayed into the corresponding controls
protected void ddSchemeCode_SelectedIndexChanged(object sender, EventArgs e)
{
if (ddSchemeCode.SelectedIndex > 0)
{
// Existing Data to load from database
TemplateData temp = DataClass.ReturnData(ddSchemeCode.SelectedItem.Text);
if (temp != null)
{
txtVersion.Text = temp.Version;
txtComment.Text = temp.Comment;
txtSchemeCode.Text = temp.SchemeCode;
txtTemplateId.Text = temp.TemplateId;
img.Src = temp.Logo;
}
So at the moment I am passing a byte[] into the source of an image control, where it would instead like a string. I've tried converting it to a string with Convert.ToBase64String(Logo) and ToString(Logo) but these do not work.
Any help is greatly appreciated. Cheers guys and gals.
Try converting the byte array to image and assign it to picturebox as below,
try
{
using (MemoryStream mStream = new MemoryStream())
{
// where pData is your byte array
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Image originalImage = Image.FromStream(mStream);
picBox.Image = originalImage;
}
}
catch (Exception ex)
{
}
Hope it helps.
As you may have noticed, you cannot "print" an image in a webpage. You need to get a little bit creative now.
What you want to look into is Response.BinaryWrite. More information about that, here: https://msdn.microsoft.com/en-us/library/system.web.httpresponse.binarywrite%28v=vs.110%29.aspx
You will probably also need a generic ashx handler. Here is an example of how to show a picture using a handler: http://www.dotnetperls.com/ashx
My suggestion would be to store the logo as a byte[] into the http session. Put the source of the image to theHttpHandlerYourGonnaCreate.ashx. You can then binary write the byte[] you've stored into the session there.
Hope this helps!
As Michael shows here, you can convert the byte array to a Bitmap object with something like this:
Bitmap bitmap = null;
using (MemoryStream imageStream = new MemoryStream(imageData))
{
bitmap = new Bitmap(imageStream);
}
It isn't entirely clear what you're using for a control to show the image, but any control that can display an image should be able to take a Bitmap or Image object.
I have a program to select an image and to set that selected image in a picture box then convert the image in the image box to byte array and save sql server data base in a image type column.
In browse button click event I'm selecting the image file like this.
OpenFileDialog fop = new OpenFileDialog();
fop.InitialDirectory = #"Desktop";
fop.Filter = "image files|*.jpg;*.png;*.gif";
if (fop.ShowDialog() == DialogResult.OK)
{
FileStream FS = new FileStream(#fop.FileName, FileMode.Open, FileAccess.Read);
pbPartySymbol.Image = new Bitmap(fop.FileName);
MessageBox.Show("Image Imported Successfully!!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
After selecting the image and setting it the picture box image I'm converting the picture box image to byte array in the save button click event and saving the byte array to database.
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
I'm calling the method like this.
byte[] myArr1 = imageToByteArray(pbPartySymbol.Image);
and I'm passing this byte array to the data base. and it saves too. But ALL the added images are saved as like this.* 0x53797374656D2E427974655B5D* Saved images cannot be get back to the picture box in the reading operation. What am I doing wrong in the SAVING?
Here's what I do in saving operation in the form.
Party ptObj = new Party(myArr1);
if (new PartyOP().saveParty(ptObj))
{
MessageBox.Show("NEW data added");
}
In my business operation layer this is my code.
public Boolean saveParty(Party ptObj)
{
string query1 = "EXEC insertToParty'" + ptObj.PTSymARR + "'";
return (new DataAccessLayer().executeNonQueries(query1));
}
Here's how I have set the property in the Party class.
class Party
{
public Party() { }
public Party(byte[] ptSym)
{
this._PTSymARR = ptSym;
}
public byte[] PTSymARR
{
get { return _PTSymARR; }
set { _PTSymARR = value; }
}
}
here's my stored procedure.
CREATE PROCEDURE insertToParty
(
#ptSymbol image
)
AS
BEGIN
BEGIN TRANSACTION
SET NOCOUNT ON;
--Query
INSERT INTO Party(PTSYM)
VALUES (#ptSymbol);
Data type of PTSYM is image data type.
That Hex string tranlates to System.Byte[].
You add the Byte-Array to the string starting with EXEC insertToParty so .Net assumes you want a string representation of that variable. Unless specified it calls .ToString wich gives you .... "System.Byte[]".
Edit: Your stored procedure does not use hex encoding on insert. image data shows in hex when viewed in SQL Studio etc.
If you would encode your byte array to a string using base64 or hex when inserting and decode that when you read the data you only had to worry about the increased storage, but I recommend that you change your db acces from a dynamic SELECT to a prepared statement with parameters:
SqlCommand command = new SqlCommand("Exec InsertToParty(#blob)");
command.Parameters.AddWithValue("#blob", ptObj.PTSymARR);
command.ExecuteNonQuery();
I have a Method as follows in one of my projects that retuns byte[] if my pictureboxstupic contains an image.
while I want to convert it in such a way that if there is no picture in pictureboxstupic it should return string = "NULL" else it should return bute[].
how can I do that??
private byte[] GetPic()
{
using (var stream = new MemoryStream())
{
var bmp = new Bitmap(pictureboxstupic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
}
Note:
The column in which I am inserting image is as follows
CREATE TABLE [dbo].[Students]
([Photo] [image] NULL)
and in my current condition I'm inserting the image in my above mentioned columns i.e Students.Photo like this
if (pictureboxstupic.Image == null)
{
cmd.Parameters.Add("#Photo", SqlDbType.VarChar).Value = "NULL";
}
else
{
cmd.Parameters.Add("#Photo", SqlDbType.Image).Value = GetPic();
}
You may always return object and cast it to type you expect - but it is not a good idea. It would be better if you just check if pictureboxstupic is empty before calling your method and then execute proper logic (e.g. assigning "NULL").
You may also apply similar semantic to TryParse - that is you may return bool that would answer if pictureboxstupic wasn't empty and return byte array as an out parameter.
#empi's answer is the right one, and I'd like to expand on it:
Methods and functions should have a tightly defined set of responsibilities. In the case of your GetPic method, it's to get an image's byte stream. That should be the extent of the logic encapsulated in that method.
Displaying the word "NULL" in some error-box is not GetPic's responsibility. It's the responsibility of whomever calls it and is in charge of displaying the image or the error message. That's why I think GetPic should just return null if it's a reasonable condition to receive no image, or perhaps even throw an exception if it's a real error condition that breaks the program flow.
What you shouldn't do in any case is return an object that can be either byte[] or string, since that defeats the whole point of a strongly typed environment, and is a great way to introduce bugs later on. If you must return either a byte[] or a string, you can either use the ref/out params as suggested by others, or create a new class called ImageData, or whatever, that contains both the bytes and the error message, which you can use to retrieve either one or the other.
-- EDIT
After your clarification, I'll still stick by my answer. You shouldn't be doing that. Databases support a NULL value that is not the same as the string "NULL". Rather than inserting this string, you should make sure your column is nullable, and insert the null value - DBNull.Value. Your current code will crash, because the Photo column cannot handle VarChar values.
return object instead? Then cast based by first checking the type using the is keyword.
if(returnedType is string) //or use as and then check for NULL
{
}
else //type is byte[]
{
}
Not sure about your use case and whether it is valid or not, but this can be a solution
You can make it by three solutions:
1.) Use object as return type
2.) Use 'ref' and 'out' parameter specifiers to return array and make method return type string for returning status message.
3.) Use 'unsafe' code for pointers...
Example:
public string GetPic(out byte[] ret)
{
if (Image == null)
return "NULL";
//set ret's value as image bytes
return "ok";
}
You can do it like:
//call the method:
string str = ""; //variable that will be changed accordingly by returned value
byte[] image = GetPic();
if (image.Length == 0)
{
//do what ever you want, like string = "NULL":
str = "NULL";
}
//
//
private byte[] GetPic()
{
PictureBox pictureboxstupic = new PictureBox();
using (var stream = new MemoryStream())
{
var bmp = new Bitmap(pictureboxstupic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
}
I solved my problem like this
Method:
private object GetPic()
{
if(pictureboxstupic.Image == null)
{
return null;
}
using (var stream = new MemoryStream())
{
var bmp = new Bitmap(pictureboxstupic.Image);
bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Jpeg);
stream.Position = 0;
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
}
usage:
cmd.Parameters.Add("#Photo", SqlDbType.Image).Value = GetPic() ?? DBNull.Value;