I have a bitmap image, which I converted to a JSON file using:
string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Bitmap image);
Content of .json file:
{
"Tag":null,
"PhysicalDimension":{
"IsEmpty":false,
"Width":376,
"Height":221
},
"Size":{
"IsEmpty":false,
"Width":376,
"Height":221
},
"Width":376,
"Height":221,
"HorizontalResolution":96,
"VerticalResolution":96,
"Flags":2,
"RawFormat":{
"Guid":"b96b3caa-0728-11d3-9d7b-0000f81ef32e"
},
"PixelFormat":2498570,
"Palette":{
"Flags":62,
"Entries":[
]
},
"FrameDimensionsList":[
"7462dc86-6180-4c7e-8e3f-ee7333a7a483"
],
"PropertyIdList":[
],
"PropertyItems":[
]
}
Now I tried to deserialize the file in this way:
Bitmap bm = new System.Web.Script.Serialization.JavaScriptSerializer().Deserialize<Bitmap>(json);
But got the error:
System.MissingMethodException: "For the" System.Bitmap "type, the
constructor without parameters is not defined."
Is there another way to deserialize the file or how can I fix this code?
Thanks!
The error of the message is... quite clear on this. If you look at the MSDN documentation for Bitmap, you'll find that it has no empty constructors defined. The JSON deserializer basically creates an new instance of a specified type (using the empty constructor) then fills out the properties. The Bitmap is a bit too complex for that to work. So... you need to work around that.
Bernard Vander Beken already showed you how to read a base64 string containin bitmap data. Here's how you can CREATE it from an existing bitmap:
ImageConverter converter = new ImageConverter();
var bitmapData = Convert.ToBase64String((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
Note that bitmapData, in the example above, is a string which can easily be sent, stored, etc. (so no need to serialize this into JSON).
EDIT:
Please note that given the above, you need to update BOTH your serialization and deserialization code. I.e. to use the deserialization samples provided, you need to send / store a completely different JSON from the one you're currently working with... which won't be a JSON any more.
In fact, your current JSON file doesn't really contain an actual image; it only has some metadata about the image you originally used. So you definitely need to change the code responsible for serialization.
I would also modify the code for deserializing a bitmap ever so slightly (MemoryStream should, in theory, be disposed of properly and setting the position isn't required).
var bytes = Convert.FromBase64String(bitmapData);
Bitmap bitmap;
using (var ms = new MemoryStream(bytes))
bitmap = new Bitmap(Bitmap.FromStream(ms));
Since Bitmap has no default constructor, it cannot be used out of the box for deserialization.
You can try to deserialize the JSON payload to a byte array, then pass it to Bitmap.FromStream via a MemoryStream.
string image = json;
byte[] byteBuffer = Convert.FromBase64String(image);
MemoryStream memoryStream = new MemoryStream(byteBuffer);
memoryStream.Position = 0;
return (Bitmap)Bitmap.FromStream(memoryStream);
Credits to http://ingsharksoft.blogspot.be/2013/07/solution-problem-serializedeserialize.html
Related
I'm working on a C# Windows Form app project where i need to serialize PictureBox with JSON and save it to a file. For some reason JSON is giving me an error when trying to serialize the PictureBox:
"Newtonsoft.Json.JsonSerializationException: 'Self referencing loop detected for property 'Owner' with type 'System.Windows.Forms.PictureBox'. Path 'AccessibilityObject'.'"
I tried to create a new project and use the serializing on a PictureBox and it worked fine. What could possibly give the error on the current project i'm working on?
string dataToSave = JsonConvert.SerializeObject(bagPicture1);
You can serialize the img like this:
var img = this.pictureBox1.Image;
var ms = new MemoryStream();
// any ImageFormat you like, ImageFormat.Bmp for uncompressed
img.Save(ms, ImageFormat.Jpeg);
var serialized = JsonConvert.SerializeObject(ms.ToArray());
Restore the img:
var myBytes = JsonConvert.DeserializeObject<byte[]>(serialized);
var img = Bitmap.FromStream(new MemoryStream(myBytes));
I'm working on a C# Windows Form app project where i need to serialize PictureBox with JSON and save it to a file. For some reason JSON is giving me an error when trying to serialize the PictureBox:
"Newtonsoft.Json.JsonSerializationException: 'Self referencing loop detected for property 'Owner' with type 'System.Windows.Forms.PictureBox'. Path 'AccessibilityObject'.'"
I tried to create a new project and use the serializing on a PictureBox and it worked fine. What could possibly give the error on the current project i'm working on?
string dataToSave = JsonConvert.SerializeObject(bagPicture1);
You can serialize the img like this:
var img = this.pictureBox1.Image;
var ms = new MemoryStream();
// any ImageFormat you like, ImageFormat.Bmp for uncompressed
img.Save(ms, ImageFormat.Jpeg);
var serialized = JsonConvert.SerializeObject(ms.ToArray());
Restore the img:
var myBytes = JsonConvert.DeserializeObject<byte[]>(serialized);
var img = Bitmap.FromStream(new MemoryStream(myBytes));
I am working on an application for IOS in Xamarin. I have a menu in which I request something called "Doublechecks". These doublechecks have a field with the name "Medication". In a previous working copy of the app, I simply used a string to fill this field, but now we had the idea to, instead of filling this medication field with a string, to fill it with an image. One of the tips I got was to convert a taken or chosen image to base64.
In the menu where I make a new doublecheck I have a button that pops up an actionsheet, where you can choose weather you want to pick an image from your PhotoLibrary, or take a new picture with your camera. When you've taken or chosen a picture, I use the following method to encode it to Base64:
var imageToSend = originalImage.AsJPEG (0.23f).GetBase64EncodedString (NSDataBase64EncodingOptions.None);
Where the originalImage is the image I took/chose. Now, when requesting all doublechecks, I use the following to decode it:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
string decoded = System.Text.Encoding.ASCII.GetString (encodedDataAsBytes);
NSData data = NSData.FromString (decoded, NSStringEncoding.ASCIIStringEncoding);
return UIImage.LoadFromData (data);
The method works up until the return. Somehow, the UIImage is not being constructed, and has its value null, even though the 'data' contains the decoded string.
I have searched several threads and fora, but without much avail. Any help would be much appreciated.
Why are you converting the base64 decoded data into a string ?
Since you already have the byte array you should be able to simply do:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
NSData data = NSData.FromArray (encodedDataAsBytes);
return UIImage.LoadFromData (data);
NSData method not always a good solution. You can also try following
var rawData = pixelMap.ToByteArray();
using (var provider = new CGDataProvider(rawData, 0, rawData.Length))
{
using (var colorSpace = CGColorSpace.CreateDeviceRGB())
{
var cgImage = new CGImage(
pixelMap.Width,
pixelMap.Height,
pixelMap.BitsPerComponent,
pixelMap.BytesPerPixel * ByteToBit,
pixelMap.BytesPerPixel * pixelMap.Width,
colorSpace,
CGBitmapFlags.ByteOrderDefault,
provider,
null,
true,
CGColorRenderingIntent.Default
);
return ImageSource.FromStream(() => UIImage.FromImage(cgImage).AsPNG().AsStream());
}
}
Check out my library and samples for more info about both Android and iOS bitmap from/to 2d pixel map.
https://github.com/enginkirmaci/Imaging-Library
I am creating a chat application very basic. I establish the chat with a tcp connection. I often send serialized object through the network stream because it is simplier to program that way. anyways if I have a class person{ public string name{get;set;} } then it will be eassy to serialize that class. when I include a public ImageSource Img {get;set;} I am not able to serialize that class person any more.
the way I serialize is as:
Person p = new Person();
p.name = \\some name
p.Img = \\ some image
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
x.Serialize(connection.stream, p);//here is when the problem comes. I am not able to serialize it if I include an Img
You can't serialize an image to XML, but you can save it to a MemoryStream and encode the binary data to base64.
string ImageToBase64(BitmapSource bitmap)
{
var encoder = new PngBitmapEncoder();
var frame = BitmapFrame.Create(bitmap);
encoder.Frames.Add(frame);
using(var stream = new MemoryStream())
{
encoder.Save(stream);
return Convert.ToBase64String(stream.ToArray());
}
}
BitmapSource Base64ToImage(string base64)
{
byte[] bytes = Convert.FromBase64String(base64);
using(var stream = new MemoryStream(bytes))
{
return BitmapFrame.Create(stream);
}
}
Note that base64 is not very efficient in terms of space... If possible, it would be better to transmit the image in binary form, rather than in XML.
your approach is correct but does not work anymore as soon as the class Person contains any non serializable object like in your case the ImageSource.
If I had to solve it staying close to your solution, I would store the byte[] of the image and parse it back after deserialization to reconstruct the ImageSource.
You can use BinaryFormatter or available encoders like http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.jpegbitmapencoder.aspx from System.Windows.Media.Imaging Namespace. Also see WPF BitmapImage Serialization/Deserialization . If you want to use string (xml) then i think the Base64 is the only way.
Im loading an image from a SQL CE db and then trying to load that into a PictureBox.
I am saving the image like this:
if (ofd.ShowDialog() == DialogResult.OK)
{
picArtwork.ImageLocation = ofd.FileName;
using (System.IO.FileStream fs = new System.IO.FileStream(ofd.FileName, System.IO.FileMode.Open))
{
byte[] imageAsBytes = new byte[fs.Length];
fs.Read(imageAsBytes, 0, imageAsBytes.Length);
thisItem.Artwork = imageAsBytes;
fs.Close();
}
}
and then saving to the Db using LINQ To SQL.
I load the image back like so:
using (FileStream fs = new FileStream(#"C:\Temp\img.jpg", FileMode.CreateNew ,FileAccess.Write ))
{
byte[] img = (byte[])encoding.GetBytes(ThisFilm.Artwork.ToString());
fs.Write(img, 0, img.Length);
}
but am getting an OutOfMemoryException. I have read that this is a slight red herring and that there is probably something wrong with the filetype, but i cant figure what.
Any ideas?
Thanks
picArtwork.Image = System.Drawing.Bitmap.FromFile(#"C:\Temp\img.jpg");
Based on the code you provided it seems like you are treating the image as a string, it might be that data is being lost with the conversion from byte[] to string and string to byte[].
I am not familiar with SQL CE, but if you can you should consider treating the data as a byte[] and not encoding to and from string.
I base my assumption in this line of code
byte[] img = (byte[])encoding.GetBytes(ThisFilm.Artwork.ToString());
The GDI has the bad behavior of throwing an OOM exception whenever it is not capable of understanding a certain image format. Use Irfanview to see what kind of image that really is, it is likely GDI can't handle it.
My advice would be to not use a FileStream to load images unless you need access to the raw bytes. Instead, use the static methods provided in Bitmap or Image objects:
Image img = Image.FromFile(#"c:\temp\img.jpg")
Bitmap bmp = Bitmap.FromFile(#"c:\temp\img.jpg")
To save the file use .Save method of the Image or Bitmap object:
img.Save(#"c:\temp\img.jpg")
bmp.Save(#"c:\temp\img.jpg")
Of course we don't know what type ArtWork is. Would you care to share that information with us?