Generate a screenshot from an html page on Windows Azure - c#

I'm trying to generate a screenshot from a html page on windows Azure.
This is the code I was using on my personal IIS and I know it works on every test machine.
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
class Program
{
static void Main(string[] args)
{
new WebsiteToImage("http://www.google.com", "C:\\screenshot.jpg");
}
// Define other methods and classes here
public class WebsiteToImage
{
internal string _url;
internal string _fileName;
public WebsiteToImage(string url, string fileName)
{
_url = url;
_fileName = fileName;
// Thread
var thread = new Thread(Generate);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
private void Generate()
{
using (var browser = new WebBrowser { ScrollBarsEnabled = false })
{
browser.Navigate(_url);
browser.DocumentCompleted += WebBrowser_DocumentCompleted;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Dispose();
}
}
private void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
// Capture
using (var bmp = new Bitmap(1280, 800))
{
var browser = (WebBrowser)sender;
browser.ClientSize = new Size(1280, 800);
browser.ScrollBarsEnabled = false;
browser.BringToFront();
browser.DrawToBitmap(bmp, browser.Bounds);
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
bmp.Save(_fileName, ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID.Equals(ImageFormat.Jpeg.Guid)), encoderParameters);
}
}
}
}
Now, on Azure I know I can't use GDI+ and I'm pretty sure I can't also use WebBrowser.
Any idea or alternative solution? Even third part component.

You haven't said whether you're using Azure Web Sites or Azure Cloud Services, but from what you say about not being able to use GDI+, I'm guessing Web Sites?
You should certainly be able to run your code in a Cloud Service, either a Web or Worker role. If the code is part of a web application hosted on Web Sites, you can use an Azure Storage Queue to add the URL to be snap-shotted, then poll that queue on a worker role, run your code, and store the resulting file into Blob storage.
If your expected load on the screen-shot server is low, you could probably get away with an Extra-Small instance, which would cost very little.

Update: Awesomium should be an option in this case.

I found Is there a webservice/API to grab a screenshot of another website? and from there this service that do the task with an open source code. For the light use we're planning to do, this is better than a custom implemented solution.

Related

Windows FolderPicker stopped working after updating to Windows 10.0.18362

I have code that was using the windows FolderPicker. After updating to Windows version 10.0.18362, my use of the FoldePicker has stopped working.
I have attached some code that I used in order to get the access to file is denied result.
using System;
using System.IO;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Storage.Pickers;
using Windows.Storage;
using Windows.Storage.AccessCache;
namespace FolderPickerTest
{
public sealed partial class MainPage : Page
{
private static string path = #"filepath";
string[] lines;
public MainPage()
{
this.InitializeComponent();
test();
}
public async void test()
{
var folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.Desktop;
folderPicker.FileTypeFilter.Add("*");
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
}
}
private void open_click(object sender, RoutedEventArgs e)
{
lines = new string[2];
try
{
lines = File.ReadAllLines(path);
}
catch(Exception ex)
{
errorText.Text = ($"Error: {ex.Message.ToString()}");
}
}
}
}
The error message that I am currently getting is:
Access to the path 'filepath' is denied
The problem here is that you are trying to read an arbitrary path using System.IO APIs. In one of the releases this was actually working when you declared the broadFileSystemAccess capability, but this is no longer the case. You now must use the StorageFile APIs to achieve your goal.
If you pick a folder with FolderPicker, you get a StorageFolder instance back. You can call GetFileAsync method on this instance to get a file by name. This is an instance of StorageFile which you can read using FileIO.ReadLinesAsync method.
To explain better the answer of Martin Zikmund, in Win 10 1803 (april 2018), broadFileSystemAccess capability was set automatically to ON in the user Settings.
Starting from Win 10 1809 (October 2018), this System setting is set to OFF by default.
You need to ask the user to explicitly set the setting ON in the Settings app, even by referencing the specific setting page directly.

C# CefSharp is not saving or loading any caches

I cannot save or load the cache data from my CefSharp browser application.
I tried adding cefSet.CefCommandLineArgs.Add("renderer-process-limit", "1"); after seeing it got suggested alot, same with cefSet.CachePath = //cache directory as string non of them worked, i personally believe that it might be connected to another problem im having which is cef always thinking that its already initialized even after i just open the computer and program can't start without i put this part to the code:
if (Cef.IsInitialized == false)
{
Cef.Initialize(cefSet, performDependencyCheck: true, browserProcessHandler: null);
}
Which means its possibly never initialising, but at the same logically it can't open without initialising when the pc just got open. But since there is no confirmation on initialising being the the exact problem i wanted to ask in a rather open way.
//created chromiumWebBrowser1 on the form
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
private void Form2_Load(object sender, EventArgs e)
{
CefSettings cefSet = new CefSettings();
cefSet.CachePath = curDir + #"\cch";
cefSet.CefCommandLineArgs.Add("renderer-process-limit", "1");
if (Cef.IsInitialized == false)
{
Cef.Initialize(cefSet, performDependencyCheck: true, browserProcessHandler: null);
}
chromiumWebBrowser1.Controls.Add(browser);
}
public static string curDir = Directory.GetCurrentDirectory();
public static string gameLoc = "file:///" + curDir + "/test.html";
public static ChromiumWebBrowser browser = new ChromiumWebBrowser(gameLoc,new RequestContext());
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Cef.Shutdown();
}
I expected some cache files in my folder as im using the application and after using it. tried with few sites and nothing on cache so far.

Image dimensions getting corrupted using ImageResizer with Azure function app

I have a azure function app with one input and two outputs. In this case whenever an image is uploaded to a container: originals, the function app will be triggered which will generate two thumbnail images.
I developed the following function app using VS2017 and deployed to Azure portal.
Code:
using ImageResizer;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using System;
using System.Collections.Generic;
using System.IO;
namespace FunctionApp1
{
public static class Function1
{
[FunctionName("Function1")]
public static void Run(
[BlobTrigger("originals/{name}", Connection = "xxxxxxx")]Stream image,
[Blob("thumbs/s-{name}", FileAccess.ReadWrite, Connection = "xxxxxxx")]Stream imageSmall,
[Blob("thumbs/m-{name}", FileAccess.ReadWrite, Connection = "xxxxxxx")]Stream imageMedium,
TraceWriter log)
{
var imageBuilder = ImageResizer.ImageBuilder.Current;
var size = imageDimensionsTable[ImageSize.Small];
imageBuilder.Build(
image, imageSmall,
new ResizeSettings(size.Item1, size.Item2, FitMode.Max, null), false);
image.Position = 0;
size = imageDimensionsTable[ImageSize.Medium];
imageBuilder.Build(
image, imageMedium,
new ResizeSettings(size.Item1, size.Item2, FitMode.Max, null), false);
}
public enum ImageSize
{
ExtraSmall, Small, Medium
}
private static Dictionary<ImageSize, Tuple<int, int>> imageDimensionsTable = new Dictionary<ImageSize, Tuple<int, int>>()
{
{ ImageSize.ExtraSmall, Tuple.Create(320, 200) },
{ ImageSize.Small, Tuple.Create(640, 400) },
{ ImageSize.Medium, Tuple.Create(800, 600) }
};
}
}
On validating it, I found that it is generating two different images as per requirement, but I see one of the file is corrupted.
CorrectImage:
CorruptedImage:
I did the validation for multiple images but see the same issue. The image with medium size configuration always gets corrupted.
Any rectifications to the above code is much helpful.
Can anyone help me to fix this issue?
Can you please check is there any other function app already in running status. In short I would like to say that check all the function apps that you have developed in this process, which is monitoring the blob storage container. I suspect that some other function app is getting triggered and causing the issue here. Please stop all the function apps and only run the required function app to see if it resolves your issue. Please let me know in case you need any further help on this.

Capturing Image in Windows Service c#

I need to create an Windows Service that will capture images from camera. After serching the internet, i do not find any similar project. I decided to use Aforge.net but got stuck in how to capture image because the Bitmap is not supported in windows Service.
here is my code so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Deployment;
using System.Runtime.InteropServices;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Imaging;
namespace PCSecurityCamera
{
partial class PCSecurityCamera : ServiceBase
{
System.Timers.Timer timeDelay;
string pixDrive = "", journalLoc = "", txnDate = "", txnTime = "", txnDate1 = "";
int retVal, timeFrame = 0, count = 0, txn_count = 0, retention = 0;
string picdirectory;
int i = 0;
string[] availableCameras = new string[5];
private FilterInfoCollection VideoCaptureDevices; //stores all available camera
private VideoCaptureDevice FinalVideoSource; //stores camera to be used
public PCSecurityCamera()
{
InitializeComponent();
timeDelay = new System.Timers.Timer();
timeDelay.Elapsed += new System.Timers.ElapsedEventHandler(WorkProcess);
}
public void WorkProcess(object sender, System.Timers.ElapsedEventArgs e)
{
}
protected override void OnStart(string[] args)
{
// TODO: Add code here to start your service.
LogService("PCSecuritycamera Service is Started");
try
{
int camCount = 0;
Array.Clear(availableCameras,0,availableCameras.Length);
VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach(FilterInfo VideoCaptureDevice in VideoCaptureDevices)
{
availableCameras[camCount] = VideoCaptureDevice.Name.ToString();
LogService(availableCameras[camCount]);
camCount++;
}
if (availableCameras[0] == "")
{
LogService("No Available Camera");
}
else
{
FinalVideoSource = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
LogService("Camera Selected: " + FinalVideoSource.ToString());
FinalVideoSource.NewFrame +=FinalVideoSource_NewFrame;
}
}
catch (Exception e)
{
LogService(e.ToString());
}
timeDelay.Enabled = true;
}
private void FinalVideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
LogService("Service Stoped");
timeDelay.Enabled = false;
}
private void LogService(string content)
{
FileStream fs = new FileStream(#"C:\Users\talatj\Desktop\Me\ServiceLog.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(content);
sw.Flush();
sw.Close();
}
}
}
my problem is how to capture the image in windows service.
Please help
System.Drawing Namespace
Classes within the System.Drawing namespace are not supported for use
within a Windows or ASP.NET service. Attempting to use these classes
from within one of these application types may produce unexpected
problems, such as diminished service performance and run-time
exceptions. For a supported alternative, see Windows Imaging
Components.
GDI+
GDI+ functions and classes are not supported for use within a Windows
service. Attempting to use these functions and classes from a Windows
service may produce unexpected problems, such as diminished service
performance and run-time exceptions or errors
HOWEVER!
System.Drawing does work in Services, it's just not supported. There can be issues with high load (running out of unmanaged resources), memory or resource leaks (badly implemented or called dispose patterns)
My suspicions is you have just not referenced the System.Drawing.dll
Note : You will just have to be wary and do this on a trial and error basis, though IMO saving bitmaps should be fine

winform Close self plus another WebBrowserControl

i know i could search proccessId / name of running tasks and kill processes i need .
though till now i was not developing schedualed tasks / self executble Applications,
so i didn't need to know how to make the application close itself after execition
trying to close everything (including WebDriver) via Application.Exit + OR this.Close()
right after i have got what i was looking for. mission Complete .
please close ... no more work for you .
but mr . Program.cs still needs somthing from Form1.
saying somthing about
Cannot access a disposed object.
Object name: 'Form1'.
any combination of both was returning in some point an exeption error
(from program.cs ) even though mission complete . no more code was requested .(?) by me..atleast.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using OpenQA.Selenium;
using OpenQA.Selenium.IE;
using System.IO;
namespace HT_R_WbBrows2
{
public partial class Form1 : Form
{
public IeEnginGenerator Iengn = new IeEnginGenerator();
public Form1()
{
InitializeComponent();
//setLogView(View.Details);
string extractededVal = Iengn.ExtractPageValue(Iengn.itrfWebEng);
string flnm = #" the directory path to file --> \dolarRate.asp";
File.WriteAllText(fn, extractededVal);
this.Close();
Application.Exit();
}
public class IeEnginGenerator
{
private string directory = Environment.CurrentDirectory;///Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase);
public IWebDriver IwebEngine;
public List<string> ListElementsInnerHtml = new List<string>();
public HtmlAgilityPack.HtmlDocument Dnetdoc = new HtmlAgilityPack.HtmlDocument();
#region <<=========== setupDriver ============>>
public string ExtractPageValue(IWebDriver DDriver, string url="")
{
if(string.IsNullOrEmpty(url))
url = #"http://www.boi.org.il/he/Markets/ExchangeRates/Pages/Default.aspx";
var service = InternetExplorerDriverService.CreateDefaultService(directory);
service.LogFile = directory + #"\seleniumlog.txt";
service.LoggingLevel = InternetExplorerDriverLogLevel.Trace;
var options = new InternetExplorerOptions();
options.IntroduceInstabilityByIgnoringProtectedModeSettings = true;
DDriver = new InternetExplorerDriver(service, options, TimeSpan.FromSeconds(60));
DDriver.Navigate().GoToUrl(url);
Dnetdoc.LoadHtml(DDriver.PageSource);
string Target = Dnetdoc.DocumentNode.SelectNodes("//table//tr")[1].ChildNodes[7].InnerText;
//.Select(tr => tr.Elements("td").Select(td => td.InnerText).ToList())
//.ToList();
return Math.Round(Convert.ToDouble(Target), 2).ToString();
//return "";//Math.Round(Convert.ToDouble( TempTxt.Split(' ')[10]),2).ToString();
}
#endregion
}
}
}
Why use a winform application? A Console application would probably suffice for what you are doing. Once Main() ends your app will close as well. Main() never ends in a winform app because of the applications runloop.
Edit:
Here would be the correct way to do this. You need to register to the forms Load event and run your code there, not in the constructor. You can't close a winform from inside a constructor.
Edit 2: Put this code in the Form1() constructor. Somewhere after InitializeComponent();
this.Load += (sender,args)=>{ /*do all your work here*/
string extractededVal = Iengn.ExtractPageValue(Iengn.itrfWebEng);
string flnm = #" the directory path to file --> \dolarRate.asp";
File.WriteAllText(fn, extractededVal);
Application.Exit();
};

Categories