How to Read barcode image in Xamarin forms - xamarin.forms

I am trying to read the text from a QRcode image on my mobile app. I am using Xamarin.Forms with ZXing NuGet package.
I have been able to get the file using Xamarin.Essentials FilePicker. But I don't know how to actually read the barcode. I have looked at some stackoverflow solutions and they all seem to be Xamarin.Android based (using BinaryBitmap objects). I need a solution that can work for iOS and UWP as well. Here is what I have so far:
string file = "";
var filePickerOptions = new PickOptions
{
PickerTitle = "Select Barcode Image",
FileTypes = FilePickerFileType.Images
};
var result = await FilePicker.PickAsync(filePickerOptions);
if (result != null)
{
file = result.FullPath;
var res = Decode(file, BarcodeFormat.QR_CODE);
Console.WriteLine(res.Text);
}
public Result Decode(string file, BarcodeFormat? format = null, KeyValuePair<DecodeHintType, object>[] aditionalHints = null)
{
var r = GetReader(format, aditionalHints);
/* I need some function here that will allow me to get the BinaryBitmap from the image file path or something along those lines.*/
var image = GetBinaryBitmap(file);
var result = r.decode(image);
return result;
}
MultiFormatReader GetReader(BarcodeFormat? format, KeyValuePair<DecodeHintType, object>[] aditionalHints)
{
var reader = new MultiFormatReader();
var hints = new Dictionary<DecodeHintType, object>();
if (format.HasValue)
{
hints.Add(DecodeHintType.POSSIBLE_FORMATS, new List<BarcodeFormat>() { format.Value });
}
if (aditionalHints != null)
{
foreach (var ah in aditionalHints)
{
hints.Add(ah.Key, ah.Value);
}
}
reader.Hints = hints;
return reader;
}

https://github.com/Redth/ZXing.Net.Mobile/issues/981. This thread solved it for me. Credit to #jason for this response.

Related

ASP.NET Core Image Resize

I'm trying to resize imagine with System.Drawing but im taking that file as IFormFile and when i use the System.Drawing its just keep warning me to about that : cannot implicitly convert type 'System.Drawing.Bitmap' to 'Microsoft.AspNetCore.Http.IFormFile' . I need to resize those photos and save them as IFormFile but i dont know how to do that.
public Task<IFormFile> ResizeImagine300x300(IFormFile file)
{
Image image = Image.FromStream(file.OpenReadStream(), true, true);
var newImage = new Bitmap(1024, 768);
using (var g = Graphics.FromImage(newImage))
{
g.DrawImage(image, 0, 0, 1024, 768);
};
return newImage;//the point where i get the error
}
Is it possible to do it in my way?
If its not possible, then which way i should follow?
Thanks for any suggestion
Edit: I wanna return as a IFormFile because i have a method which is uploading those files to my database. here is my method :
public async Task<FileRepo> FileUploadToDatabase(List<IFormFile> files)
{
foreach (var file in files)
{
var fileName = Path.GetFileNameWithoutExtension(file.FileName);
var fileExtension = Path.GetExtension(file.FileName);
_fileRepo = new FileRepo
{
FileName = fileName,
FileExtension = fileExtension,
FileType = file.ContentType,
CreatedDate= DateTime.Now
};
using (var dataStream = new MemoryStream())
{
await file.CopyToAsync(dataStream);
_fileRepo.FileData = dataStream.ToArray();
}
}
return _fileRepo;
}
After that I'm uploading that _fileRepo variable to my database like that :
var File = _fileUploader.FileUploadToDatabase(files);
var FileResult = File.Result;
FileResult.ProductID = ProductID;
_unitOfWorkFR.RepositoryFileRepo.Create(FileResult);

Retrieving Image from Chooser Intent in Android 10

I'm trying to update my app to work with androids new scoped storage rules in Android 10 and up, but am having the hardest time with it. I know I need to rebuild my app with new versions of java, but I just want to get it to work while I study and learn enough to do so. In a nutshell, I really need help. I have read so many different ways to make scoped storage work, and everybody seems to be doing it differently.
Just for clarification, what I am trying to do with the uri is both display in an imageview, then upload to database.
This code is working to take a picture and select images and videos in android 9, but in android 10, it only works when camera component captures a picture or a video. When a user selects an image or video from file, it returns a null pointer exception. Because I am pretty sure the error is in how I am dealing with the different chooser intents, I have shown the on result code first.
I have been unable to find a clear example of how to retrieve a usable image or video uri in android 10. If anybody can help, I would really appreciate it. I know I have much to learn.
if ((new java.io.File(_filePath)).exists()){
} else {
_filePath = vidfile.getAbsolutePath();
if ((new java.io.File(_filePath)).exists()){
} else {
ArrayList<String> _filePath_1 = new ArrayList<>();
if (_data != null) {
if (_data.getClipData() != null) {
for (int _index = 0; _index < _data.getClipData().getItemCount(); _index++) {
ClipData.Item _item = _data.getClipData().getItemAt(_index);
_filePath_1.add(FileUtil.convertUriToFilePath(getApplicationContext(),
_item.getUri()));
}
}
else {
_filePath_1.add(FileUtil.convertUriToFilePath(getApplicationContext(),
_data.getData()));
}
}
_filePath = _filePath_1.get((int)0);
}
}
Just in case I am wrong, here is the code for the click event to launch the chooser...
SimpleDateFormat date1 = new SimpleDateFormat("yyyyMMdd_HHmmss");
String fileName1 = date1.format(new Date()) + ".jpg";
picfile = new
File(getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() +
File.separator + fileName1);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri _uri_camr1 = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
_uri_camr1 = FileProvider.getUriForFile(getApplicationContext(),
getApplicationContext().getPackageName() + ".provider", picfile);
}
else {
_uri_camr1 = Uri.fromFile(picfile);
}
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, _uri_camr1);
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
SimpleDateFormat date2 = new SimpleDateFormat("yyyyMMdd_HHmmss");
String fileName2 = date2.format(new Date()) + ".mp4";
vidfile = new
File(getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath() +
File.separator + fileName2);
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
Uri _uri_camr2 = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
_uri_camr2 = FileProvider.getUriForFile(getApplicationContext(),
getApplicationContext().getPackageName() + ".provider", vidfile);
}
else {
_uri_camr2 = Uri.fromFile(vidfile);
}
takeVideoIntent.putExtra(MediaStore.EXTRA_OUTPUT, _uri_camr2);
takeVideoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
contentSelectionIntent.setType("*/*");
contentSelectionIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Intent[] intentArray = new Intent[]{ takePictureIntent, takeVideoIntent};
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
chooserIntent.putExtra(Intent.EXTRA_TITLE, "Choose an action");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
startActivityForResult(chooserIntent, REQ_CD_CAMR);
try this code. it copies the selected file to scoped storage and gives you the final path of scoped storage from where you can access it. try it out & let me know if you face any problem.
android.net.Uri sharedFileUri = android.net.Uri.fromFile(new java.io.File(_filepath));
java.io.FileInputStream input = null;
java.io.FileOutputStream output = null;
try {
String filePath = new java.io.File(getCacheDir(), "tmp").getAbsolutePath();
android.os.ParcelFileDescriptor pfd = getContentResolver().openFileDescriptor(sharedFileUri, "rw");
if (pfd != null) {
java.io.FileDescriptor fd = pfd.getFileDescriptor();
input = new java.io.FileInputStream (fd);
output = new java.io.FileOutputStream (filePath);
int read;
byte[] bytes = new byte[4096];
while ((read = input.read(bytes)) != -1) {
output.write(bytes, 0, read);
}
java.io.File sharedFile = new java.io.File(filePath);
String finalPath = sharedFile.getPath(); // this will provide you path to scoped storage. use this final path to access the selected file from scoped storage.
}
}catch(Exception ex) {
android.widget.Toast.makeText(this, ex.toString(), android.widget.Toast.LENGTH_SHORT).show();
} finally {
try {
input.close();
output.close();
} catch (Exception ignored) {
}
}

Passing images from one page to another in Xamarin Forms

In my app I need to pass images from one page to another page image view to display. I am taking a photo from camera and do some stuffs, then I want to send that images to the second page.
if (await isCamAvailable())
{
MediaFile photo1 = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions() { Directory = "NewBusiness", Name = "image1.jpg", PhotoSize = PhotoSize.MaxWidthHeight, MaxWidthHeight = 1024, CompressionQuality = 95 });
if (photo1 != null)
{
PhotoImage1.Source = ImageSource.FromStream(() => { return photo1.GetStream(); });
countList.Remove("a");
countList.Add("a");
}
}
Then I am added it to a string array by doing
private List<string> sendImgList = new List<string>();
sendImgList.Add(createImgByteString(photo1.GetStream()));
private string createImgByteString(Stream data)
{
var bytes = new byte[data.Length];
return Convert.ToBase64String(bytes);
}
Then from second page (for testing i just added only one image)
foreach (string ss in imgList) {
byte[] Base64Stream = Convert.FromBase64String(ss);
imgView.Source = ImageSource.FromStream(() => new MemoryStream(Base64Stream));
}
I followed this example. But image not showing.
https://forums.xamarin.com/discussion/139360/how-to-transfer-images-from-one-page-to-another
Also getting this in logcat..
[0:] ImageLoaderSourceHandler: Image data was invalid: Xamarin.Forms.StreamImageSource05-29 14:22:43.758 W/monodroid-assembly( 8737): typemap: unable to find mapping to a Java type from managed type 'System.Byte, mscorlib'
It seems that you used the Media.Plugin . Why don't you pass the ImageSource directly?
If you do want to convert it to byte array , check the following code
public byte[] GetImageStreamAsBytes(Stream input)
{
var buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
var imgDate = GetImageStreamAsBytes(photo1.GetStream());
It would be better to pass the byte array directly .
The best mode to pass parameter in pages is with Prism.
https://prismlibrary.com/docs/xamarin-forms/navigation/passing-parameters.html
>
_navigationService.NavigateAsync(new Uri("MainPage", new NavigationParameters
{
{ "key_parameter", image }
})));
And on other page:
>
public override void OnNavigatedTo(INavigationParameters parameters)
{
image = (Image)parameters["key_parameter"];
}

.NET Already Open DataReader

I get this error when running this code. I have looked for solution though I don't like the idea of using MARS as people have suggested as it may contain a lot of data, is there any other option here? Also can I edit a variable in a database without rewriting all of them as I do here, will this save server power or make no difference?
There is already an open DataReader associated with this Command which must be closed first.
public ActionResult CheckLinks(Link model)
{
var userId = User.Identity.GetUserId();
var UserTableID = db.UserTables.Where(c => c.ApplicationUserId == userId).First().ID;
foreach (var item in db.Links.Where(p => p.UserTable.ID == UserTableID))
{
string pageContent = null;
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(item.Obdomain);
HttpWebResponse myres = (HttpWebResponse)myReq.GetResponse();
using (StreamReader sr = new StreamReader(myres.GetResponseStream()))
{
pageContent = sr.ReadToEnd();
}
string live = "";
if (pageContent.Contains(item.Obpage))
{
live = "Yes";
}
else { live = "No"; }
var link = new Link { Obdomain = item.Obdomain, ClientID = item.ClientID, Obpage = item.Obpage, BuildDate = item.BuildDate, Anchor = item.Anchor, IdentifierID = item.IdentifierID, live = (Link.Live)Enum.Parse(typeof(Link.Live), live), UserTableID = item.UserTableID };
db.Entry(link).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}
Entity Framework allows only one active command per context at a time. You should add .ToList() at the end of the following statement:
db.Links.Where(p => p.UserTable.ID == UserTableID).ToList();
So your code could look like this:
var items = db.Links.Where(p => p.UserTable.ID == UserTableID).ToList();
foreach (var item in items)

Read text file with PCLStorage in Xamarin.Forms

Is there a way to read an embedded JSON file in a PCL project with PCLStorage module? I looked everywhere but couldn't find a sample related to this matter.
EDIT: PCLStorage link: https://github.com/dsplaisted/pclstorage
you need something like this:
public static async Task<string> ReadFileContent(string fileName, IFolder rootFolder)
{
ExistenceCheckResult exist = await rootFolder.CheckExistsAsync(fileName);
string text = null;
if (exist == ExistenceCheckResult.FileExists)
{
IFile file = await rootFolder.GetFileAsync(fileName);
text = await file.ReadAllTextAsync();
}
return text;
}
to use:
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder myCoolFolder = await rootFolder.CreateFolderAsync("MyCoolForler", CreationCollisionOption.OpenIfExists);
string fileContent = await this.ReadFileContent("MyCoolFile.txt", myCoolFolder);
You should be able to read embedded resources like this:
var assembly = typeof(LoadResourceText).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream("WorkingWithFiles.PCLTextResource.txt");
string text = "";
using (var reader = new System.IO.StreamReader (stream)) {
text = reader.ReadToEnd ();
}
Xamarin has a great guide on how to work with them here.
https://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/files/

Resources