I have WriteableBitmap. I know that in variable wp1 exists image, because I saved this picture, and it was all fine. I need to encode the image into a byte[] array.
WriteableBitmap wp1 = new WriteableBitmap(1, 1); ;
wp1.SetSourceAsync(memStream);
using (Stream stream = wp1.PixelBuffer.AsStream())
{
if (stream.CanWrite)
{
byte[] pixelArray = new byte[stream.Length];
await stream.ReadAsync(pixelArray, 0, pixelArray.Length);
}
}
After all the pixelArray is empty. Length of the array pixelArray equals to the length of stream, but all bytes are zero. What should I do?
I think your problem is this line of code:
wp1.SetSourceAsync(memStream);
That's an asynchronous method, so you'll have to wait until it's done before proceeding. Try changing it to:
await wp1.SetSourceAsync(memStream);
If you're using WriteableBitmap Extensions, there's an easier method that does that for you, something like :var pixelDataArray = wp1.ToByteArray();
Related
I have been trying to convert a captured VideoFrame object to a byte array with little success. It is clear from the documentation that each frame can be saved to a SoftwareBitmap object, e.g.
SoftwareBitmap bitmap = frame.SoftwareBitmap;
I have been able to save this bitmap as an image but I would like to obtain it's data and store it in a byte array. Many SO questions already deal with this but the SoftwareBitmap belongs to the Windows.Graphics.Imaging namespace (not the more typical Xaml.Controls.Image which the other SO posts address, such as this one) so traditional methods like image.Save() are unavailable.
It seems that each SoftwareBitmap has a CopyToBuffer() method but the documentation on this is very terse with regards to how to actually use this. And I'm also not sure if that's the right way to go?
Edit:
Using Alan's recommendation below I've managed to get this working. I'm not sure if it's useful but here's the code I used if anyone else comes across this:
private void convertFrameToByteArray(SoftwareBitmap bitmap)
{
byte[] bytes;
WriteableBitmap newBitmap = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight);
bitmap.CopyToBuffer(newBitmap.PixelBuffer);
using (Stream stream = newBitmap.PixelBuffer.AsStream())
using (MemoryStream memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
bytes = memoryStream.ToArray();
}
// do what you want with the acquired bytes
this.videoFramesAsBytes.Add(bytes);
}
By using the CopyToBuffer() method, you can copy pixel data to the PixelBuffer of a WriteableBitmap.
Then I think you can refer to the answer in this question to convert it to byte array.
For anyone looking to access an encoded byte[] array from the SoftwareBitmap (e.g. jpeg):
private async void PlayWithData(SoftwareBitmap softwareBitmap)
{
var data = await EncodedBytes(softwareBitmap, BitmapEncoder.JpegEncoderId);
// todo: save the bytes to a DB, etc
}
private async Task<byte[]> EncodedBytes(SoftwareBitmap soft, Guid encoderId)
{
byte[] array = null;
// First: Use an encoder to copy from SoftwareBitmap to an in-mem stream (FlushAsync)
// Next: Use ReadAsync on the in-mem stream to get byte[] array
using (var ms = new InMemoryRandomAccessStream())
{
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(encoderId, ms);
encoder.SetSoftwareBitmap(soft);
try
{
await encoder.FlushAsync();
}
catch ( Exception ex ){ return new byte[0]; }
array = new byte[ms.Size];
await ms.ReadAsync(array.AsBuffer(), (uint)ms.Size, InputStreamOptions.None);
}
return array;
}
How can I upload an image properly from Windows Phone where the image source is
a PhotoResult from a PhotoChooserTask? I'm using RestSharp for this, but it only
uploads a big bunch of zeroes to my server.
Here's the code part I have trobule with:
using (MemoryStream memo = new MemoryStream())
{
appGlobal.appData.selectedPhoto.ChosenPhoto.CopyTo(memo);
byte[] imgArray = new byte[appGlobal.appData.selectedPhoto.ChosenPhoto.Length];
memo.Read(imgArray, 0, imgArray.Length);
request.AddFile("image", imgArray, "image", "image/jpeg");
}
I can't seem to figure out how am I supposed to convert PhotoResult.ChosenPhoto (which is a PhotoStream) to a byte array.
Any thoughts?
Ok I found out what the problem was. It seems that when you get the PhotoResult back from
a chooser task let it be PhotoChooserTask or CameraCaptureTask, the stream's position isn't set to 0. So you'll have to set it manually before reading the bytes out from it. Here's the fixed code for my question:
byte[] imgArray = new byte[(int)appGlobal.appData.selectedPhoto.ChosenPhoto.Length];
appGlobal.appData.selectedPhoto.ChosenPhoto.Position = 0;
appGlobal.appData.selectedPhoto.ChosenPhoto.Read(imgArray, 0, (int)appGlobal.appData.selectedPhoto.ChosenPhoto.Length);
appGlobal.appData.selectedPhoto.ChosenPhoto.Seek(0, SeekOrigin.Begin);
request.AddFile("image", imgArray, "image");
Also thanks for the help KooKiz. :)
You're mixing two approaches in your code.
Either directly read the contents of the stream in a byte array:
byte[] imgArray = new byte[appGlobal.appData.selectedPhoto.ChosenPhoto.Length];
appGlobal.appData.selectedPhoto.ChosenPhoto.Read(imgArray, 0, imgArray.Length);
request.AddFile("image", imgArray, "image", "image/jpeg");
Or copy the stream to a MemoryStream then use the ToArray method:
using (MemoryStream memo = new MemoryStream())
{
appGlobal.appData.selectedPhoto.ChosenPhoto.CopyTo(memo);
byte[] imgArray = memo.ToArray();
request.AddFile("image", imgArray, "image", "image/jpeg");
}
I have been trying get a stream from a byte array in metro style app using the following code.
InMemoryRandomAccessStream memoryStream = new InMemoryRandomAccessStream();
memoryStream.AsStreamForWrite().Write(byteArray, 0, byteArray.Length);
memoryStream.Seek(0);
It executes with no errors but stream size is zero (0). Can anybody tell me why is its size is zero?
You can use the DataWriter and DataReader classes. For example ...
// put bytes into the stream
var ms = new InMemoryRandomAccessStream();
var dw = new Windows.Storage.Streams.DataWriter(ms);
dw.WriteBytes(new byte[] { 0x00, 0x01, 0x02 });
await dw.StoreAsync();
// read them out
ms.Seek(0);
byte[] ob = new byte[ms.Size];
var dr = new Windows.Storage.Streams.DataReader(ms);
await dr.LoadAsync((uint)ms.Size);
dr.ReadBytes(ob);
You can also use the BinaryWriter/BinaryReader to read and write from and to byte[] and Streams.
private Stream ConvertToStream(byte[] raw)
{
Stream streamOutput = new MemoryStream();
using (BinaryWriter writer = new BinaryWriter(streamOutput))
{
writer.Write(raw);
}
return streamOutput;
}
Another option is to use built in extension methods as Marc Gravell already mentioned:
private Stream ConvertToStream(byte[] raw)
{
return raw.AsBuffer().AsStream();
}
The extension methods are commented with [Security Critical] which may indicate a later change. However, after looking around a bit I couldn't find any additional information on the security code comment.
I know this is a very old question, but I was running into this issue myself today and figured it out so I'll leave this here for others.
I realized that the stream wasn't being written if it was too small. To fix this, I explicitly set the length of the stream like this:
ms.AsStreamForWrite(imageBytes.Length).Write(imageBytes, 0, imageBytes.Length);
That should be all you need.
I have an android.graphics.bitmap and an android.net.Uri both of these I can use anyway I want. But I don't know how to take the bitmap and turn it into a byte[] I have tried using a Parcel but I can't initialize it, and when I use it in the writetoparcel method for both the bitmap and uri it throws an error.
I tried the bitmaps ToArray method and that does nothing but create an empty array.
I also tried to use the compress method but I cannot initialize a stream. The text editor throws an error about creating a new Stream inside an abstract class.
Is there some reference that I am missing that allows me to do this.
This is what I ended up using to get it into a byte array and resize.
Bitmap thumb;
Android.Net.Uri val;
this.thumb = MediaStore.Images.Media.GetBitmap(this.ContentResolver, this.val);
Bitmap scaledThumb = Bitmap.CreateScaledBitmap(this.thumb, 1600, 1200, true);
MemoryStream stream = new MemoryStream();
scaledThumb.Compress(Bitmap.CompressFormat.Jpeg, 50, stream);
this.byteArr = stream.ToArray();
This is how you do it.
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
My guess is you would want to use:
Android.Graphics.Bitmap.CopyPixelsToBuffer (Java.Nio.Buffer)
or:
Android.Graphics.Bitmap.GetPixels (int[], int, int, int, int, int, int)
I have a function which extracts a file into a byte array (data).
int contentLength = postedFile.ContentLength;
byte[] data = new byte[contentLength];
postedFile.InputStream.Read(data, 0, contentLength);
Later I use this byte array to construct an System.Drawing.Image object
(where data is the byte array)
MemoryStream ms = new MemoryStream(data);
Image bitmap = Image.FromStream(ms);
I get the following exception "ArgumentException: Parameter is not valid."
The original posted file contained a 500k jpeg image...
Any ideas why this isnt working?
Note: I assure you I have a valid reason for converting to a byte array and then to a memorystream!!
That's most likely because you didn't get all the file data into the byte array. The Read method doesn't have to return as many bytes as you request, and it returns the number of bytes actually put in the array. You have to loop until you have gotten all the data:
int contentLength = postedFile.ContentLength;
byte[] data = new byte[contentLength];
for (int pos = 0; pos < contentLength; ) {
pos += postedFile.InputStream.Read(data, pos, contentLength - pos);
}
This is a common mistake when reading from a stream. I have seen this problem a lot of times.
Edit:
With the check for an early end of stream, as Matthew suggested, the code would be:
int contentLength = postedFile.ContentLength;
byte[] data = new byte[contentLength];
for (int pos = 0; pos < contentLength; ) {
int len = postedFile.InputStream.Read(data, pos, contentLength - pos);
if (len == 0) {
throw new ApplicationException("Upload aborted.");
}
pos += len;
}
You're not checking the return value of postedFile.InputStream.Read. It is not at all guaranteed to fill the array on the first call. That will leave a corrupt JPEG in data (0's instead of file content).
Have you checked the return value from the Read() call to verify that is actually reading all of the content? Perhaps Read() is only returning a portion of the stream, requiring you to loop the Read() call until all of the bytes are consumed.
Any reason why you don't simply do this:
Image bitmap = Image.FromStream(postedFile.InputStream);
I have had problems loading images in .NET that were openable by more robust image libraries. It's possible that the specific jpeg image you have is not supported by .NET. jpeg files are not just one type of encoding, there's a variety of possible compression schemes allowed.
You could try it with another image that you know is in a supported format.