I'm new to C# and got problem with QR code decoding using ZXing.Net. The application launches with no errors, but I get nothing in the result string. I think the problem could be in RGBLuminanceSource().
private static byte[] ToByteArray(Image img)
{
byte[] byteArray = new byte[0];
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Close();
byteArray = stream.ToArray();
}
return byteArray;
}
private void button1_Click(object sender, EventArgs e)
{
*** SOME OTHER CODE HERE ***
Bitmap BitmapImage = new Bitmap(#"D:\1.png");
QRCodeReader reader = new QRCodeReader();
LuminanceSource source = new RGBLuminanceSource(ToByteArray(BitmapImage), BitmapImage.Width, BitmapImage.Height);
var binarizer = new HybridBinarizer(source);
var binBitmap = new BinaryBitmap(binarizer);
string result = reader.decode(binBitmap).Text;
*** SOME OTHER CODE HERE ***
}
Just call function. Also, replace ... with your handling
public Result decode(Uri uri)
{
Bitmap image;
try
{
image = (Bitmap) Bitmap.FromFile(uri.LocalPath);
}
catch (Exception)
{
throw new FileNotFoundException("Resource not found: " + uri);
}
using (image)
{
LuminanceSource source;
source = new BitmapLuminanceSource(image);
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
Result result = new MultiFormatReader().decode(bitmap);
if (result != null)
{
... code found
}
else
{
... no code found
}
return result;
}
}
Related
So I'm making a Xamarin.Forms app. I have a StackLayout, of which I'm taking a snapshot(only the element, not the whole screen.)
This is the interface:
public interface IViewSnapShot
{
Task<byte[]> CaptureAsync(Xamarin.Forms.View view);
}
this is the event:
private async Task SavePic_ClickedAsync(object sender, EventArgs e)
{
var imageByte = await DependencyService.Get<IViewSnapShot>().CaptureAsync(BlueprintSnapshot);
}
and this is Android platform specific:
public class MakeViewSnapshot : IViewSnapShot
{
Task<byte[]> IViewSnapShot.CaptureAsync(Xamarin.Forms.View view)
{
var nativeView = view.GetRenderer().View;
var wasDrawingCacheEnabled = nativeView.DrawingCacheEnabled;
nativeView.DrawingCacheEnabled = true;
nativeView.BuildDrawingCache(false);
Bitmap bitmap = nativeView.GetDrawingCache(false);
// TODO: Save bitmap and return filepath
nativeView.DrawingCacheEnabled = wasDrawingCacheEnabled;
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
The problem is bitmapData gives error
Cannot implicitly convert type 'byte[]' to 'System.Threading.Tasks.Task'
I have search internet, and every post says that this is the way to convert bitmap to byte[] array. Any idea how to fix this error?
Later I'll want to upload the byte[] array to web api.
Instead of returning a byte[], you can use the Task.FromResult() to wrap a result into a Task:
return Task.FromResult(bitmapData);
Your code might looks like this:
public class MakeViewSnapshot : IViewSnapShot
{
Task<byte[]> IViewSnapShot.CaptureAsync(Xamarin.Forms.View view)
{
var nativeView = view.GetRenderer().View;
var wasDrawingCacheEnabled = nativeView.DrawingCacheEnabled;
nativeView.DrawingCacheEnabled = true;
nativeView.BuildDrawingCache(false);
Bitmap bitmap = nativeView.GetDrawingCache(false);
// TODO: Save bitmap and return filepath
nativeView.DrawingCacheEnabled = wasDrawingCacheEnabled;
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return Task.FromResult(bitmapData);
}
}
And then later when you want to get the byte[] returned by CaptureAsync() you just need to call:
byte[] result = CaptureAsync(<Your_parameters>).Result;
This question already has answers here:
Byte array to image conversion
(14 answers)
Display image from byte[ ]
(1 answer)
Closed 5 years ago.
I'm new to WPF programming and Microsoft SQL server. I want to insert and retrieve an image to/from a database. I learned about converting an image (Windows.Controls.Image) to byte[] and storing it to a database, but I couldn't convert from byte[] to Image back to display it in a WPF window.
private Image byteArrayToImage(byte[] arr)
{
MemoryStream stream = new MemoryStream();
stream.Write(arr, 0, arr.Length);
stream.Position = 0;
System.Drawing.Image img = System.Drawing.Image.FromStream(stream); // Exception
BitmapImage returnImage = new BitmapImage();
returnImage.BeginInit();
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
returnImage.StreamSource = ms;
returnImage.EndInit();
Image ans = new Image();
ans.Source = returnImage;
return ans;
}
Output:
System.ArgumentException: 'Parameter is not valid.'
private byte[] imageToArray(System.Drawing.Image img) // Work well
{
MemoryStream ms = new MemoryStream();
FileInfo fi = new FileInfo(tempData); // File name
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] pic = ms.ToArray();
return pic;
}
first, create a static class for your PictureHelper. You must import the BitmapImage that is used in WPF, i think its the using System.Drawing.Imaging;
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Threading;
using Application = System.Windows.Forms.Application;
using Size = System.Drawing.Size;
public static class PictureHelper
{
public static BitmapImage GetImage(object obj)
{
try
{
if (obj == null || string.IsNullOrEmpty(obj.ToString())) return new BitmapImage();
#region Picture
byte[] data = (byte[])obj;
MemoryStream strm = new MemoryStream();
strm.Write(data, 0, data.Length);
strm.Position = 0;
Image img = Image.FromStream(strm);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Bmp);
ms.Seek(0, SeekOrigin.Begin);
bi.StreamSource = ms;
bi.EndInit();
return bi;
#endregion
}
catch
{
return new BitmapImage();
}
}
public static string PathReturner(ref string name)
{
string filepath = "";
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Multiselect = false;
openFileDialog.Filter = #"Image Files(*.jpeg;*.bmp;*.png;*.jpg)|*.jpeg;*.bmp;*.gif;*.png;*.jpg";
openFileDialog.RestoreDirectory = true;
openFileDialog.Title = #"Please select an image file to upload.";
MiniWindow miniWindow = new MiniWindow();
miniWindow.Show();
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
filepath = openFileDialog.FileName;
name = openFileDialog.SafeFileName;
}
miniWindow.Close();
miniWindow.Dispose();
return filepath;
}
public static string Encryptor(this string safeName)
{
string extension = Path.GetExtension(safeName);
string newFileName = String.Format(#"{0}{1}{2}", Guid.NewGuid(), DateTime.Now.ToString("MMddyyyy(HHmmssfff)"), extension);
newFileName = newFileName.Replace("(", "").Replace(")", "");
return newFileName;
}
public static Bitmap ByteToBitmap(this byte[] blob)
{
MemoryStream mStream = new MemoryStream();
byte[] pData = blob;
mStream.Write(pData, 0, Convert.ToInt32(pData.Length));
Bitmap bm = new Bitmap(mStream, false);
mStream.Dispose();
return bm;
}
public static byte[] BitmapToByte(this Image img)
{
byte[] byteArray = new byte[0];
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, ImageFormat.Png);
stream.Close();
byteArray = stream.ToArray();
}
return byteArray;
}
}
this is for retrieving the class (in my case, Candidate) with picture
public SortableBindingList<Candidate> RetrieveManyWithPicture(Candidate entity)
{
var command = new SqlCommand { CommandText = "RetrievePictureCandidates", CommandType = CommandType.StoredProcedure };
command.Parameters.AddWithValue("#CandidateId", entity.CandidateId).Direction = ParameterDirection.Input;
DataTable dt = SqlHelper.GetData(command); //this is where I retrieve the row from db, you have your own code for retrieving, so make sure it works.
var items = new SortableBindingList<Candidate>();
if (dt.Rows.Count <= 0) return items;
foreach (DataRow row in dt.Rows)
{
Candidate item = new Candidate();
item.CandidateId = row["CandidateId"].GetInt();
item.LastName = row["LastName"].GetString();
item.FirstName = row["FirstName"].GetString();
item.PictureId = row["PictureId"].GetInt();
item.PhotoType = PictureHelper.GetImage(row["Photo"]); //in my db, this is varbinary. in c#, this is byte[]
items.Add(item);
}
return items;
}
this is for uploading image from wpf to db which I used on my button
private void UploadButton_Click(object sender, EventArgs e)
{
string safeName = "";
string pathName = PictureHelper.PathReturner(ref safeName);
PictureViewModel vm = new PictureViewModel();
if (pathName != "")
{
safeName = safeName.Encryptor();
FileStream fs = new FileStream(pathName, FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, Convert.ToInt32(fs.Length));
fs.Close();
PicNameLabel.Text = safeName;
vm.Entity.Name = safeName; //this is the byte[]
Bitmap toBeConverted = PictureHelper.ByteToBitmap(data); //convert the picture before sending to the db
vm.Entity.Photo = PictureHelper.BitmapToByte(toBeConverted);
vm.Entity.Path = pathName;
CandidatePictureBox.Image = toBeConverted;
vm.Insert(vm.Entity);
}
}
this is the method to save the picture
public bool Insert(Picture entity)
{
var command = new SqlCommand();
try
{
command.CommandText = "AddPicture";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#Name", entity.Name).Direction = ParameterDirection.Input;
command.Parameters.AddWithValue("#Photo", entity.Photo).Direction = ParameterDirection.Input;
int result = SqlHelper.ExecuteNonQuery(command); //executenonquery will save the params to the db
return true;
}
catch (Exception)
{
return false;
}
}
I want to store a WPF BitmapImage to XML. (I know this is not usually recommended but for my case, it makes sense as I want to embed all my resource to a single XML file besides other data I have).
So Here are my extension methods:
public static string ToBase64(this BitmapImage image, string format)
{
return Convert.ToBase64String(Encode(image, format));
}
public static Stream FromBase64(this string content)
{
var bytes = Convert.FromBase64String(content);
var stream = new MemoryStream();
stream.Write(bytes, 0, bytes.Length);
return stream;
}
private static byte[] Encode(BitmapImage bitmapImage, string format)
{
byte[] data = null;
BitmapEncoder encoder = null;
switch (format.ToUpper())
{
case "PNG": encoder = new PngBitmapEncoder();
break;
case "GIF": encoder = new GifBitmapEncoder();
break;
case "BMP": encoder = new BmpBitmapEncoder();
break;
case "JPG": encoder = new JpegBitmapEncoder();
break;
}
if (encoder != null)
{
encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
using (var ms = new MemoryStream())
{
encoder.Save(ms);
ms.Seek(0, SeekOrigin.Begin);
data = ms.ToArray();
}
}
return data;
}
public static BitmapImage ToBitmapImage(this Stream stream)
{
try
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
return bitmap;
}
catch (Exception ex)
{
}
return null;
}
and here is my XML logics:
public async void LoadImage(Guid imageSourceGuid)
{
var sourceElement = await GetImageSource(imageSourceGuid);
if (sourceElement != null)
{
var data = sourceElement.Element("Value").Value;
Format = sourceElement.Attribute("Format").Value.ToUpper();
if (string.IsNullOrEmpty(data) == false)
{
using (var stream = data.FromBase64())
{
SetImage(stream.ToBitmapImage());
}
}
}
}
private void SetImage(BitmapImage bitmap)
{
this.ImageShape.Source = bitmap;
}
public async Task<XElement> GetImageSource(Guid id)
{
XElement result = null;
await Task.Run(() =>
{
var settings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment, IgnoreWhitespace = true, IgnoreComments = true, Async = true };
using (var reader = XmlReader.Create(FilePath, settings))
{
while (reader.Read())
{
if (reader.IsStartElement() && reader.Name == "ImageSource")
{
var att = reader.GetAttribute("Id");
if (att != null && Guid.Parse(att) == id)
{
result = XNode.ReadFrom(reader) as XElement;
break;
}
}
}
}
});
return result;
}
My XML file looks like:
<?xml version="1.0" encoding="utf-8"?>
<ImageSources>
<ImageSource Id="1b1e4ebc-484c-4f63-bbed-bf33430f85f2" Format="JPG" OriginalWidth="534" OriginalHeight="338">
<Value><![CDATA[....]]<Value>
</ImageSource>
</ImageSources>
...
But when I try to create a BitmapImage using ToBitmapImage method from the XML data I saved earlier I get "The image cannot be decoded. The image header might be corrupted." exception.
This only happens for JPG files I have no issue with PNG files at all.
You should rewind the MemoryStream after writing in your FromBase64 method:
public static Stream FromBase64(this string content)
{
var bytes = Convert.FromBase64String(content);
var stream = new MemoryStream();
stream.Write(bytes, 0, bytes.Length);
stream.Seek(0, SeekOrigin.Begin); // here
return stream;
}
Or construct it directly from the byte array:
public static Stream FromBase64(this string content)
{
return new MemoryStream(Convert.FromBase64String(content));
}
Afaik, JpegBitmapDecoder is the only BitmapDecoder in WPF that is affected by the source stream's actual Position.
for (int i = 3; i < 10; i++)
{
Uri uriimg = new Uri("http://i.msdn.microsoft.com/dynimg/IC53593" + i + ".jpg", UriKind.RelativeOrAbsolute);
SaveToLocalStorage(ImageToArray(uriimg), "anh1.jpg");
}
private byte[] ImagesToArray(Uri uriimg)
{
var image = new BitmapImage(uriimg);
MemoryStream ms = new MemoryStream();
image.ImageOpened += (s, e) =>
{
image.CreateOptions = BitmapCreateOptions.None;
WriteableBitmap wb = new WriteableBitmap(image);
wb.SaveJpeg(ms, image.PixelWidth, image.PixelHeight, 0, 100);
};
return ms.ToArray();
}
public async void SaveToLocalStorage(byte[] _imageBytes, string fileName)
{
if (_imageBytes == null)
{
return;
}
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
if (!isoFile.DirectoryExists("dataImages"))
{
isoFile.CreateDirectory("dataImages");
}
string filePath = System.IO.Path.Combine("dataImages", fileName);
using (var stream = isoFile.CreateFile(filePath))
{
await stream.WriteAsync(_imageBytes, 0, _imageBytes.Length);
}
}
public ImageSource LoadFromLocalStorage(string fileName)
{
var isoFile = IsolatedStorageFile.GetUserStoreForApplication();
ImageSource imageSource = null;
if (isoFile.DirectoryExists("dataImages"))
{
string filePath = System.IO.Path.Combine("dataImages", fileName);
using (var imageStream = isoFile.OpenFile(filePath, FileMode.Open, FileAccess.Read))
{
imageSource = PictureDecoder.DecodeJpeg(imageStream);
}
}
return imageSource;
}
I get the value as byte [0] it can not convert to byte [].
The problem I see is in ImagesToArray. You create a new MemoryStream, subscribe to an event that sets it, and then immediately return it. I'm pretty sure that ms will have 0 bytes when it is returned.
You should instead not use image.ImageOpened, and just put that code in the ImagesToArray method directly:
private byte[] ImagesToArray(Uri uriimg)
{
var image = new BitmapImage(uriimg);
MemoryStream ms = new MemoryStream();
image.CreateOptions = BitmapCreateOptions.None;
WriteableBitmap wb = new WriteableBitmap(image);
wb.SaveJpeg(ms, image.PixelWidth, image.PixelHeight, 0, 100);
return ms.ToArray();
}
How can I load a bitmapImage from base64String in windows 8?
I tried this but I am not successful. It used to work on windows phone. What is different?
Looks like I have to use the function setsourceasync. When I use that, then I am required to pass the parameter as IRandomMemory which I am unable to do. How to do this?
public static BitmapImage Base64ToImage(string base64String)
{
var bitmapImage = new BitmapImage();
try
{
if (!String.IsNullOrEmpty(base64String))
{
var imageBytes = Convert.FromBase64String(base64String);
using (var ms = new MemoryStream(imageBytes, 0, imageBytes.Length))
{
bitmapImage.SetSourcec(ms);
return bitmapImage;
}
}
}
catch (Exception e)
{
}
return null;
}
To create an IRandomAccessStream object for the SetSource method, you need to use a DataWriter. Take a look to this code:
public async Task<BitmapImage> GetImage(string value)
{
if (value == null)
return null;
var buffer = System.Convert.FromBase64String(value);
using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
{
writer.WriteBytes(buffer);
await writer.StoreAsync();
}
var image = new BitmapImage();
image.SetSource(ms);
return image;
}
}
Here conversion methods for both System.Drawing.Bitmap and System.Windows.Media.BitmapSource.
Enjoy
Remark: Not tested on Win8 but there is not reason why it should not work.
string ToBase64(Bitmap bitmap)
{
if (bitmap == null)
throw new ArgumentNullException("bitmap");
using (var stream = new MemoryStream())
{
bitmap.Save(stream, ImageFormat.Png);
return Convert.ToBase64String(stream.ToArray());
}
}
string ToBase64(BitmapSource bitmapSource)
{
using (var stream = new MemoryStream())
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapSource));
encoder.Save(stream);
return Convert.ToBase64String(stream.ToArray());
}
}
Bitmap FromBase64(string value)
{
if (value == null)
throw new ArgumentNullException("value");
using (var stream = new MemoryStream(Convert.FromBase64String(value)))
{
return (Bitmap)Image.FromStream(stream);
}
}
BitmapSource BitmapSourceFromBase64(string value)
{
if (value == null)
throw new ArgumentNullException("value");
using (var stream = new MemoryStream(Convert.FromBase64String(value)))
{
var decoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
BitmapSource result = decoder.Frames[0];
result.Freeze();
return result;
}
}