I'm desperately trying to save an image to an SQL database and then load it on my WP. All of the guides online say to convert the image to a Byte array, store it and then load it back into an image.
So far, I've been able to save the image into a Byte array using:
public static byte[] ConvertToBytes(Stream photoStream)
{
byte[] a = new Byte[photoStream.Length];
for (int i = 0; i < photoStream.Length; i++)
{
a[i] = (Byte)photoStream.ReadByte();
}
return (a);
}
This generates a Byte array that is similar in size to the image I'm saving.
The suggested way to load images is:
1 public static BitmapImage ConvertToImage(Byte[] inputBytes)
2 {
3 MemoryStream stream = new MemoryStream(inputBytes);
4 BitmapImage image = new BitmapImage();
5 image.SetSource(stream);
6 return (image);
7 }
This doesn't work.
I get this error (on line 5):
"Unspecified error"
Does anybody have any idea how to fix this or can suggest an alternative method/code?
I know there is information online - i can assure you that i have searched long and hard for a working method and been able to make nothing work.
Any help would be much appreciated!
I managed to solve this using:
public static byte[] ConvertToBytes(String imageLocation)
{
StreamResourceInfo sri = Application.GetResourceStream(new Uri(imageLocation, UriKind.RelativeOrAbsolute));
BinaryReader binary = new BinaryReader(sri.Stream);
byte[] imgByteArray = binary.ReadBytes((int)(sri.Stream.Length));
binary.Close();
binary.Dispose();
return imgByteArray;
}
public static WriteableBitmap ConvertToImage(Byte[] inputBytes)
{
MemoryStream ms = new MemoryStream(inputBytes);
WriteableBitmap img = new WriteableBitmap(400, 400);
img.LoadJpeg(ms);
return (img);
}
Thanks for all your help guys.
i used that code
byte[] Arr = Convert.FromBase64String(Im); >> i think you need that steep
Stream memStream = new MemoryStream(Arr);
WriteableBitmap wbimg = PictureDecoder.DecodeJpeg(memStream);
image2.Source = wbimg;
image2.Tag = IlbumID;
if that nat work
try
memStream.Read (Arr ,0, Arr.Length );
Related
Simple Question: I have a Xamarin.Forms.Image called "image". I need it to be a byte array. I feel like this has to be a simple thing but I can't find it on the internet anywhere.
var image = Xamarin.Forms.Image();
image.source = "my_image_source.png";
//Magic code
byte[] imgByteArray = ???
Unfortunately, the Image class does not expose methods to access the actual image once loaded.
You will need to read the Image from the file and convert it to the Stream you are expecting.
To prevent reading the image object twice you can set the stream read to your Image control.
var image = Xamarin.Forms.Image();
var assembly = this.GetType().GetTypeInfo().Assembly;
byte[] imgByteArray = null;
using (var s = assembly.GetManifestResourceStream("my_image_source.png"))
{
if (s != null)
{
var length = s.Length;
imgByteArray = new byte[length];
s.Read(buffer, 0, (int)length);
image.Source = ImageSource.FromStream(() => s);
}
}
// here imageByteArray will have the bytes from the image file or it will be null if the file was not loaded.
if (imgByteArray != null)
{
//use your data here.
}
Hope this helps.-
Update:
This code will require adding your my_image_source.png as part of the PCL as an embedded resource.
I have a Windows 10 UWP app that will run on Windows 10 Mobile. A requirement I have is to capture a signature from the user. So far, I am simply using an InkCanvas in XAML and have it wired up to my code behind.
I then have a button that when clicked, will take the signature on the InkCanvas and send it to the server via a WCF call. The server and WCF service is already existing. It takes in the signature image as a base64 serialized string.
I know how to get the base64 once I have either an image or a byte array. However, in my many hours of reading, I am finding that articles/examples were either written for WPF or Windows 8.1 and do not work on Windows 10 UWP. Also, of the examples that I have found that will work, it seems my only option is to save the signature to file as a GIF.
I see that I can call GetStrokes() like this
var strokeCollection = cvsSignature.InkPresenter.StrokeContainer.GetStrokes();
Which will return me a read only list of InkStroke. I guess I can iterate that list and build a byte array? How would I do that? It seems this is not efficient?
Otherwise, I thought I could just change the stream from a file stream to a memory stream but I guess either this is not possible or I am missing something. I am trying this
using (var inkMemStream = new MemoryStream())
{
await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(inkMemStream);
}
But with this type of approach I get an exception that I cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream
Thanks!
I found a way, if you don't want to save your InkCanvas to a file or as a GIF, to manipulate it in memory. I actually have three options below. Note, for some of this, you will need to add a reference to Win2D.uwp, which can be found on NuGet by searching that exact name. It is provided by Microsoft.
Convert the InkCanvas to a byte array:
private byte[] ConvertInkCanvasToByteArray()
{
//First, we need to get all of the strokes in the canvas
var canvasStrokes = myCanvas.InkPresenter.StrokeContainer.GetStrokes();
//Just as a check, make sure to only do work if there are actually strokes (ie not empty)
if (canvasStrokes.Count > 0)
{
var width = (int)myCanvas.ActualWidth;
var height = (int)myCanvas.ActualHeight;
var device = CanvasDevice.GetSharedDevice();
//Create a new renderTarget with the same width and height as myCanvas at 96dpi
var renderTarget = new CanvasRenderTarget(device, width,
height, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
//This will clear the renderTarget with a clean slate of a white background.
ds.Clear(Windows.UI.Colors.White);
//Here is where we actually take the strokes from the canvas and draw them on the render target.
ds.DrawInk(myCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
//Finally, this will return the render target as a byte array.
return renderTarget.GetPixelBytes();
}
else
{
return null;
}
}
If all you need is a byte array of the pixels, you are done. However, if you now want to generate an image, you use the WriteableBitmap to do so. Here are sync and async methods that can be called to do this.
private WriteableBitmap GetSignatureBitmapFull()
{
var bytes = ConvertInkCanvasToByteArray();
if (bytes != null)
{
var width = (int)cvsSignature.ActualWidth;
var height = (int)cvsSignature.ActualHeight;
var bmp = new WriteableBitmap(width, height);
using (var stream = bmp.PixelBuffer.AsStream())
{
stream.Write(bytes, 0, bytes.Length);
return bmp;
}
}
else
return null;
}
private async Task<WriteableBitmap> GetSignatureBitmapFullAsync()
{
var bytes = ConvertInkCanvasToByteArray();
if (bytes != null)
{
var width = (int)cvsSignature.ActualWidth;
var height = (int)cvsSignature.ActualHeight;
var bmp = new WriteableBitmap(width, height);
using (var stream = bmp.PixelBuffer.AsStream())
{
await stream.WriteAsync(bytes, 0, bytes.Length);
return bmp;
}
}
else
return null;
}
Finally, here is an async method that I am using to be able to do a crop on the bitmap if you want to do that. The key thing with this method is notice how with this approach, you don't have to get the pixel bytes as an array first. You just get the strokes from the canvas and then it is saved directly into a memory stream
private async Task<WriteableBitmap> GetSignatureBitmapCropped()
{
try
{
var canvasStrokes = cvsSignature.InkPresenter.StrokeContainer.GetStrokes();
if (canvasStrokes.Count > 0)
{
var bounds = cvsSignature.InkPresenter.StrokeContainer.BoundingRect;
var xOffset = (uint)Math.Round(bounds.X);
var yOffset = (uint)Math.Round(bounds.Y);
var pixelWidth = (int)Math.Round(bounds.Width);
var pixelHeight = (int)Math.Round(bounds.Height);
using (var memStream = new InMemoryRandomAccessStream())
{
await cvsSignature.InkPresenter.StrokeContainer.SaveAsync(memStream);
var decoder = await BitmapDecoder.CreateAsync(memStream);
var transform = new BitmapTransform();
var newBounds = new BitmapBounds();
newBounds.X = 0;
newBounds.Y = 0;
newBounds.Width = (uint)pixelWidth;
newBounds.Height = (uint)pixelHeight;
transform.Bounds = newBounds;
var pdp = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage);
var pixels = pdp.DetachPixelData();
var cropBmp = new WriteableBitmap(pixelWidth, pixelHeight);
using (var stream = cropBmp.PixelBuffer.AsStream())
{
await stream.WriteAsync(pixels, 0, pixels.Length);
}
return cropBmp;
}
}
else
{
return null;
}
}
catch (Exception ex)
{
return null;
}
}
Hope this helps provide some alternatives when using InkCanvas in Windows 10 Universal.
it seems my only option is to save the signature to file as a GIF.
GIF is not the only choice. The official sample just show GIF, but you can also save the InkStokes collection to JPG and PNG. Code as follows:
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg" ,".gif",".png"});
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
But with this type of approach I get an exception that I cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream
As you see, it cannot convert from System.IO.MemoryStream to Windows.Storage.Streams.IOutputStream directly. You need to read the image file you just saved as ImageSource. As you known how to get the base64 once you have either an image or a byte array. So what we just need is to get an image or a byte array from the image file.
Read the image file as byte array and then a memory stream as follows
if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
{
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Gif,JPG,PNG", new System.Collections.Generic.List<string> { ".jpg", ".gif", ".png" });
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (null != file)
{
using (IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
}
using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read))
{
WriteableBitmap inkimagesource = new WriteableBitmap(50, 50);
inkimagesource.SetSource(streamforread);
byte[] imageBuffer = inkimagesource.PixelBuffer.ToArray();
MemoryStream ms = new MemoryStream(imageBuffer);
}
}
}
Read the file as image source just need to change the file reading code as follows:
using (IRandomAccessStream streamforread = await file.OpenAsync(FileAccessMode.Read)
{
var bitmap = new BitmapImage();
bitmap.SetSource(streamforread);
}
I guess I can iterate that list and build a byte array? How would I do that? It seems this is not efficient?
It seems like currently there is no API can build the InkStroke collections as byte array directly. SaveAsync() method has already help you save the InkStroke collection to a stream, you can use code above for using it.
I am developing one windows phone application which useful for upload images to web server. I am selecting all images from my device into one List object. I am converting all bitmap image to byte[] one by one.
My code
public byte[] ConvertToBytes(BitmapImage bitmapImage)
{
byte[] data = null;
WriteableBitmap wBitmap = null;
using (MemoryStream stream = new MemoryStream())
{
wBitmap = new WriteableBitmap(bitmapImage);
wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
//data = stream.GetBuffer();
data = stream.ToArray();
DisposeImage(bitmapImage);
return data;
}
}
public void DisposeImage(BitmapImage image)
{
if (image != null)
{
try
{
using (MemoryStream ms = new MemoryStream(new byte[] { 0x0 }))
{
image.SetSource(ms);
}
}
catch (Exception ex)
{
}
}
}
Conversion from bitmap to byte
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.DirectoryExists("ImagesZipFolder"))
{
//MediaImage mediaImage = new MediaImage();
//mediaImage.ImageFile = decodeImage(new byte[imgStream[0].Length]);
//lstImages.Items.Add(mediaImage);
store.CreateDirectory("ImagesZipFolder");
for (int i = 0; i < imgname.Count(); i++)
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(#"ImagesZipFolder\" + imgname[i], FileMode.CreateNew,store))
//using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(#"ImagesZipFolder\text.txt" , System.IO.FileMode.OpenOrCreate, store))
{
// byte[] bytes = new byte[imgStream[i].Length];
byte[] bytes = ConvertToBytes(ImgCollection[i]);
stream.Write(bytes, 0, bytes.Length);
}
}
}
else {
directory = true;
}
}
I have 91 images in my emulator. When I am converting all these bitmap images into byte[], get's following error on line wBitmap = new WriteableBitmap(bitmapImage);
An exception of type 'System.OutOfMemoryException' occurred in System.Windows.ni.dll but was not handled in user code
What can I do to solve this error?
Web Service
If we are sending huge file to web service, is it gives error like
An exception of type 'System.OutOfMemoryException' occurred in System.ServiceModel.ni.dll but was not handled in user code
What can I do to solve this error?
Change the way you do things, to use less memory.
For instance, instead of converting every picture then uploading them, convert a picture, upload it, convert the next, and so on.
If you really want to process all the pictures at once, you can store the byte arrays in the isolated storage rather than keeping them in memory, and read them back when needed.
Basically, rethink your process and use the storage to use less memory at a given time.
That or ask Microsoft to lift the memory limit on Windows Phone, but it may be a tad trickier.
The problem lies within how the GC and bitmap images work together as described in this bug report: https://connect.microsoft.com/VisualStudio/feedback/details/679802/catastrophic-failure-exception-thrown-after-loading-too-many-bitmapimage-objects-from-a-stream#details
From the report:
When Silverlight loads an image, the framework keeps a reference and
caches the decoded image until flow control is returned to the UI
thread dispatcher. When you load images in a tight loop like that,
even though your application doesn't retain a reference, the GC can't
free the image until we release our reference when flow control is
returned.
After processing 20 or so images, you could stop and queue the next
set using Dispatcher.BeginInvoke just to break up the work that is
processed in one batch. This will allow us to free images that aren't
retained by your application.
I understand with the current decode behavior it's not obvious that
Silverlight is retaining these references, but changing the decoder
design could impact other areas, so for now I recommend processing
images like this in batches.
Now, if you're actually trying to load 500 images and retain them, you
are still likely to run out of memory depending on image size. If
you're dealing with a multi-page document, you may want to instead
load pages on demand in the background and release them when out of
view with a few pages of buffer so that at no point do you exceed
reasonable texture memory limits.
Fix:
private List<BitmapImage> Images = .....;
private List<BitmapImage>.Enumerator iterator;
private List<byte[]> bytesData = new List<byte[]>();
public void ProcessImages()
{
if(iterator == null)
iterator = Images.GetEnumerator();
if(iterator.MoveNext())
{
bytesData.Add(ConvertToBytes(iterator.Current));
//load next images
Dispatcher.BeginInvoke(() => ProcessImages());
}else{
//all images done
}
}
public static byte[] ConvertToBytes(BitmapImage bitmapImage)
{
using (MemoryStream stream = new MemoryStream())
{
var wBitmap = new WriteableBitmap(bitmapImage);
wBitmap.SaveJpeg(stream, wBitmap.PixelWidth, wBitmap.PixelHeight, 0, 100);
stream.Seek(0, SeekOrigin.Begin);
return stream.ToArray();
}
}
I have found new way to convert Bitmap Image to byte[] array. There is no need to write image in memory.
Hare is code
public byte[] GetBytes(BitmapImage bi)
{
WriteableBitmap wbm = new WriteableBitmap(bi);
return ToByteArray(wbm);
}
public byte[] ToByteArray(WriteableBitmap bmp)
{
// Init buffer
int w = bmp.PixelWidth;
int h = bmp.PixelHeight;
int[] p = bmp.Pixels;
int len = p.Length;
byte[] result = new byte[4 * w * h];
// Copy pixels to buffer
for (int i = 0, j = 0; i < len; i++, j += 4)
{
int color = p[i];
result[j + 0] = (byte)(color >> 24); // A
result[j + 1] = (byte)(color >> 16); // R
result[j + 2] = (byte)(color >> 8); // G
result[j + 3] = (byte)(color); // B
}
return result;
}
Hi I can’t find sample for convert MULTI PAGE tiff image to byte array.
For convert byte array to Tiff I use this method
public static Tiff CreateTiffFromBytes(byte[] bytes)
{
using (var ms = new MemoryStream(bytes))
{
Tiff tiff = Tiff.ClientOpen("in-memory", "r", ms, new TiffStream());
return tiff;
}
}
EDITED:
This method convert TIFF image with more pages to byte Array. I think in this method will be root of problem.
//imageIn is tif image with 12 pages
public static byte[] ImageToByteArray(System.Drawing.Image imageIn)
{
using (var ms = new MemoryStream())
{
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Tiff);
return ms.ToArray();
}
}
public static List<System.Drawing.Image> GetAllPages(System.Drawing.Image multiTiff)
{
var images = new List<System.Drawing.Image>();
var bitmap = (Bitmap)multiTiff;
int count = bitmap.GetFrameCount(FrameDimension.Page);
for (int idx = 0; idx < count; idx++)
{
bitmap.SelectActiveFrame(FrameDimension.Page, idx);
using (var byteStream = new MemoryStream())
{
bitmap.Save(byteStream, ImageFormat.Tiff);
images.Add(System.Drawing.Image.FromStream(byteStream));
}
}
return images;
}
After conversion to byte array I lose pages.
Image from byte array has only one page.
Image src = Image.FromFile(source);
//imagesInSource.Count (pages) is 12
List<Image> imagesInSource = GetAllPages(src);
byte[] imageData = ImageToByteArray(src);
Image des = ImageConvert.ByteArrayToImage(imageData);
//imagesInSource.Count (pages) is 1
List<Image> imagesInDes = GetAllPages(des);
I am not sure why you can't send TIFF file to the service? The file is just bytes, after all.
And your code in the first snippet is incorrect because you dispose memory stream that is passed to Tiff object. You shouldn't do that. The Tiff object will dispose the stream itself.
EDIT:
In the third snippet you create images for each page of the System.Drawing.Image but the you convert only first produced image to byte array. You should use something like
List<byte[]> imagesBytes = new List<byte[]>();
foreach (Image img in imagesInSource)
{
byte[] imageData = ImageToByteArray(src);
imageBytes.Add(imageData);
}
Then you should send imagesBytes to your server and create several TIFF images from that.
Anyway, it seems like you should think more about what are you really trying to do. Because for now it unclear to me what all these conversions are for.
I am having a problem converting a Byte array into an Image type for displaying in an application on Windows Phone 7.
The data is retrieved from a server, and when I upload and download the data it works fine, but I am struggling when converting it back into an Image format.
Can anyone shed some light on this issue for me?
This is my method for turning the Byte array into a BitmapImage,
public BitmapImage decodeImage(byte[] array)
{
MemoryStream ms = new MemoryStream(array, 0, array.Length);
// Convert byte[] to Image
ms.Write(array, 0, array.Length);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(ms);
return bitmapImage;
}
Then this is the code where I try to set the returned BitmapImage to the source for the Image box I am using in the XAML UI.
BitmapImage usrIMG = new BitmapImage();
usrIMG = getJson.decodeImage(userProfile.Photos[0].Image);
profileImage.Source = usrIMG;
I know the code looks mishmashed, and I am declaring things that I dont need to, i have been fiddling with it for ages and I am completely at a loss.
Many Thanks
the following code works fine for me in a quick test for your scenario of using the PhotoChooserTask, and store the selected image in a byte array. You also might want to review your code where you store and retrieve the byte array on your side, to make sure nothing gets lost there.
private byte[] imageBytes;
private void GetPhoto_Click(object sender, RoutedEventArgs e)
{
PhotoChooserTask photoTask = new PhotoChooserTask();
photoTask.Completed += new EventHandler<PhotoResult>(photoTask_Completed);
photoTask.Show();
}
void photoTask_Completed(object sender, PhotoResult e)
{
imageBytes = new byte[e.ChosenPhoto.Length];
e.ChosenPhoto.Read(imageBytes, 0, imageBytes.Length);
// save 'imageBytes' byte array to data base ...
}
private void ShowPhoto_Click(object sender, RoutedEventArgs e)
{
// load 'imageBytes' byte array to data base ...
BitmapImage bitmapImage = new BitmapImage();
MemoryStream ms = new MemoryStream(imageBytes);
bitmapImage.SetSource(ms);
myImageElement.Source = bitmapImage;
}
You'll need a WritableBitmap and to know the height and width of the image to be able to do this.
Then you can do something like this:
var result = new WriteableBitmap(width, height);
var ms = new MemoryStream();
ms.Write(myByteArray, myByteArray, myByteArray.Length);
result.SetSource(ms);
var bitmapImage = new BitmapImage();
bitmapImage.SetSource(new MemoryStream(..Binary array Data..));
img1.Source = bitmapImage;
public BitmapImage ByteArraytoBitmap(Byte[] byteArray)
{
MemoryStream stream = new MemoryStream(byteArray);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
i used this code before and it's work 100% successfuly.