diff --git a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm index 0492a426c..c4201e3f4 100644 --- a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm @@ -3,12 +3,12 @@
Local File:
- +
From web:
- +
GIF: @@ -21,6 +21,6 @@

- + \ No newline at end of file diff --git a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm index d8b98e9ba..7ead83afe 100644 --- a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm @@ -26,10 +26,10 @@

metus. Integer leo dolor, tristique a, dignissim ac, iaculis eget, elit. Donec arcu.

The image should also be limited by size because it has: style="width:90%"
- - + +

- +

diff --git a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm index a7cd2582c..4c11cb2d4 100644 --- a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm @@ -2,102 +2,102 @@

Contains many images that should not load until in scroll view

Image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- +

Another image

- + \ No newline at end of file diff --git a/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs index 3e1c05114..983c888e8 100644 --- a/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs +++ b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs @@ -24,7 +24,7 @@ public async Task GenerateSampleAsync(HtmlSample sample) config.MarginTop = 0; config.MarginBottom = 0; - var pdf = await PdfGenerator.GeneratePdfAsync(sample.Html, config); + var pdf = await PdfGenerator.GeneratePdfAsync(sample.Html, config, imageLoad: OnImageLoaded); pdf.Save(GetSamplePath(sample)); } } diff --git a/Source/Demos/HtmlRenderer.Demo.Console/Program.cs b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs index efdfb0e9f..65188c80e 100644 --- a/Source/Demos/HtmlRenderer.Demo.Console/Program.cs +++ b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs @@ -22,6 +22,9 @@ foreach (var htmlSample in samples) { + ////Just doing one test here. Comment this for all of them. + //if (!htmlSample.FullName.Contains("05")) continue; + await skia.GenerateSampleAsync(htmlSample); await pdfSharp.GenerateSampleAsync(htmlSample); } diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs b/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs index 237af910f..8c1e4b2cb 100644 --- a/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs +++ b/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; +using System.Drawing.Imaging; using System.Linq; using System.Runtime.CompilerServices; using System.Text; @@ -21,6 +23,9 @@ public SampleConverterBase(string sampleRunIdentifier, string basePath) _sampleRunIdentifier = sampleRunIdentifier; _basePath = basePath; _thisTypeName = this.GetType().Name; + + this.OnImageLoaded += ImageLoad; + this.OnStyleLoaded += StylesheetLoad; } public CssData CssData => null; @@ -32,9 +37,18 @@ protected string GetSamplePath(HtmlSample sample) return Path.Combine(path, sample.FullName + _thisTypeName + "_" + ".pdf"); } - internal void ImageLoad(object? sender, HtmlStylesheetLoadEventArgs e) + protected EventHandler OnImageLoaded; + protected EventHandler OnStyleLoaded; + + internal void ImageLoad(object? sender, HtmlImageLoadEventArgs e) { - throw new NotImplementedException(); + //The samples use some well known image resources, so do that here. + var imageStream = DemoUtils.GetImageStream(e.Src); + if (imageStream != null) + { + e.Handled = true; + e.Callback(imageStream); + } } internal void StylesheetLoad(object? sender, HtmlStylesheetLoadEventArgs e) diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs index 57e6bd774..93a749b38 100644 --- a/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs +++ b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs @@ -27,7 +27,7 @@ public async Task GenerateSampleAsync(HtmlSample sample) using (var fileStream = File.Open(GetSamplePath(sample), FileMode.CreateNew)) { - await PdfGenerator.GeneratePdfAsync(sample.Html, fileStream, config); + await PdfGenerator.GeneratePdfAsync(sample.Html, fileStream, config, imageLoad: OnImageLoaded); fileStream.Flush(); } } diff --git a/Source/HtmlRenderer/Adapters/RAdapter.cs b/Source/HtmlRenderer/Adapters/RAdapter.cs index 00ba36209..0ed190d7e 100644 --- a/Source/HtmlRenderer/Adapters/RAdapter.cs +++ b/Source/HtmlRenderer/Adapters/RAdapter.cs @@ -150,7 +150,14 @@ public RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor color2, d public RImage ConvertImage(object image) { // TODO:a remove this by creating better API. - return ConvertImageInt(image); + if (image is Stream imageStream) + { + return ImageFromStream(imageStream); + } + else + { + return ConvertImageInt(image); + } } /// diff --git a/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs b/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs index d2b547899..e2285a3ef 100644 --- a/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs +++ b/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs @@ -84,7 +84,10 @@ public async Task DownloadImageAsync(Uri imageUri, string filePath, bool async, { var tempPath = Path.GetTempFileName(); if (async) - ThreadPool.QueueUserWorkItem(DownloadImageFromUrlAsync, new DownloadData(imageUri, tempPath, filePath)); + { + //Don't wait for the image to be downloaded, just start the task. TODO: cancellation tokens. + var task = DownloadImageFromUrl(imageUri, tempPath, filePath); + } else await DownloadImageFromUrl(imageUri, tempPath, filePath); } @@ -107,84 +110,54 @@ public void Dispose() /// private async Task DownloadImageFromUrl(Uri source, string tempPath, string filePath) { + Exception downloadException = null; try { using (var client = new HttpClient()) { _clients.Add(client); - //client.DownloadFile(source, tempPath); - var response = await client.GetStreamAsync(source); - //OnDownloadImageCompleted(client, source, tempPath, filePath, null, false); + var response = await client.GetAsync(source); + response.EnsureSuccessStatusCode(); + OnDownloadImageCompleted(response, source, tempPath, filePath, downloadException, false); } } - catch (Exception ex) + catch (TaskCanceledException) { - OnDownloadImageCompleted(null, source, tempPath, filePath, ex, false); - } - } - - /// - /// Download the requested file in the URI to the given file path.
- /// Use async sockets API to download from web, . - ///
- /// key value pair of URL and file info to download the file to - private async void DownloadImageFromUrlAsync(object data) - { - var downloadData = (DownloadData)data; - try - { - var client = new HttpClient(); - _clients.Add(client); - //client.DownloadFileCompleted += OnDownloadImageAsyncCompleted; - //client.DownloadFileAsync(downloadData._uri, downloadData._tempPath, downloadData); - var response = await client.GetStreamAsync(downloadData._uri); + //If the download was cancelled, don't fire anything + return; } catch (Exception ex) { - OnDownloadImageCompleted(null, downloadData._uri, downloadData._tempPath, downloadData._filePath, ex, false); - } - } - - /// - /// On download image complete to local file.
- /// If the download canceled do nothing, if failed report error. - ///
- private void OnDownloadImageAsyncCompleted(object sender, AsyncCompletedEventArgs e) - { - var downloadData = (DownloadData)e.UserState; - try - { - using (var client = (WebClient)sender) - { - client.DownloadFileCompleted -= OnDownloadImageAsyncCompleted; - OnDownloadImageCompleted(client, downloadData._uri, downloadData._tempPath, downloadData._filePath, e.Error, e.Cancelled); - } - } - catch (Exception ex) - { - OnDownloadImageCompleted(null, downloadData._uri, downloadData._tempPath, downloadData._filePath, ex, false); + downloadException = ex; } + + } /// /// Checks if the file was downloaded and raises the cachedFileCallback from /// - private void OnDownloadImageCompleted(WebClient client, Uri source, string tempPath, string filePath, Exception error, bool cancelled) + private async Task OnDownloadImageCompleted(HttpResponseMessage response, Uri source, string tempPath, string filePath, Exception error, bool cancelled) { if (!cancelled) { if (error == null) { - var contentType = CommonUtils.GetResponseContentType(client); - if (contentType == null || !contentType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) + var mediaType = response.Content.Headers.ContentType?.MediaType; + if (mediaType == null || !mediaType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) { - error = new Exception("Failed to load image, not image content type: " + contentType); + error = new Exception("Failed to load image, not image content type: " + mediaType); } - } + //Save the content to the temp path. + using (var responseStream = response.Content.ReadAsStream()) + { + using (var tempFile = File.OpenWrite(tempPath)) + { + await responseStream.CopyToAsync(tempFile); + } + } - if (error == null) - { if (File.Exists(tempPath)) { try diff --git a/Source/HtmlRenderer/Core/Utils/CommonUtils.cs b/Source/HtmlRenderer/Core/Utils/CommonUtils.cs index 12c03ad32..fa0827706 100644 --- a/Source/HtmlRenderer/Core/Utils/CommonUtils.cs +++ b/Source/HtmlRenderer/Core/Utils/CommonUtils.cs @@ -191,21 +191,6 @@ public static FileInfo TryGetFileInfo(string path) return null; } - /// - /// Get web client response content type. - /// - /// the web client to get the response content type from - /// response content type or null - public static string GetResponseContentType(WebClient client) - { - foreach (string header in client.ResponseHeaders) - { - if (header.Equals("Content-Type", StringComparison.InvariantCultureIgnoreCase)) - return client.ResponseHeaders[header]; - } - return null; - } - /// /// Gets the representation of the online uri on the local disk. ///