I'm migrating to c# from VFP and need help with FileToStr(path), actually we have thousands of files stored into a database with this function, and for now we want to maintain compatibility with VFP.
FileToStr() help at VFP help library doesn't say anything about what kind of Encoding perform with the file just
FILETOSTR(cFileName) = Returns the contents of a file as a character string.
For now this is a Black Box. I have two questions:
There is a c# function that perform the same task as VFP FileToStr()?
What Kind of encoding perform FileToStr() to the file?
Actually I have this function to convert the file:
public async Task<string> ImageToStrAsync(string path)
{
string BitmapToImage = await Task.Factory.StartNew(() =>
{
Bitmap bm = new Bitmap(path);
TypeConverter cv = TypeDescriptor.GetConverter(typeof(Bitmap));
return Convert.ToBase64String(
(byte[])cv.ConvertTo(bm, typeof(byte[]))
);
});
return BitmapToImage;
}
Another had previously answered and then deleted it... Don't know why.
What you are looking for is...
string fileContent = System.IO.File.ReadAllText( someFileNameVariable );
OR
string fileContent = System.IO.File.ReadAllText( someFileNameVariable, System.Text.Encoding.UTF8 );
(or other encoding option... ASCII, UTF7, etc as enumerated option).
As for binary, such as for image files..
byte[] binaryContent = System.IO.File.ReadAllBytes( someBinaryFileName );
And to get a byte[] array that you have stored, such as a bitmap image into an actual image object, you could do the following.
BitmapImage yourBmp = new BitmapImage();
using (var ms = new System.IO.MemoryStream(binaryContent))
{
yourBmp.BeginInit();
yourBmp.CacheOption = BitmapCacheOption.OnLoad;
yourBmp.StreamSource = ms;
yourBmp.EndInit();
}
And converting a byte array to a string...
string result = System.Text.Encoding.UTF8.GetString(byteArray)
Related
I have an API which reads an uploaded Image and changes it to a byte[], however in the database the field for where I have to save the image is a string instead of varbinary(MAX), and I cannot change the field type of the database.
I thought about converting the image to base64 and then storing it but this might cause unnecessary strain on the database.
I have found online the following way but this method can be inconsistent based on the server as the encoding might change:
var str = System.Text.Encoding.Default.GetString(result);
And if I were to use the above method I would need to know what type of encoding does ReadBytes use.
Below is my code:
byte[] fileData = null;
using (var binaryReader = new BinaryReader(image.InputStream))
{
binaryReader.BaseStream.Position = 0;
fileData = binaryReader.ReadBytes(image.ContentLength);
}
Furthermore, when I converted the image to a base64 and viewed it, only half the image was visible:
var base64String = Convert.ToBase64String(fileData);
use Convert.toBase64String() method or just using MemoryStream class->
// 1.toBase64String()
string str = Convert.ToBase64String(bytes);
// 2.MemoryStream class
using (MemoryStream stream = new MemoryStream(bytes))
using (StreamReader streamReader = new StreamReader(stream))
{
return streamReader.ReadToEnd();
}
Initialize the BinaryReader with this overload that specifies the encoding.
var binaryReader = new BinaryReader(System.IO.Stream input, System.Text.Encoding encoding);
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'm doing a C# web service soap receiving an image.
I send a string contain the byte characters.
I transform the string in byte[] and next I world like to create the Bitmap.
The line Bitmap img = new Bitmap(ms); generate an exception : invalid argument.
I have a in the ms object this error : System.InvalidOperationException
value contain the correct string, imgBytes contain the good number of sell.
public string GetImage(string value)
{
byte[] imgBytes = Encoding.ASCII.GetBytes(value);
MemoryStream ms = new MemoryStream(imgBytes, true);
Bitmap img = new Bitmap(ms);
Code with debug mode
Exception
Thank you for your help.
It looks like your string holds base64 encoded data. Try to decode it to a byte array via Convert.FromBase64String
I had a similar problem. Basically you write into your memory stream (in the constructor) and the position pointer is at the end. So before reuse the memory stream you can try setting its position pointer to the beginning. Like this:
MemoryStream ms = new MemoryStream(imgBytes, true);
ms.Position = 0;
Bitmap img = new Bitmap(ms);
or the more general approach:
MemoryStream ms = new MemoryStream(imgBytes, true);
ms.Seek(0, SeekOrigin.Begin);
Bitmap img = new Bitmap(ms);
Hope this will solve your Problem.
Update
I think #heinbeinz answer is also important: First decode your string from the right encoding (normally base64), then set the position.
I would need to take a screenshot, if easy to without saving it. I would sent the image data directly to a PHP script. Because I don't have this PHP script at the moment, so I search for the easiest way of format in which I should convert the screenshot data. For debugging reasons until I've got my PHP script I would like to convert a picture of these data on my client side using C#.
My code at the moment for taking a screenshot and convert it (I'm not sure if I can convert the output in my logfile back into a picture):
internal static byte[] ImageToByteArray(Image img)
{
byte[] byteArray = new byte[0];
MemoryStream stream = new MemoryStream();
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Close();
byteArray = stream.ToArray();
return byteArray;
}
public static string TakeScreenshot()
{
String filepath = #"C:\log2.txt";
Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
graphics.Dispose();
bitmap.Save("C:\\temp.png");
Image img = (Image)bitmap;
string str = System.Text.Encoding.Default.GetString(ImageToByteArray(img));
System.IO.File.AppendAllText(filepath, str);
//just for debugging
return "OH";
}
Main question at the moment, is there any way to get a picture back from my converted code (log2.txt).
This line of code:
string str = System.Text.Encoding.Default.GetString(ImageToByteArray(img));
Will almost certainly not do what you want it to do. It will try to interpret your byte array as a string in whatever is the default character encoding on your machine. If the default is something like UTF-8 or any multibyte character set, then it's quite likely to fail. Even if the default encoding is a single-byte character set, it could create a string that can't be reliably turned back into the original byte array.
If you really want to store the byte array as text, you can call Convert.ToBase64String:
string str = Convert.ToBase64String(ImageToByteArray(img));
If you read that string back from the file into str, you can rebuild the byte array with:
byte[] imageBytes = Convert.FromBase64String(str);
Another advantage in your particular case is that there are PHP functions for dealing with base 64 strings.
My MVC app creates images at runtime that I do NOT need to save on the disk.
What's the best way to send those to the requesting browser?
Note that the images will never be the same, so there is no reason to save them on disk first.
The server will draw the random image and will return the image to the calling client. I'm trying to understand what the best format for this type of operation is (bitmap, image ...) so that the streaming back to the server is as smooth and as fast as possible.
If you are sending them in the same page where you create it, then you can modify your Response to send it directly.
//After having your bitmap created...
MemoryStream ms = new MemoryStream();
bmp.Save(ms, ImageFormat.PNG);
bmp.Dispose();
byte[] data = ms.ToArray();
Response.ContentType = "image/png";
Response.ContentLength = data.Length;
using(var str = Response.GetResponseStream())
str.Write(data, 0, data.Length);
Response.End();
If you can get the bytes of the bitmap, then it's easy to return it to the client
public ActionResult GetImage()
{
byte[] byteArray = MagicMethodToGetImageData();
return new FileContentResult(byteArray, "image/jpeg");
}
Moreover, if you want to return the image plus some data, you can encode the bytes as base64 and wrap it in a JSON like this:
public ActionResult GetImage()
{
byte[] byteArray = MagicMethodToGetImageData();
var results = new
{
Image = Convert.ToBase64String(byteArray),
OtherData = "some data"
};
return Json(results);
}
One possibility would be to use the FileContentResult class to read the file content and directly show it or offer to download. A solution could look like this:
private FileContentResult getFileContentResult(string name, bool download = true)
{
if (!string.IsNullOrEmpty(name))
{
// don't forget to set the appropriate image MIME type
var result = new FileContentResult(System.IO.File.ReadAllBytes(name), "image/png");
if (download)
{
result.FileDownloadName = Server.UrlEncode(name);
}
return result;
}
return null;
}
The use this method in some Action like this:
public ActionResult GetImage(string name)
{
return getFileContentResult(name, true);
// or use the image directly for example in a HTML img tag
// return getFileContentResult(name);
}
The class is pretty robust and fast - I have made good experience using it for exactly the same purpose.