How to get drawable path? - c#

public async Task<List<AppItem>> GetAndroidApps()
{
try
{
var apps = Android.App.Application.Context.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
foreach(var item in apps)
{
string packageName = item.PackageName;
string appName = item.LoadLabel(Android.App.Application.Context.PackageManager);
var appIcon = item.LoadIcon(Android.App.Application.Context.PackageManager).ToString();
System.Diagnostics.Debug.WriteLine($"{appIcon}; {appName}; {packageName};");
}
return null;
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
return null;
}
}
How I can get appIcon path to display it?
I can't get full path to other app icon...
Thank you!
Best wishes!

You could load the icon from the drawable resource identifier (in the package's resources) of this component's. And set the imagesource for imageview.
I use my App6 for example to load the icon. It works.
var apps = Android.App.Application.Context.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
foreach (var item in apps)
{
string packageName = item.PackageName;
string appName = item.LoadLabel(Android.App.Application.Context.PackageManager);
if (packageName == "com.companyname.app6")
{
var appIcon = item.LoadIcon(Android.App.Application.Context.PackageManager).ToString();
var image = item.Icon;
imageView.SetImageResource(image);
}
//System.Diagnostics.Debug.WriteLine($"{appIcon}; {appName}; {packageName};");
}
Updated:
You could use the DependentService to do that.
I convet the resID of deawable to bitmap and then convert the bitmap to stream. At last, i set the image source form the stream in Xamarin.forms.
Create the interface in Xamarin.forms.
public interface GetIcon
{
byte[] GetIconFromApp();
}
Implementation in Android:
[assembly: Dependency(typeof(GetIconFromApp_Android))]
namespace App13.Droid
{
class GetIconFromApp_Android : GetIcon
{
public byte[] GetIconFromApp()
{
var apps = Android.App.Application.Context.PackageManager.GetInstalledApplications(PackageInfoFlags.MatchAll);
byte[] bitmapData=null;
foreach (var item in apps)
{
string packageName = item.PackageName;
string appName = item.LoadLabel(Android.App.Application.Context.PackageManager);
if (packageName == "com.companyname.app6")
{
var appIcon = item.LoadIcon(Android.App.Application.Context.PackageManager).ToString();
var imageID = item.Icon;
// Converting Drawable Resource to Bitmap
var bitmap = BitmapFactory.DecodeResource(Forms.Context.Resources, imageID);
//comver bitmap to byte
using (var stream = new MemoryStream())
{
bitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
}
}
return bitmapData;
}
}
}
Platform implementations with button click event.
private void Button_Clicked(object sender, EventArgs e)
{
var ImageByteArray = DependencyService.Get<GetIcon>().GetIconFromApp();
image.Source = ImageSource.FromStream(() => new MemoryStream(ImageByteArray, 0, ImageByteArray.Length));
}
Screenshot:

Related

C# how can I extract photos from a zip file faster and more efficiently without extracting them using ZipArchive

I have a xamarin app that reads photos without extracting them into a zip file.
When I click very quickly on the page where the photos should be displayed. Sometimes half doesn't show because the app hasn't been able to read them all yet.
Navigating after that page goes like this
public async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
{
Content tappedStep = (Content)MyListView.SelectedItem;
int stepIndex = tappedStep.contentid;
string nextTitle = _protocol.name;
using (UserDialogs.Instance.Loading("Loading", null, null, true, MaskType.Black))
{
loading = true;
if (loading)
{
Title = nextTitle;
}
await Navigation.PushAsync(new StepView(_protocol, Title, tappedStep.chaptertitle, stepIndex));
}
((ListView)sender).SelectedItem = null;
}
So if I want to navigate too quickly after the stepview, the photos are often not all there.
This is the code I use to read the photos in the zip file.
private string PathToZip()
{
string folderName = $"protocol-{_protocol.id}-{_protocol.versionnr}.zip";
string extractPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string zipPath = $"{$"{extractPath}"}/{$"{folderName}"}";
return zipPath;
}
private async Task GetImage()
{
try
{
PathToZip();
int currentIndex = GetCurrentIndex();
Content content = _protocol.contents[currentIndex];
string imageName = $"{content.contentid}.jpg";
using (ZipArchive archive = ZipFile.OpenRead(PathToZip()))
{
for (int i = 0; i < archive.Entries.Count; i++)
{
ZipArchiveEntry pictureEntry = archive.Entries[i];
if (pictureEntry.Name == imageName)
{
//for reading the image
byte[] buffer;
long length = pictureEntry.Length;
buffer = new byte[length];
pictureEntry.Open().Read(buffer, 0, (int)length);
myImage.Source = ImageSource.FromStream(() => new MemoryStream(buffer));
}
}
}
}
catch (Exception)
{
}
}
How can I make this more efficient so that if the app hasn't loaded everything yet, when I want to navigate to the next page, the app then waits for each page to be read?
Thanks in advance

Is there a method of screenshot for all virtual display?

All the methods I've found are somehow UI dependent. So, how to capture all displays without any dependency and third party?
You can use GetSystemMetrics function with SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN parameters for entire desktop. It will be handle all virtual displays.
using System;
using System.ComponentModel;//You can remove it if you will catch the below exception from another layer
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace Helpers {
public static class HelperScreenShot {
public static void TakeAndSaveByAllScreen(ImageFormat imageFormat, string fullFileName = null) {
var img = CopyFromScreen();
if(img == null) return;
if(string.IsNullOrWhiteSpace(fullFileName)) {
fullFileName = $"{Guid.NewGuid()}.{imageFormat.ToString().ToLower()}";
}
img.Save(fullFileName, imageFormat);
}
public static byte[] TakeAsBinary(ImageFormat imageFormat) {
using var image = CopyFromScreen();
if(image == null) return default;
using var ms = new MemoryStream();
image.Save(ms, imageFormat);
return ms.ToArray();
}
private static Bitmap CopyFromScreen() {
try {
var size = HelperDisplay.GetVirtualScreenSize();
var image = new Bitmap(size.Width, size.Height);
using var graphics = Graphics.FromImage(image);
graphics.CopyFromScreen(Point.Empty, Point.Empty, size);
return image;
}
catch(Win32Exception) {//When screen saver is active
return null;
}
}
private static class HelperDisplay {
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(MetricType metricType);
public static Size GetVirtualScreenSize() {
var width = GetSystemMetrics(MetricType.VirtualScreenWidth);
var height = GetSystemMetrics(MetricType.VirtualScreenHeight);
return new Size(width, height);
}
private enum MetricType {
VirtualScreenWidth = 78,
VirtualScreenHeight = 79
}
}
}
}
Usage
var dir = Path.Combine("images", "screenshot");
var imgFormat = ImageFormat.Png;
var fileName = $"{Guid.NewGuid()}.{imgFormat.ToString().ToLower()}";
fileName = Path.Combine(dir, fileName);
if(!Directory.Exists(dir)) {
Directory.CreateDirectory(dir);
}
HelperScreenShot.TakeAndSaveByAllScreen(fileName, imgFormat);
//or
var binaryImg = HelperScreenShot.TakeAsBinary(imgFormat);
Further Reading:
Multiple Monitor System Metrics
winuser.h header
How do you use System.Drawing in .NET Core?

How to choose multiple image from Gallery at one time (tickbox) in Xamarin Android?

Hi have a Xamarin Android project using C#. Currently I am using await CrossMedia.Current.PickPhotoAsync() method to upload image. However, it did not provide a tickbox beside the images for me to select multiple. How can I manage to select multiple images and upload together?
You could implement it by yourself.
1.Add these methods to your MainActivity.cs file
public static int OPENGALLERYCODE = 100;
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
//If we are calling multiple image selection, enter into here and return photos and their filepaths.
if (requestCode == OPENGALLERYCODE && resultCode == Result.Ok)
{
List<string> images = new List<string>();
if (data != null)
{
//Separate all photos and get the path from them all individually.
ClipData clipData = data.ClipData;
if (clipData != null)
{
for (int i = 0; i < clipData.ItemCount; i++)
{
ClipData.Item item = clipData.GetItemAt(i);
Android.Net.Uri uri = item.Uri;
var path = GetRealPathFromURI(uri);
if (path != null)
{
images.Add(path);
}
}
}
else
{
Android.Net.Uri uri = data.Data;
var path = GetRealPathFromURI(uri);
if (path != null)
{
images.Add(path);
}
}
}
}
}
/// <summary>
/// Get the real path for the current image passed.
/// </summary>
public String GetRealPathFromURI(Android.Net.Uri contentURI)
{
try
{
ICursor imageCursor = null;
string fullPathToImage = "";
imageCursor = ContentResolver.Query(contentURI, null, null, null, null);
imageCursor.MoveToFirst();
int idx = imageCursor.GetColumnIndex(MediaStore.Images.ImageColumns.Data);
if (idx != -1)
{
fullPathToImage = imageCursor.GetString(idx);
}
else
{
ICursor cursor = null;
var docID = DocumentsContract.GetDocumentId(contentURI);
var id = docID.Split(':')[1];
var whereSelect = MediaStore.Images.ImageColumns.Id + "=?";
var projections = new string[] { MediaStore.Images.ImageColumns.Data };
cursor = ContentResolver.Query(MediaStore.Images.Media.InternalContentUri, projections, whereSelect, new string[] { id }, null);
if (cursor.Count == 0)
{
cursor = ContentResolver.Query(MediaStore.Images.Media.ExternalContentUri, projections, whereSelect, new string[] { id }, null);
}
var colData = cursor.GetColumnIndexOrThrow(MediaStore.Images.ImageColumns.Data);
cursor.MoveToFirst();
fullPathToImage = cursor.GetString(colData);
}
return fullPathToImage;
}
catch (Exception ex)
{
Toast.MakeText(Xamarin.Forms.Forms.Context, "Unable to get path", ToastLength.Long).Show();
}
return null;
}
2.invoked the following in the specific Activity which you want to open the picker
public void OpenGallery()
{
try
{
var imageIntent = new Intent(Intent.ActionPick);
imageIntent.SetType("image/*");
imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionGetContent);
this.StartActivityForResult(Intent.CreateChooser(imageIntent, "Select photo"), OPENGALLERYCODE);
Toast.MakeText(this, "Tap and hold to select multiple photos.", ToastLength.Short).Show();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Toast.MakeText(this, "Error. Can not continue, try again.", ToastLength.Long).Show();
}
}
void ClearFileDirectory()
{
var directory = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures), ImageHelpers.collectionName).Path.ToString();
if (Directory.Exists(directory))
{
var list = Directory.GetFiles(directory, "*");
if (list.Length > 0)
{
for (int i = 0; i < list.Length; i++)
{
File.Delete(list[i]);
}
}
}
}
//collectionName is the name of the folder in your Android Pictures directory.
public static readonly string collectionName = "TmpPictures";
public string SaveFile(byte[] imageByte, string fileName)
{
var fileDir = new Java.IO.File(Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures), collectionName);
if (!fileDir.Exists())
{
fileDir.Mkdirs();
}
var file = new Java.IO.File(fileDir, fileName);
System.IO.File.WriteAllBytes(file.Path, imageByte);
return file.Path;
}
public string CompressImage(string path)
{
byte[] imageBytes;
//Get the bitmap.
var originalImage = BitmapFactory.DecodeFile(path);
//Set imageSize and imageCompression parameters.
var imageSize = .86;
var imageCompression = 67;
//Resize it and then compress it to Jpeg.
var width = (originalImage.Width * imageSize);
var height = (originalImage.Height * imageSize);
var scaledImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, true);
using (MemoryStream ms = new MemoryStream())
{
scaledImage.Compress(Bitmap.CompressFormat.Jpeg, imageCompression, ms);
imageBytes = ms.ToArray();
}
originalImage.Recycle();
originalImage.Dispose();
GC.Collect();
return SaveFile(imageBytes, Guid.NewGuid().ToString());
}

How to make Generated gif in xamarin.ios slower?

I created a service used in my xamarin.forms project to generate a gif from four downloaded frame. The android side is working good, but I got a problem in iOs side, where gif is created but it's too fast, regardless of the set delay value. This is my class:
public class GifService : IGifService
{
public string CreateGif(string frame1Path, string frame2Path, string frame3Path, string frame4Path,string webId,string path="")
{
List<UIImage> listOfFrame = new List<UIImage>();
UIImage image1 = new UIImage(frame1Path);
listOfFrame.Add(image1);
UIImage image2 = new UIImage(frame2Path);
listOfFrame.Add(image2);
UIImage image3 = new UIImage(frame3Path);
listOfFrame.Add(image3);
UIImage image4 = new UIImage(frame4Path);
listOfFrame.Add(image4);
NSMutableDictionary fileProperties = new NSMutableDictionary();
fileProperties.Add(CGImageProperties.GIFLoopCount, new NSNumber(0));
NSMutableDictionary frameProperties = new NSMutableDictionary();
frameProperties.Add(CGImageProperties.GIFDelayTime, new NSNumber(5f));
NSUrl documentsDirectoryUrl = NSFileManager.DefaultManager.GetUrl(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User,null, true,out _);
NSUrl fileUrl = documentsDirectoryUrl.Append(webId + ".gif",false);
var destination = CGImageDestination.Create(fileUrl, MobileCoreServices.UTType.GIF, 4);
destination.SetProperties(fileProperties);
foreach(var frame in listOfFrame)
{
var cgImage = frame.CGImage;
if(cgImage!= null)
{
destination.AddImage(cgImage, frameProperties);
}
}
if (!destination.Close())
{
Console.WriteLine("Failed to finalize the image destination");
}
return fileUrl.Path;
}
}
I think that the problem is CGImageProperties.GIFDelayTime that is ignored, but i don't know why. How can I resolve this problem?
After some tries, I found finally a solution to generate a gif with a desired delay. I don't know why, but in the way i showed in my question, the options are ignored.
Here a working solution:
public class GifService : IGifService
{
public string CreateGif(string frame1Path, string frame2Path, string frame3Path, string frame4Path,string webId,string path="")
{
List<UIImage> listOfFrame = new List<UIImage>();
UIImage image1 = new UIImage(frame1Path);
listOfFrame.Add(image1);
UIImage image2 = new UIImage(frame2Path);
listOfFrame.Add(image2);
UIImage image3 = new UIImage(frame3Path);
listOfFrame.Add(image3);
UIImage image4 = new UIImage(frame4Path);
listOfFrame.Add(image4);
NSMutableDictionary fileProperties = new NSMutableDictionary
{
{ CGImageProperties.GIFLoopCount, new NSNumber(1) }
};
NSUrl documentsDirectoryUrl = NSFileManager.DefaultManager.GetUrl(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomain.User,null, true,out _);
NSUrl fileUrl = documentsDirectoryUrl.Append(webId + ".gif",false);
var destination = CGImageDestination.Create(fileUrl, MobileCoreServices.UTType.GIF, 4);
destination.SetProperties(fileProperties);
foreach (var frame in listOfFrame)
{
//difference is here, i create a var option and i set the
//GifDictionary
var options = new CGImageDestinationOptions();
options.GifDictionary = new NSMutableDictionary();
options.GifDictionary[CGImageProperties.GIFDelayTime] = new NSNumber(1f);
var cgImage = frame.CGImage;
if(cgImage!= null)
{
destination.AddImage(cgImage, options);
}
}
if (!destination.Close())
{
Console.WriteLine("Failed to finalize the image destination");
}
return fileUrl.Path;
}
}

Retrieving Images from Resource folder in C# windows form application

I am developing project in C# windows application. I am new to this technology. I declared Image variable in one class and list in another class. I want to retrieve image from Resource folder and store it in list ten times. I wrote code like this but it is returning null.
class clsAddImage
{
public Image m_imgSampleImage;
}
class clsList
{
public List<clsAddImage> lstImage = new List<clsAddImage>();
}
class clsAddImageToList
{
public void AddImgMethod()
{
clsList objlist = new clsList();
int i;
for (i = 0; i < 10; i++)
{
clsAddImage objaddimg = new clsAddImage();
objlist.lstImage.Add(objaddimg);
}
foreach (clsAddImage addimg in objlist.lstImage)
{
string path = "C:\\Users\\c09684\\Documents\\Visual Studio 2010\\Projects\\WindowsFormsAddImage\\WindowsFormsAddImage\\Resources\\Chrysanthemum.jpg";
addimg.m_imgSampleImage = Image.FromFile(path);
}
}
}
public Form1()
{
InitializeComponent();
clsAddImageToList a = new clsAddImageToList();
a.AddImgMethod();
}
I assume that you refer to a Windows8 app? In that case you can not simply program a directory to retrieve information. The user has to choose a directory manually, which you can store for future use. However, you can have access to KnownFolders (for most you have to check Capabilities in the Package.appxmanifest, e.g. Pictures Library), see http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.knownfolders for the options.
With the following task you will be able to retrieve files from a directory, I hope this helps you solving your problem:
public async Task GetFilesFromDisk()
{
StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
StringBuilder outputText = new StringBuilder();
IReadOnlyList<StorageFile> fileList = await picturesFolder.GetFilesAsync();
var images = new List<BitmapImage>();
if (fileList != null)
{
foreach (StorageFile file in fileList)
{
string cExt = file.FileType;
if (cExt.ToUpper() == ".JPG")
{
Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
using (Windows.Storage.Streams.IRandomAccessStream filestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
}
}
} // ForEach
}
}

Categories

Resources