I need to create a bitmap from an html string using the CefSharp.OffScreen.ChromiumWebBrowser.
var browser = new CefSharp.OffScreen.ChromiumWebBrowser(htmlString);
// what to do?
var bitmap = browser.Bitmap;
What do I have to do to get the bitmap?
Passing the URL and not the html string to the ChromiumWebBrowser and waiting for the browser to finish loading the html file solves this problem:
var browser = new CefSharp.OffScreen.ChromiumWebBrowser(htmlURL);
// wait the browser to finish loading the html file
using (var waitHandle = new System.Threading.AutoResetEvent(false))
{
EventHandler<LoadingStateChangedEventArgs> loadingHandler = null;
loadingHandler = (sender, e) =>
{
if (!e.IsLoading)
{
if (browser != null)
{
browser.LoadingStateChanged -= loadingHandler;
}
waitHandle.Set();
}
};
browser.LoadingStateChanged += loadingHandler;
waitHandle.WaitOne();
}
var bitmap = browser.Bitmap; // bitmap not null
Related
private static void StartBrowser(string source)
{
var th = new Thread(() =>
{
var webBrowser = new WebBrowser();
webBrowser.ScrollBarsEnabled = false;
webBrowser.DocumentCompleted += webBrowser_DocumentCompleted;
webBrowser.DocumentText = source;
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
static void webBrowser_DocumentCompleted(object sender,WebBrowserDocumentCompletedEventArgs e)
{
var webBrowser = (WebBrowser)sender;
using (Bitmap bitmap = new Bitmap(576,384))
{
webBrowser.DrawToBitmap(bitmap,new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.Save(#"images/" + "xxx.jpg",System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
Hi Guys,
I am trying to print out an HTML file in a windows service by using the windows application web browser. For some reason, I cannot get a clear image, it draws only 25% of the image.
Note:- There is a barcode image in the upper right corner.
I am making a Native IOS app using C#. I have a registration form and i am sending form data with image. but i am unable to send image as my UIImage control does not contains its path or name.I am sending Form to web api in multipart . text field data is uploading but image is not being upoloaded .
Here's how you can pick image from Camera/Gallery onto an UIImageView, and then upload;
Use UIImagePickerController for selecting image from Gallery/Camera
UIImagePickerController galleryImagePicker;
UIImagePickerController cameraImagePicker;
Use the below function on clicking a button or on your ImageView to bring a pop for to select between Camera/Gallery:
void ShowSelectPicPopup ()
{
var actionSheetAlert = UIAlertController.Create ("Select picture",
"Complete action using", UIAlertControllerStyle.ActionSheet);
actionSheetAlert.AddAction (UIAlertAction.Create ("Camera",
UIAlertActionStyle.Default, (action) => HandleCameraButtonClick ()));
actionSheetAlert.AddAction (UIAlertAction.Create ("Gallery",
UIAlertActionStyle.Default, (action) => HandleGalleryButtonClick ()));
actionSheetAlert.AddAction (UIAlertAction.Create ("Cancel", UIAlertActionStyle.Cancel,
(action) => Console.WriteLine ("Cancel button pressed.")));
// Required for iPad - You must specify a source for the Action Sheet since it is
// displayed as a popover
var presentationPopover = actionSheetAlert.PopoverPresentationController;
if (presentationPopover != null) {
presentationPopover.SourceView = View;
presentationPopover.PermittedArrowDirections = UIPopoverArrowDirection.Up;
}
PresentViewController (actionSheetAlert, true, null);
}
Now the actions:
void HandleGalleryButtonClick ()
{
if (galleryImagePicker == null) {
galleryImagePicker = new UIImagePickerController ();
galleryImagePicker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
galleryImagePicker.MediaTypes = UIImagePickerController.AvailableMediaTypes (UIImagePickerControllerSourceType.PhotoLibrary);
galleryImagePicker.FinishedPickingMedia += Handle_FinishedPickingMedia;
galleryImagePicker.Canceled += Handle_Canceled;
}
PresentViewController (galleryImagePicker, true, () => { });
}
void HandleCameraButtonClick ()
{
if (cameraImagePicker == null) {
cameraImagePicker = new UIImagePickerController ();
cameraImagePicker.PrefersStatusBarHidden ();
cameraImagePicker.SourceType = UIImagePickerControllerSourceType.Camera;
cameraImagePicker.FinishedPickingMedia += Handle_FinishedPickingCameraMedia;
cameraImagePicker.Canceled += Handle_CameraCanceled;
}
PresentViewController (cameraImagePicker, true, () => { });
}
void Handle_Canceled (object sender, EventArgs e)
{
galleryImagePicker.DismissViewController (true, () => { });
}
protected void Handle_FinishedPickingMedia (object sender, UIImagePickerMediaPickedEventArgs e)
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info [UIImagePickerController.MediaType].ToString ()) {
case "public.image":
Console.WriteLine ("Image selected");
isImage = true;
break;
case "public.video":
Console.WriteLine ("Video selected");
break;
}
// get common info (shared between images and video)
var referenceURL = e.Info [new NSString ("UIImagePickerControllerReferenceUrl")] as NSUrl;
if (referenceURL != null)
Console.WriteLine ("Url:" + referenceURL);
// if it was an image, get the other image info
if (isImage) {
// get the original image
var originalImage = e.Info [UIImagePickerController.OriginalImage] as UIImage;
if (originalImage != null) {
// do something with the image
Console.WriteLine ("got the original image");
Picture.Image = originalImage; // Picture is the ImageView
picAssigned = true;
}
} else { // if it's a video
// get video url
var mediaURL = e.Info [UIImagePickerController.MediaURL] as NSUrl;
if (mediaURL != null) {
Console.WriteLine (mediaURL);
}
}
// dismiss the picker
galleryImagePicker.DismissViewController (true, () => { });
}
protected void Handle_FinishedPickingCameraMedia (object sender, UIImagePickerMediaPickedEventArgs e)
{
// determine what was selected, video or image
bool isImage = false;
switch (e.Info [UIImagePickerController.MediaType].ToString ()) {
case "public.image":
Console.WriteLine ("Image selected");
isImage = true;
break;
case "public.video":
Console.WriteLine ("Video selected");
break;
}
// get common info (shared between images and video)
var referenceURL = e.Info [new NSString ("UIImagePickerControllerReferenceUrl")] as NSUrl;
if (referenceURL != null)
Console.WriteLine ("Url:" + referenceURL);
// if it was an image, get the other image info
if (isImage) {
// get the original image
var originalImage = UIHelper.RotateCameraImageToProperOrientation (e.Info [UIImagePickerController.OriginalImage] as UIImage, 320);
if (originalImage != null) {
// do something with the image
Console.WriteLine ("got the original image");
Picture.Image = originalImage; // display
picAssigned = true;
}
} else { // if it's a video
// get video url
var mediaURL = e.Info [UIImagePickerController.MediaURL] as NSUrl;
if (mediaURL != null) {
Console.WriteLine (mediaURL);
}
}
// dismiss the picker
cameraImagePicker.DismissViewController (true, () => { });
}
void Handle_CameraCanceled (object sender, EventArgs e)
{
cameraImagePicker.DismissViewController (true, () => { });
}
You may need to add following two permissions in your Info.plist to access Camera/Gallery
Privacy - Camera Usage Description
Privacy - Photo Library Usage Description
They're both String, and Value can be something like "YourAppName needs access to use your camera"
And finally to upload image as multipart:
First convert the image to byte array
public static byte[] ConvertImageToByteArray(UIImage Picture) {
byte [] image = null;
try {
using (NSData imageData = Picture.Image.AsJPEG (0.5f)) { // Here you can set compression %, 0 = no compression, 1 = max compression, or the other way around, I'm not sure
image = new byte [imageData.Length];
Marshal.Copy (imageData.Bytes, image, 0, Convert.ToInt32 (imageData.Length));
} catch (Exception e) {
Console.WriteLine ("Error # Picture Byte Conversion: " + e.Message);
}
return image;
}
And finally to post the image, I use modernhttpclient
public async Task PostPicture (byte [] image)
{
try {
string url = .....;
var requestContent = new MultipartFormDataContent ();
ByteArrayContent content = content = new ByteArrayContent (image);
content.Headers.ContentType = MediaTypeHeaderValue.Parse ("image/jpeg");
requestContent.Add (content, "file", "post" + DateTime.Now + ".jpg"); // change file name as per your requirements
string result = await HttpCall.PostMultiPartContent (url, requestContent, null);
} catch (Exception ex) {
System.Diagnostics.Debug.WriteLine (ex.Message);
}
}
public class HttpCall
{
public static async Task<string> PostMultiPartContent (string url, MultipartFormDataContent content, Action<int> progressAction) // Here you can pass an handler to keep track of the upload % in your UI, I'm passing null above. (Not keeping track)
{
try {
var request = new HttpRequestMessage (HttpMethod.Post, url);
var progressContent = new ProgressableStreamContent (content, 4096, (sent, total) => {
var percentCompletion = (int)(((double)sent / total) * 100);
System.Diagnostics.Debug.WriteLine ("Completion: " + percentCompletion);
if (progressAction != null)
progressAction (percentCompletion);
});
request.Content = progressContent;
var client = new HttpClient();
var response = await client.SendAsync (request);
string result = await response.Content.ReadAsStringAsync ();
System.Diagnostics.Debug.WriteLine ("PostAsync: " + result);
return result;
} catch (Exception e) {
System.Diagnostics.Debug.WriteLine (e.Message);
return null;
}
}
}
I'm making a WPF application where I use WebClient to download files form a webserver. I have a list of URL's with all the files i have to download. I use a foreach to loop through every URL and download each one at the time. The first URL much be completed before moving to the next one. I know the size of each file. Is there a way where I can set my e.ProgressPercentage to know the size of all files instead of loading from 0 to 100% for each file. I know that I'm calling DownloadProtocol for each URL right now, which makes a new instance of WebClient, but it is the only way I can think of to fulfill my solution, which is to download one file at a time.
public DownloadStart()
{
foreach(var url in ListOfDownloadURL)
{
DownloadGameFile dlg = new DownloadGameFile();
await dlg.DownloadProtocol(url, myLocation);
}
}
Download function in DownloadGameFile class:
public async Task DownloadProtocol(string address, string location)
{
Uri Uri = new Uri(address);
using (WebClient client = new WebClient())
{
//client.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
//client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
client.DownloadProgressChanged += (o, e) =>
{
Console.WriteLine(e.BytesReceived + " " + e.ProgressPercentage);
//ProgressBar = e.ProgressPercentage (total)
};
client.DownloadFileCompleted += (o, e) =>
{
if (e.Cancelled == true)
{
Console.WriteLine("Download has been canceled.");
}
else
{
Console.WriteLine("Download completed!");
}
};
await client.DownloadFileTaskAsync(Uri, location);
}
}
Why not take the easy way out and just update the progress when file is completed? Something like...
ProgressBar p = new ProgressBar();
p.Maximum = ListOfDownloadURL.Count();
foreach(var url in ListOfDownloadURL)
{
DownloadGameFile dlg = new DownloadGameFile();
await dlg.DownloadProtocol(url, myLocation);
p.Value += 1;
}
Or if you insist, you could query file sizes before you begin downloading, sum total bytes of all the files and then calculate the percentage when ever DownloadProgressChanged is fired.
var bytes = Convert.ToInt64(client.ResponseHeaders["Content-Length"]);
In WinRT app I have one FlipView myFlipView with some pictures and one Image myImage. On myFlipView's event SelectionChanged there is the following method:
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
To sum up it finds uri of current image in myFlipView and set that image in myImage but with some modifications defined in ModifyPicture. It works perfectly on tablets but on computers with mouses there is one error. When I click arrows attached to FlipView very fast then myImage shows wrong picture. For example if in myFlipView I have 10 pictures (p1, p2, ..., p10) and currently p1 is chosen, when I change to p2 on myImage also p2 appears. But when I click very fast sometimes in FlipView I have for example p9 and in myImage p8. I suppose it is connected with fact that method is called many times but I don't know how to fix it. Thank you in advance for help :)
You should probably save the Task/IAsyncOperation that's already running and cancel it if the event handler is called again before it completes.
See this article on how to cancel running tasks.
Pseudo-code (as I don't know C#):
Task loadAndSetImage(uri) {
return new Task...
}
flipView_SelectionChanged {
if (myFlipView == null) return;
if (this.runningTask && !this.runningTask.IsCanceled) {
this.runningTask.Cancel();
}
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
this.runningTask = loadAndSetImage(newUri);
this.runningTask.ContinueWith( (t) => this.runningTask = null; );
}
In addition to or instead of cancelling internal tasks as ma_il mentions - you could break/cancel your async method execution if you detect that it should be canceled. E.g.
private int myFlipView_SelectionChangedCallId;
async private void myFlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (myFlipView == null) return;
var callId = ++myFlipView_SelectionChangedCallId;
Uri newUri = new Uri("ms-appx://" + (((BitmapImage)(((Image)(((ContentControl)(myFlipView.SelectedItem)).Content)).Source)).UriSource.AbsolutePath));
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(newUri);
if (callId != myFlipView_SelectionChangedCallId) return;
WriteableBitmap wb = new WriteableBitmap(1, 1);
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
await wb.SetSourceAsync(fileStream);
if (callId != myFlipView_SelectionChangedCallId) return;
}
}
wb = ModifyPicture(wb);
myImage.Source = wb;
}
Also if your ModifyPicture method does any heavy pixel processing - you would want to run it on a background thread and await it.
I have a collection of picture Objects for which I need to download thumbs and pictures files located on dataservise, how can I managed this?
In this method I have loop to call three methods; one to add objects to data base, second to download and save picture thumb and third to download and save picture file the other two is ClientOpenReadCompleted methods.
public bool AddAllPhoto()
{
var amount = App.ViewModel.NewPictures.Count;
for (int i = 0; i < amount; i++)
{
//to add picture to DB
SavePicture(App.ViewModel.NewPictures[i]);
DownloadPicture(NewPictures[i].ID.ToString());
DownloadPictureThumb(NewPictures[i].ID.ToString()));
}
return true;
}
Second;
public void DownloadPictureThumb(string path)
{
string outputString = String.Format("http://" + App.ServerAdress + "/ /Pictures/Thumbs/{0}.jpg", path);
var client = new WebClient();
client.OpenReadCompleted += ClientOpenReadCompleted1;
client.OpenReadAsync(new Uri(outputString));
}
private static void ClientOpenReadCompleted1(object sender, OpenReadCompletedEventArgs e)
{
var resInfo = new StreamResourceInfo(e.Result, null);
var reader = new StreamReader(resInfo.Stream);
byte[] contents;
using (var bReader = new BinaryReader(reader.BaseStream))
{
contents = bReader.ReadBytes((int)reader.BaseStream.Length);
}
var file = IsolatedStorageFile.GetUserStoreForApplication();
var thumbFilePath = String.Format(PicturesThumbsColectionKey + "{0}", PictureDataStoreLocal.ID);
var stream = thumbFile.CreateFile(thumbFilePath);
stream.Write(contents, 0, contents.Length);
stream.Close();
}
And third one
public void DownloadPicture(string path)
{
string outputString = String.Format("http://" + App.ServerAdress + "/Pictures/{0}.jpg", path);
var client = new WebClient();
client.OpenReadCompleted += ClientOpenReadCompleted1;
client.OpenReadAsync(new Uri(outputString));
}
private static void ClientOpenReadCompleted1(object sender, OpenReadCompletedEventArgs e)
{
var resInfo = new StreamResourceInfo(e.Result, null);
var reader = new StreamReader(resInfo.Stream);
byte[] contents;
using (var bReader = new BinaryReader(reader.BaseStream))
{
contents = bReader.ReadBytes((int)reader.BaseStream.Length);
}
var file = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = file.CreateFile(PictureDataStoreLocal.ID.ToString());
stream.Write(contents, 0, contents.Length);
stream.Close();
}
I assume you want to process the pictures synchronously. If so I would use a wait handle. The easiest way to do this would be to declare a private AutoResetEvent field. The AutoResetEvent is good here because it just lets one thread through and then blocks again automatically.
If you do this you will need to make sure of two things:
1. You do ALL work on a different thread so that when you call WaitOne() you aren't blocking the thread that is supposed to be doing the work.
2. You always reset the wait handle regardless of the outcome of the server calls.
To take care of 1. you just need to update your loop:
m_waitHandle.Reset(); // Make sure the wait handle blocks when WaitOne() is called
for (int i = 0; i < amount; i++)
{
// Process on a background thread
ThreadPool.QueueUserWorkItem((obj) =>
{
// Get the current index. This is an anonymous method so if
// we use 'i' directly we will not necessarily be using the
// correct index. In our case the wait handle avoids this
// problem as the pictures are downloaded one after the other
// but it's still good practise to NEVER use a loop variable in
// an anonymous method.
int index = (int)obj;
//to add picture to DB
SavePicture(App.ViewModel.NewPictures[index]);
DownloadPicture(NewPictures[index].ID.ToString());
DownloadPictureThumb(NewPictures[index].ID.ToString()));
}, i);
m_waitHandle.WaitOne(); // Wait for processing to finish
}
For 2. you need to make sure that m_waitHandle.Set() is ALWAYS called when processing is finished.
What I do is send extra parameters to the OpenReadCompleted event using a delegate like so,
someimage.LoadingCompleted += delegate(object sender, EventArgs imge) { someimage_LoadingCompleted(sender, imge, _item, "someimage"); };
and then in someimage_LoadingCompleted I have code within a switch statement.
Here is my solution, not that elegant but working one; If you have any suggestion to improve , please post and I will edit my post.
EventWaitHandle m_WaitHandle;
public bool AddAllPhoto()
{
var amount = App.ViewModel.NewPictures.Count;
if (m_WaitHandle!=null)
m_WaitHandle.Reset();
for (int i = 0; i < amount; i++)
{
{
SavePicture(App.ViewModel.NewPictures[i]);
ThreadPool.QueueUserWorkItem((obj) =>
{
var index = (int)obj;
DownloadPictureThumb(App.ViewModel.NewPictures[index].ID.ToString());
DownloadPicture(App.ViewModel.NewPictures[index].ID.ToString());
},i);
if (m_WaitHandle != null) m_WaitHandle.WaitOne();
}
return true;
}
public void DownloadPictureThumb(string path)
{
string outputString = String.Format("http://" + App.ServerAdress + "/Pictures/Thumbs/{0}.jpg", path);
var client = new WebClient();
client.OpenReadCompleted += ClientOpenReadCompleted2;
client.OpenReadAsync(new Uri(outputString),path);
}
private static void ClientOpenReadCompleted2(object sender, OpenReadCompletedEventArgs e)
{
var resInfo = new StreamResourceInfo(e.Result, null);
var reader = new StreamReader(resInfo.Stream);
byte[] contents;
using (var bReader = new BinaryReader(reader.BaseStream))
{
contents = bReader.ReadBytes((int)reader.BaseStream.Length);
}
var file = IsolatedStorageFile.GetUserStoreForApplication();
var thumbFilePath = String.Format(PicturesThumbsColectionKey + "{0}", e.UserState as string);
var stream = file.CreateFile(thumbFilePath);
stream.Write(contents, 0, contents.Length);
stream.Close();
}
public void DownloadPicture(string path)
{
string outputString = String.Format("http://" + App.ServerAdress + "/Pictures/{0}.jpg", path);
var client = new WebClient();
client.OpenReadCompleted += ClientOpenReadCompleted1;
client.OpenReadAsync(new Uri(outputString), path);
}
private static void ClientOpenReadCompleted1(object sender, OpenReadCompletedEventArgs e)
{
var resInfo = new StreamResourceInfo(e.Result, null);
var reader = new StreamReader(resInfo.Stream);
byte[] contents;
using (var bReader = new BinaryReader(reader.BaseStream))
{
contents = bReader.ReadBytes((int)reader.BaseStream.Length);
}
var file = IsolatedStorageFile.GetUserStoreForApplication();
var stream = file.CreateFile(e.UserState as string);
stream.Write(contents, 0, contents.Length);
stream.Close();
}
[Here][1] you will find explanation to how to get the url from WebClient in OpenReadCompleted?