Downloading image from web asychrounly in parallel ForEach loop - c#

Hi I would like download images from web asychrounly in parallel loop foreach.
I have dictionary with signature IDictionary<string,user>.
User class has two properties:
Uri ProfilePhoto
BitmapImage ProfilePhotoAsBitmapImage
My aim is, go through dictionary in loop if ProfilePhoto is null I get default avatar, it not I would like download image from web asynchronly.
private void GetProfilePhotosFromServer(IEnumerable<UserInfo> friends)
{
Parallel.ForEach(friends, f =>
{
//get defualt
if (f.ProfilePhoto == null)
f.ProfilePhotoAsBitmap = CreateDefaultAvatar(f.Sex);
//start downloading from web server asynchronly
//problem is that I don’t know how retrieve BitmapImage object from
//StartDownloading method or method ProcessImage, which is on the bottom
//of my question
var image = StartDownloadingImage(f.MediumProfilePhoto);
image.Freeze();
f.ProfilePhotoAsBitmap = image;
});
}
Problem is that I don’t know how retrieve BitmapImage object from StartDownloading method or method ProcessImage, which is on the bottom of my question.
Start web request:
private void StartDownloadingImage(Uri imageUri)
{
_webRequest = WebRequest.Create(imageUri);
_webRequest.BeginGetResponse(this.ProcessImage, null);
//how retrieve result of ProcessImage method
}
After web request is finished I call this method:
private void ProcessImage(IAsyncResult asyncResult)
{
var response = _webRequest.EndGetResponse(asyncResult);
using (var stream = response.GetResponseStream())
{
var buffer = new Byte[response.ContentLength];
int offset = 0, actuallyRead = 0;
do
{
actuallyRead = stream.Read(buffer, offset, buffer.Length - offset);
offset += actuallyRead;
}
while (actuallyRead > 0);
var image = new BitmapImage
{
CreateOptions = BitmapCreateOptions.None,
CacheOption = BitmapCacheOption.OnLoad
};
image.BeginInit();
image.StreamSource = new MemoryStream(buffer);
image.EndInit();
//problem
return image;
}
}
BitmapImage object is created in ProcessImage method how can I pass this object to the property od User object which is used in GetProfilePhotosFromServer method?
Method above create from MemoryStream BitampImage object.

You need to pass in the additional operations and the UserInfo object as a callback to the asynchronous method. The easiest way to do this is to create a class containing them and pass that as the asynchronous state of the method.
private class ImageCallbackState
{
public UserInfo Friend { get; set; }
public Action<UserInfo,BitmapImage> Callback { get; set; }
}
private void GetProfilePhotosFromServer(IEnumerable<UserInfo> friends)
{
Parallel.ForEach(friends, f =>
{
//get defualt
if (f.ProfilePhoto == null)
f.ProfilePhotoAsBitmap = CreateDefaultAvatar(f.Sex);
Action<UserInfo,BitmapImage> action = (u,i) => {
i.Freeze();
u.ProfilePhotoAsBitMap = i;
};
var state = new ImageCallbackState { Friend = f, Callback = action };
StartDownloadingImage(f.MediumProfilePhoto,state);
});
}
private void StartDownloadingImage(Uri imageUri, ImageCallbackState state)
{
_webRequest = WebRequest.Create(imageUri);
_webRequest.BeginGetResponse(this.ProcessImage, state); // pass callback state
}
private void ProcessImage(IAsyncResult asyncResult)
{
var response = _webRequest.EndGetResponse(asyncResult);
using (var stream = response.GetResponseStream())
{
var buffer = new Byte[response.ContentLength];
int offset = 0, actuallyRead = 0;
do
{
actuallyRead = stream.Read(buffer, offset, buffer.Length - offset);
offset += actuallyRead;
}
while (actuallyRead > 0);
var image = new BitmapImage
{
CreateOptions = BitmapCreateOptions.None,
CacheOption = BitmapCacheOption.OnLoad
};
image.BeginInit();
image.StreamSource = new MemoryStream(buffer);
image.EndInit();
var state = asyncResult.AsyncState as ImageCallbackState
state.Callback(state.Friend,image);
}
}

Related

How to create an image out of a custom control in Xamarin Forms? [duplicate]

Is there a package that does screen capture in xamarin.forms ?
I need also to capture google maps screen shots
Check out this blog post by Daniel Hindrikes.
I'm going to assume that you use a PCL for your shared code.
You will need to create an interface in your PCL. He calls it IScreenshotManager. The declaration looks like this:
public interface IScreenshotManager
{
Task<byte[]> CaptureAsync();
}
Now all platforms will have their own implementation for it.
For iOS;
public class ScreenshotManager : IScreenshotManager
{
public async System.Threading.Tasks.Task<byte[]> CaptureAsync()
{
var view = UIApplication.SharedApplication.KeyWindow.RootViewController.View;
UIGraphics.BeginImageContext(view.Frame.Size);
view.DrawViewHierarchy(view.Frame, true);
var image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
using(var imageData = image.AsPNG())
{
var bytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, bytes, 0, Convert.ToInt32(imageData.Length));
return bytes;
}
}
}
For Android:
public class ScreenshotManager : IScreenshotManager
{
public static Activity Activity { get; set; }
public async System.Threading.Tasks.Task<byte[]> CaptureAsync()
{
if(Activity == null)
{
throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
}
var view = Activity.Window.DecorView;
view.DrawingCacheEnabled = true;
Bitmap bitmap = view.GetDrawingCache(true);
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
And for Windows Phone:
public class ScreenshotManager : IScreenshotManager
{
public async Task<byte[]> CaptureAsync()
{
var rootFrame = Application.Current.RootVisual as PhoneApplicationFrame;
var screenImage = new WriteableBitmap((int)rootFrame.ActualWidth, (int)rootFrame.ActualHeight);
screenImage.Render(rootFrame, new MatrixTransform());
screenImage.Invalidate();
using (var stream = new MemoryStream())
{
screenImage.SaveJpeg(stream, screenImage.PixelWidth, screenImage.PixelHeight, 0, 100);
var bytes = stream.ToArray();
return bytes;
}
}
}
Don't forget to register your platform specific implementations with the attribute which registers it with the Dependency Service, like this:
[assembly: Xamarin.Forms.Dependency (typeof (ScreenshotManager))]
It goes above the namespace declaration.
Now from your shared code you would be able to get the byte[] of a screenshot with a call like this:
var screenshotBytes = DependencyService.Get<IScreenshotManager>().CaptureAsync();
You probably want to check if DependencyService.Get<IScreenshotManager>() isn't null before using it.
After that you can turn your byte[] into an image and do whatever you like with it!
Implementation for UWP
public async Task<byte[]> CaptureAsync()
{
//create and capture Window
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(Window.Current.Content);
var pixelpuffer = await renderTargetBitmap.GetPixelsAsync();
var logicalDpi = DisplayInformation.GetForCurrentView().LogicalDpi;
IRandomAccessStream stream = new InMemoryRandomAccessStream();
BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.BitmapTransform.InterpolationMode = BitmapInterpolationMode.Fant;
encoder.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, (uint)renderTargetBitmap.PixelWidth, (uint)renderTargetBitmap.PixelHeight, logicalDpi, logicalDpi, pixelpuffer.ToArray());
await encoder.FlushAsync();
byte[] resultingBuffer = new byte[stream.Size];
await stream.ReadAsync(resultingBuffer.AsBuffer(), (uint)resultingBuffer.Length, InputStreamOptions.None);
return resultingBuffer;
}

How to call dependency Injection screenshot code in my shared code?

I'm a beginner in Xamarin.Forms, and I have a question: How can I call the following code in my shared code/xaml.cs?
public class screenshotManager : IScreenshotManager
{
public static Activity Activity { get; set; }
public async System.Threading.Tasks.Task<byte[]> CaptureAsync()
{
if (Activity == null)
{
throw new Exception("You have to set ScreenshotManager.Activity in your Android project");
}
var view = Activity.Window.DecorView;
view.DrawingCacheEnabled = true;
Bitmap bitmap = view.GetDrawingCache(true);
byte[] bitmapData;
using (var stream = new MemoryStream())
{
bitmap.Compress(Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
return bitmapData;
}
}
If your need is to get the image captured from a byte[], as we discussed in comments, so you should do as #Jason said.
Something like this:
var imageBytes = await screenshotManager.CaptureAsync();
Image imageView = new Image();
imageView.Source = ImageSource.FromStream(() => new MemoryStream(imageBytes));

Load image from url to ImageView - C#

I want to load an image from url to imageview in c# ( android programming ) after search in google i cant find any good result , thank you for helping
i am using xamarin studio
The very first hit I got from Google was a thread on the Xamarin forums discussing this exact issue:
private Bitmap GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
using (var webClient = new WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
imageBitmap = BitmapFactory.DecodeByteArray(imageBytes, 0, imageBytes.Length);
}
}
return imageBitmap;
}
var imageBitmap = GetImageBitmapFromUrl("http://xamarin.com/resources/design/home/devices.png");
imagen.SetImageBitmap(imageBitmap);
Both approaches work, but is a good practice to do it asynchronously. Here you have some good examples:
Asynchronous Image Loading in Xamarin Android http://javatechig.com/xamarin/asynchronous-image-loading-xamarin-android
xamarin-store-app image helper https://github.com/xamarin/xamarin-store-app/blob/master/XamarinStore.Droid/Helpers/Images.cs
Am using the below class in Xamarin Android:
public class DownloadImageTask : AsyncTask
{
private ImageView bmImage;
private ProgressBar progressBar;
public DownloadImageTask( ImageView bmImage , ProgressBar progressBar)
{
this.bmImage = bmImage;
this.progressBar = progressBar;
}
protected override void OnPostExecute( Object result )
{
base.OnPostExecute(result);
bmImage.SetImageBitmap(( Bitmap ) result);
if (progressBar != null)
progressBar.Visibility = ViewStates.Gone;
}
protected override Object DoInBackground( params Object[] #params )
{
var urldisplay = #params[0].ToString();
Bitmap mIcon11 = null;
try
{
var req = WebRequest.Create(urldisplay);
var response = req.GetResponse();
var stream = response.GetResponseStream();
mIcon11 = BitmapFactory.DecodeStream(stream);
}
catch ( Exception e )
{
}
return mIcon11;
}
}
Execution :
new DownloadImageTask(imgProfile , progressBar).Execute(uri);
I did this to load an Svg from an url into an ImageView using SkiaSharp.
In the .xml
<ImageView
android:contentDescription=""
android:id="#+id/video_recorder_image"
android:layout_width="wrap_content"
android:layout_height="50dp" />
In the activity/fragment.
private ImageView iconImageView;
public override void OnViewCreated(View view, Bundle savedInstanceState)
{
iconImageView = (ImageView)view.FindViewById(Resource.Id.video_recorder_image);
Bitmap image = GetImageBitmapFromUrl(_iconUrl);
}
private Bitmap GetImageBitmapFromUrl(string url)
{
Bitmap imageBitmap = null;
using (var webClient = new WebClient())
{
var imageBytes = webClient.DownloadData(url);
if (imageBytes != null && imageBytes.Length > 0)
{
var svgContent = Convert.ToBase64String(imageBytes, 0, imageBytes.Length);
var byteArray = Convert.FromBase64String(svgContent);
using (var stream = new MemoryStream(byteArray))
{
var bitmap = new SKBitmap(500, 500);
var canvas = new SKCanvas(bitmap);
// load the SVG
var svg = new SkiaSharp.Extended.Svg.SKSvg(new SKSize(500, 500));
svg.Load(stream);
// draw the SVG to the bitmap
canvas.DrawPicture(svg.Picture);
var skData = SKImage.FromBitmap(bitmap).Encode(SKEncodedImageFormat.Png, 100);
// Convert image to string and then to Bitmap
var convertedSvgStream = skData.AsStream();
var convertedImageBytes = new byte[(int)convertedSvgStream.Length];
convertedSvgStream.Seek(0, SeekOrigin.Begin);
convertedSvgStream.Read(convertedImageBytes, 0, (int)convertedSvgStream.Length);
imageBitmap = BitmapFactory.DecodeByteArray(convertedImageBytes, 0, convertedImageBytes.Length);
}
}
}
return imageBitmap;
}

WP8 take picture with Nokia Imaging API (real time filter) and save to IsolatedStorage

I followed the examples here: http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj662940%28v=vs.105%29.aspx
I made the live preview and stuff work, but how can I take a picture? This is what i tried:
private PhotoCaptureDevice _photoCaptureDevice = null;
string strImageName = "IG_Temp";
private NokiaImagingSDKEffects _cameraEffect = null;
private MediaElement _mediaElement = null;
private CameraStreamSource _cameraStreamSource = null;
private Semaphore _cameraSemaphore = new Semaphore(1, 1);
MediaLibrary library = new MediaLibrary();
private async void ShutterButton_Click(object sender, RoutedEventArgs e)
{
if (_cameraSemaphore.WaitOne(100))
{
await _photoCaptureDevice.FocusAsync();
_cameraSemaphore.Release();
CameraCaptureSequence seq = _photoCaptureDevice.CreateCaptureSequence(1);
await seq.StartCaptureAsync();
MemoryStream captureStream1 = new MemoryStream();
// Assign the capture stream.
seq.Frames[0].CaptureStream = captureStream1.AsOutputStream();
try
{
// Set the position of the stream back to start
captureStream1.Seek(0, SeekOrigin.Begin);
// Save photo as JPEG to the local folder.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(strImageName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to the local folder.
while ((bytesRead = captureStream1.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
}
finally
{
// Close image stream
captureStream1.Close();
}
// Navigate to the next page
Dispatcher.BeginInvoke(() =>
{
NavigationService.Navigate(new Uri("/Edit.xaml?name=" + strImageName, UriKind.Relative));
});
}
}
But I will get an error:
System.InvalidOperationException
in line: await seq.StartCaptureAsync();
What am I doing wrong?

.Net Task reporting progress?

I have a task that runs that uploads a byte array through a web service. I want to report the progress whenever it hits 10, 20, 30, 40 etc percent. In order to update that in the DB though, i need to pass a guid to the web service to identify the file reporting progress. I cannot reach that object from inside the task though. Any ideas?
Entry point:
Guid smGuid;
smGuid = Guid.NewGuid();
Task t1 = new Task(action, pubAttFullPath);
t1.Start();
string attFullFilePath = System.IO.Path.GetFullPath(
mailItem.Attachments[i].FileName);
string attExtension = System.IO.Path.GetExtension(
mailItem.Attachments[i].FileName);
pubAttFullPath = attFullFilePath;
pubAttFileName = mailItem.Attachments[i].FileName;
Task Code:
Action<object> action = (object obj) =>
{
//Set filename from object
string FileName;
FileName = System.IO.Path.GetFileName(obj.ToString());
//Declare Web Service
TransferFile.TransferFile ws_TransferFile = new TransferFile.TransferFile();
//
bool transfercompleted = false;
using (FileStream fs = new FileStream(
obj.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
//Declare Buffers and Counts
byte[] buffer = new byte[49152];
long fileSize = fs.Length;
long totalReadCount = 0;
int readCount;
int currentPacketNumber = 0;
int percentageComplete = 0;
//Loop and copy file until it changes to not exactly the same byte count as the buffer
//which means the file is about to complete.
while ((readCount = fs.Read(buffer, 0, buffer.Length)) > 0)
{
if (!transfercompleted)
{
totalReadCount += readCount;
byte[] bytesToTransfer;
if (readCount == buffer.Length)
{
//Copy bytes until buffer is different
bytesToTransfer = buffer;
ws_TransferFile.WriteBinaryFile(bytesToTransfer, FileName);
percentageComplete = (int)(totalReadCount / (double)fileSize * 100);
}
else
{
// Only a part is requred to upload,
// copy that part.
List<byte> b = new List<byte>(buffer);
bytesToTransfer = b.GetRange(0, readCount).ToArray();
ws_TransferFile.WriteBinaryFile(bytesToTransfer, FileName);
percentageComplete = 100;
transfercompleted = true;
fs.Close();
break;
}
}
}
}
};
How about just passing it in as a bound variable?
Guid smGuid;
smGuid = Guid.NewGuid();
Task t1 = new Task( _ => action( smGuid, pubAttFullPath ), null );
t1.Start();
Task code:
Action<Guid, string> action = (smGuid, FileName) =>
{
//Declare Web Service
TransferFile.TransferFile ws_TransferFile = new TransferFile.TransferFile();
//
bool transfercompleted = false;
// And so on...
}

Categories

Resources