I'm having trouble creating an Image/Bitmap object in C# from a base64 encoded byte array.
Here's what I'm dealing with:
I have a frontend where a user can crop an image. When the user selects an image via an input[type=file]
, my javascript code uses HTML5's FileReader to save the DataUrl
(base64 string) to a hidden field
, that is posted along with the crop coordinates and dimensions, and everything else in that form
.
The essence:
base64 data, if you want to test yourself:
http://kristianbak.com/test_image.txt
- base64 string is posted to the action, and received as the parameter
imageData
- the action converts the string to a base64 byte array, like this:
byte[] imageBytes = Convert.FromBase64String(imageData.EncodeTo64());
EncodeTo64 extension method:
public static string EncodeTo64(this String toEncode)
{
var toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode);
var returnValue = Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
After the base64 string is converted to a byte array, I read the bytes into the memory using a MemoryStream
:
using (var imageStream = new MemoryStream(imageBytes, false))
{
Image image = Image.FromStream(imageStream); //ArgumentException: Parameter is not valid.
}
I have also tried the following variations:
a)
using (var imageStream = new MemoryStream(imageBytes))
{
Bitmap image = new Bitmap(imageStream); //ArgumentException: Parameter is not valid.
}
b)
using (var imageStream = new MemoryStream(imageBytes))
{
imageStream.Position = 0;
Image image = Image.FromStream(imageStream); //ArgumentException: Parameter is not valid.
}
c)
TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(Bitmap));
Bitmap image = (Bitmap)typeConverter.ConvertFrom(imageBytes);
d)
Using this method:
private Bitmap GetBitmap(byte[] buf)
{
Int16 width = BitConverter.ToInt16(buf, 18);
Int16 height = BitConverter.ToInt16(buf, 22);
Bitmap bitmap = new Bitmap(width, height); //ArgumentException: Parameter is not valid.
int imageSize = width * height * 4;
int headerSize = BitConverter.ToInt16(buf, 10);
System.Diagnostics.Debug.Assert(imageSize == buf.Length - headerSize);
int offset = headerSize;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
bitmap.SetPixel(x, height - y - 1, Color.FromArgb(buf[offset + 3], buf[offset], buf[offset + 1], buf[offset + 2]));
offset += 4;
}
}
return bitmap;
}
Conclusion:
I feel that there's something else wrong, and I hope you can answer to this question.
Edit:
Sample of the frontend code:
<script>
$(function() {
var reader = new window.FileReader();
function readImage(file, callBack) {
reader.onload = function (e) {
var image = new Image();
image.onload = function (imageEvt) {
if (typeof callBack == "function") {
callBack(e.target.result);
}
};
image.src = e.target.result;
};
reader.readAsDataURL(file);
}
$j('#file').change(function (e) {
var file = e.target.files[0];
readImage(file, function(imageData) {
$('#imageData').val(imageData);
});
});
});
</script>
@using (Html.BeginForm("UploadImage", "Images", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.ValidationSummary(true)
<input name="PostedImage.ImageData" type="hidden" id="imageData" value="" />
@* REST OF THE HTML CODE HERE *@
<p>Choose an image:</p>
<input type="file" name="file" id="file" />
<input type="submit" value="Upload" />
}
Sample of the Controller / Action:
[HttpPost]
public ActionResult Opret(PostedImage postedImage)
{
String imageData = PostedImage.ImageData;
byte[] imageBytes = Convert.FromBase64String(imageData.EncodeTo64());
using (var imageStream = new MemoryStream(imageBytes, false))
{
Image image = Image.FromStream(imageStream);
}
}
I think your problem is that you are taking a base64 string that was posted to your controller , treating it like ASCII, and then converting it to base64 again.
I think you need to change this line
to
from there your bytes should be correct and you should be able to create your image
--Edit--
I took the sample data you provided in the text document and parsed it before loading it into a Bitmap. I was able to save the image to my hard drive and was greeted by a Spartan (Go Green!!)
Give this code a try and see what happens.
Please note imageData is exactly what's exposed on http://kristianbak.com/test_image.txt. I would have provided the initialization, but it's a pretty big string and would probably break things.