Due to some datastorage limitations (noSQL) I need to store images as strings. How can I serialize the image Bitmap to string and back. Here is how I am doing it:
Uri testImageUri = new Uri("/DictionaryBasedVM;component/test.jpg", UriKind.Relative);
StreamResourceInfo sri = Application.GetResourceStream(testImageUri);
var stringData = GetString(sri.Stream);
ImageSource = stringData;
Where
ImageControlis just a silverlight image control defined in xaml. I am using the following utility functions:
//For testing
public static string GetString(Stream stream)
{
byte[] byteArray = ReadFully(stream);
return Encoding.Unicode.GetString(byteArray,0,byteArray.Length);
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
And the following property:
private string _开发者_JAVA百科ImageSource = "";
public string ImageSource
{
set
{
_ImageSource = value;
byte[] byteArray = Encoding.Unicode.GetBytes(value);
MemoryStream imageStream = new MemoryStream(byteArray);
BitmapImage imageSource = new BitmapImage();
imageSource.SetSource(imageStream);
ImageControl.Source = imageSource;
}
get
{
return _ImageSource;
}
}
I get the error : "Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))" as shown:
Even if I don't store it as a string I am still curious why I can't do this.
Unicode is probably not the best encoding for this purpose. You'd be better of Base64 encoding the byte[]
and storing that.
Base64 would add 30% size to the string. I don't think it's necessary here. You can safely "cast" bytes to chars and vice versa for this particular binary need, as long as you don't do anything with the string. Here is some code that seems to work:
// usage example
string encoded = FileToString("myimage.png");
Console.WriteLine(s.Length);
FileFromString(encoded, "copy.png");
public static void FileFromString(string input, string filePath)
{
if (input == null)
throw new ArgumentNullException("input");
if (filePath == null)
throw new ArgumentNullException("filePath");
using (FileStream stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))
{
byte[] buffer = FromString(input);
stream.Write(buffer, 0, buffer.Length);
}
}
public static byte[] FromString(string input)
{
if (input == null)
throw new ArgumentNullException("input");
char[] cbuffer = input.ToCharArray();
byte[] buffer = new byte[cbuffer.Length];
for (int i = 0; i < buffer.Length; i++)
{
buffer[i] = (byte)cbuffer[i];
}
return buffer;
}
public static string FileToString(string filePath)
{
if (filePath == null)
throw new ArgumentNullException("filePath");
using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Write))
{
return ToString(stream);
}
}
public static string ToString(Stream input)
{
if (input == null)
throw new ArgumentNullException("input");
StringBuilder sb = new StringBuilder();
byte[] buffer = new byte[4096];
char[] cbuffer = new char[4096];
int read;
do
{
read = input.Read(buffer, 0, buffer.Length);
for (int i = 0; i < read; i++)
{
cbuffer[i] = (char)buffer[i];
}
sb.Append(new string(cbuffer, 0, read));
}
while (read > 0);
return sb.ToString();
}
However, it's possible the system where you store strings may not like strings that contains the 0 or other special numbers. In this case, base64 is still an option.
Have you tried using Convert.ToBase64String and Convert.FromBase64String methods instead? I'd guess the unicode GetString/GetBytes don't work, as your byte arrays don't line up with 'known characters'.
精彩评论