Images don't display in PDF - html

I have a fairly simple HTML page rendered via asp.net. It looks beautiful in the PDF after running it through HtmlRenderer.PdfSharp EXCEPT that the images don't appear. Just the red X of a missing image in the PDF even though the web page itself does display the image correctly.
Here is my HtmlRenderer.PdfSharp code:
public void BuildPDF( string url, string pdfPath ) {
string html = GetHTML(url);
Byte[] res = null;
using( MemoryStream ms = new MemoryStream() ) {
using( FileStream file = new FileStream(pdfPath, FileMode.Create, FileAccess.Write) ) {
byte[] bytes = new byte[ms.Length];
var pdf = TheArtOfDev.HtmlRenderer.PdfSharp.PdfGenerator.GeneratePdf(html, PdfSharp.PageSize.A4);
pdf.Save(ms);
res = ms.ToArray();
file.Write(res, 0, res.Length);
ms.Close();
}
}
}
private string GetHTML(string url) {
string html = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AutomaticDecompression = DecompressionMethods.GZip;
using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() )
using( Stream stream = response.GetResponseStream() )
using( StreamReader reader = new StreamReader(stream) ) {
html = reader.ReadToEnd();
}
return html;
}
And here is the img HTML that doesn't render in the PDF: <img src="images/ChartImg.png" />
How can I solve this?

Use the absolute path to the images.
<img src="http://example.org/images/ChartImg.png" />
You can parse the html and do a string replace first before passing it to the pdf converter.

The Code below:
var pdf = PdfGenerator.GeneratePdf(Html, PageSize.A4, 20, null, OnStylesheetLoad, OnImageLoadPdfSharp);
... ...
public static void OnImageLoadPdfSharp(object sender, HtmlImageLoadEventArgs e)
{
var url = e.Src;
if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
{
var ImgFilePath = System.Web.HttpContext.Current.Server.MapPath(url);
if (XImage.ExistsFile(ImgFilePath))
e.Callback(XImage.FromFile(ImgFilePath));
var ImgFilePath2 = System.Web.HttpContext.Current.Server.MapPath(url);
if (XImage.ExistsFile(ImgFilePath2))
e.Callback(XImage.FromFile(ImgFilePath2));
}
else
{
using (var client = new WebClient())
{
using (var stream = new MemoryStream(client.DownloadData(url)))
{
e.Callback(XImage.FromStream(stream));
}
}
}
}

It's better to use the image resolution callback for this for this:
var pdf = PdfGenerator.GeneratePdf(html, pdfConfig, imageLoad: OnImageLoad);
// snip
private void OnImageLoad(object sender, HtmlImageLoadEventArgs e)
{
using (var client = new WebClient())
{
var url = e.Src;
if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
{
url = Properties.Settings.Default.BaseUrl.TrimEnd('/') + e.Src;
}
using (var stream = new MemoryStream(client.DownloadData(url)))
{
e.Callback(XImage.FromStream(stream));
}
}
}

I'm late for your problem but maybe this will help someone else.
I used absolute urls and they were correct. Images were loaded correctly when I opened html file in browser.
However, they were not loaded after I converted this html to pdf. So I tried to use image resolution callback like #ohjo suggested. An exception occured here: An existing connection was forcibly closed by the remote host.
I was able to solve this but adding one more line that sets SecurityProtocol to this solution:
var pdf = PdfGenerator.GeneratePdf(Html, PageSize.A4, 20, null, OnStylesheetLoad, OnImageLoadPdfSharp);
... ...
public static void OnImageLoadPdfSharp(object sender, HtmlImageLoadEventArgs e)
{
var url = e.Src;
if (!e.Src.StartsWith("http://") && !e.Src.StartsWith("https://"))
{
var ImgFilePath = System.Web.HttpContext.Current.Server.MapPath(url);
if (XImage.ExistsFile(ImgFilePath))
e.Callback(XImage.FromFile(ImgFilePath));
var ImgFilePath2 = System.Web.HttpContext.Current.Server.MapPath(url);
if (XImage.ExistsFile(ImgFilePath2))
e.Callback(XImage.FromFile(ImgFilePath2));
}
else
{
using (var client = new WebClient())
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (var stream = new MemoryStream(client.DownloadData(url)))
{
e.Callback(XImage.FromStream(stream));
}
}
}
}

Related

IN ASP.NET web application I want to convert a youtube links to MP3 file

i want to just convert youtube links to MP3 file in asp.net.I have research about that and do the code but the code gives exception like below:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. how to resolve that
protected void Button1_Click(object sender, EventArgs e)
{
try
{
string url = TextBox1.Text;
var source = #"C:\Users\Dipak";
var youtube = YouTube.Default;
var vid = youtube.GetVideo(url);
File.WriteAllBytes(source + vid.FullName, vid.GetBytes());
var inputFile = new MediaFile { Filename = source + vid.FullName };
var outputFile = new MediaFile { Filename = $"{source + vid.FullName}.mp3" };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
engine.Convert(inputFile, outputFile);
}
}
catch (Exception exception)
{
}
}
I have found this types of code in Stack overflow but won't work

In Aspose, when exporting document to html, how can I access multiple images in stream

When I use Aspose.Word to export a .docx with multiple images into html, I can save those images into MemoryStream, for example, I can use IImageSavingCallback as
var imagesStream = new MemoryStream();
var handleImageSaving = new HandleImageSaving(imagesStream);
options.ImageSavingCallback = handleImageSaving;
document.Save(stream, options);
public class HandleImageSaving : IImageSavingCallback
{
private MemoryStream m_images;
public HandleImageSaving(
MemoryStream i_images)
{
m_images = i_images;
}
void IImageSavingCallback.ImageSaving(ImageSavingArgs args)
{
args.ImageStream = m_images;
args.KeepImageStreamOpen = true;
}
}
After .Save is executed, multiple images are stored in imagesStream, now I need to retrieve image one by one from imagesStream, how can I do it?
Please try using the following sample:
Document doc = new Document(MyDir + #"input.docx");
MemoryStream htmlStream = new MemoryStream();
MemoryStream imagesStream = new MemoryStream();
HtmlSaveOptions options = new HtmlSaveOptions(SaveFormat.Html);
var handleImageSaving = new HandleImageSaving(imagesStream);
options.ImageSavingCallback = handleImageSaving;
doc.Save(htmlStream, options);
DocumentBuilder builder = new DocumentBuilder();
foreach (Stream imgStream in handleImageSaving.ImageStreams)
{
builder.InsertImage(imgStream);
builder.Writeln();
}
builder.Document.Save(MyDir + #"15.12.0.docx");
And the definition of HandleImageSaving class is as follows
public class HandleImageSaving : IImageSavingCallback
{
public ArrayList ImageStreams;
private MemoryStream m_images;
public HandleImageSaving(MemoryStream i_images)
{
ImageStreams = new ArrayList();
m_images = i_images;
}
void IImageSavingCallback.ImageSaving(ImageSavingArgs args)
{
Shape shape = (Shape)args.CurrentShape;
m_images = new MemoryStream(shape.ImageData.ImageBytes);
ImageStreams.Add(m_images);
args.ImageStream = m_images;
args.KeepImageStreamOpen = true;
}
}
Hope, this helps. I work with Aspose as Developer Evangelist.

trying to access an external JSON file using netwonsoft in mvc4 c#

I'm trying to read an external json to display data on screen. What am I doing worng here?
public void QuarterlyReport(object sender, EventArgs e)
{
JObject qData1 = JObject.Parse(System.IO.File.ReadAllText(#"~/json/quarterlyData.json"));
// read JSON directly from a file
using (StreamReader file = System.IO.File.OpenText(#"~/json/quarterlyData.json"))
using (JsonTextReader reader = new JsonTextReader(file))
{
JObject Qdata2 = (JObject) JToken.ReadFrom(reader);
}
string Qdata = Newtonsoft.Json.JsonConvert.SerializeObject(qData1);
}
public async Task<FileStreamResult> Index()
{
var _reportingService = new ReportingService("https://mysite.jsreportonline.net", "myemail#gmail.com", "password");
var report = await _reportingService.RenderAsync("VyxOYwH7Ze", new { Qdata });
//add the stream to be used by browser
MemoryStream ms = new MemoryStream();
//copy whatever JS is sending to us
report.Content.CopyTo(ms);
//start at content point
ms.Position = 0;
//send this to browser
return File(ms, report.ContentType.MediaType);
}
I can't seem to get the vaule into the variable Qdata. What is it that I am doing wrong in the method?
The line where you declare Qdata:
string Qdata = Newtonsoft.Json.JsonConvert.SerializeObject(qData1);
is not in the same scope as this line:
var report = await _reportingService.RenderAsync("VyxOYwH7Ze", new { Qdata });
Yes, the problem was that
JObject qData1 = JObject.Parse(System.IO.File.ReadAllText(#"~/json/quarterlyData.json"));
And
string Qdata = Newtonsoft.Json.JsonConvert.SerializeObject(qData1);
Needed to be in the same scope as
var report = await _reportingService.RenderAsync("VyxOYwH7Ze", new { Qdata });

how to display files with a download link from google drive

I've a requirement where I should display the list of all files from google drive (of course using oAuth for authorization and authentication)... displaying the list of files which has the extension (.mp3) along with the full path where the user can either copy the path of the file and paste it in a seperate url or can click on the file name to download the file. I'm not getting proper inputs of getting the full path of the file from google drive. I'm using asp.net application.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Google.GData.Client;
using Google.GData.Documents;
using System.IO;
using Google.Apis.Drive.v2;
using Google.Apis.Drive;
using Google.Apis;
namespace AccessGoogleDriveData
{
public partial class GoogleOAuthCallback : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string state = Request.QueryString["state"];
// creating oauthparameter with client id and secret key
OAuth2Parameters parameters = new OAuth2Parameters()
{
ClientId = "myclientid.apps.googleusercontent.com",
ClientSecret = "clientsecretid",
RedirectUri = "http://localhost:16615/GoogleOAuthCallback.aspx">,
Scope = "https://docs.google.com/feeds/ ",
State = "documents",
AccessType = "offline"
};
lstDocuments.Visible = false;
if (state != null)
{
parameters.AccessCode = Request.QueryString["code"];
// it gets accesstoken from google
Google.GData.Client.OAuthUtil.GetAccessToken(parameters);
GOAuth2RequestFactory requestFactory = new GOAuth2RequestFactory(null, "MyDocumentsListIntegration-v1", parameters);
DocumentsService service = new DocumentsService("MyDocumentsListIntegration-v1");
service.RequestFactory = requestFactory;
DocumentsListQuery query = new DocumentsListQuery();
// Make a request to the API and get all documents.
DocumentsFeed feed = service.Query(query);
lstDocuments.Visible = true;
if (feed.Entries.Count > 0)
{
// var documentsList = from entry in feed.Entries select entry.Title.Text;
var documentsList = from entry in feed.Entries where GetFileExtension(entry.Title.Text.ToString()) == "mp3" select entry.Title.Text;
lstDocuments.DataSource = documentsList;
lstDocuments.DataBind();
}
}
}
protected void btnGetDocuments_Click(object sender, EventArgs e)
{
OAuth2Parameters parameters = new OAuth2Parameters()
{
ClientId = "myclientid.apps.googleusercontent.com",
ClientSecret = "clientsecretid",
RedirectUri = "http://localhost:16615/GoogleOAuthCallback.aspx",
Scope = "https://docs.google.com/feeds/ ">,
State = "documents",
AccessType = "offline" // offline means it creats a refreshtoken
};
string url = Google.GData.Client.OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
Session["oauthDocumentsParameters"] = parameters;
// it redirct to google login page
Response.Redirect(url);
}
private string GetFileExtension(string sFileName)
{
sFileName = sFileName.Trim();
if (String.IsNullOrEmpty(sFileName))
{
return String.Empty;
}
string sExtension = String.Empty;
char[] cArr = sFileName.ToCharArray();
int iIndex = 0;
for (int i = cArr.Length - 1; i > -1; i--)
{
if (cArr[i].Equals('.'))
{
iIndex = i;
break;
}
}
if (iIndex > 0)
{
for (int i = iIndex + 1; i < cArr.Length; i++)
{
sExtension += cArr[i];
}
}
return sExtension.ToLower();
}
}
}

How cancel Async Call in Windows Phone?

I have a list wich is loaded with elements each time the user make a research...These elements contain an Icon which is dowloaded with an async method GetByteArrayAsync of the HttpClient object. I have an issue when the user make a second research while the icon of the first list are still downloading.Because the list of elements is changing while Icon downloads are processing on each element of the first list. So my guess is that I need to cancel these requests each time the user proceed to a new research...Ive readen some stuuf on Task.run and CancellationTokenSource but I can't find really helpful example for my case so here is my code...Hope you can help me with that ...Thank you
public static async Task<byte[]> DownloadElementFile(BdeskElement bdeskElement)
{
//create and send the request
DataRequest requesteur = new DataRequest();
byte[] encryptedByte = await requesteur.GetBytesAsync(dataRequestParam);
return encryptedByte;
}
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
byte[] BytesReceived = await httpClient.GetByteArrayAsync(datarequesparam.TargetUri);
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
EDIT
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam)
{
var handler = new HttpClientHandler { Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000") };
HttpClient httpClient = new HttpClient(handler);
try
{
cts = new CancellationTokenSource();
HttpResponseMessage reponse = await httpClient.GetAsync(datarequesparam.TargetUri,cts.Token);
if (reponse.StatusCode == HttpStatusCode.OK)
{
byte[] BytesReceived = reponse.Content.ReadAsByteArrayAsync().Result;
if (BytesReceived.Length > 0)
{
return BytesReceived;
}
else
{
return null;
}
}
else
{
return null;
}
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
catch(OperationCanceledException)
{
throw new OperationCanceledException();
}
EDIT2
I need to cancel this funntion when the user make a new research and the list "listBoxGetDocsLibs" changed.
private async void LoadIconDocLibs()
{
foreach (var doclib in listBoxGetDocsLibs)//ERROR HERE COLLECTION HAS CHANGED
{
doclib.Icon = new BitmapImage();
try
{
byte[] Icon = await ServerFunctions.GetDocLibsIcon(doclib);
if (Icon != null)
{
{
var ms = new MemoryStream(Icon);
BitmapImage photo = new BitmapImage();
photo.DecodePixelHeight = 64;
photo.DecodePixelWidth = 92;
photo.SetSource(ms);
doclib.Icon = photo;
}
}
}
catch(OperationCanceledException)
{
}
}
}
First you need to define CancellationTokenSource:
private System.Threading.CancellationTokenSource cts;
place above code somewhere, where you can access it with your Button or other method.
Unfortunately GetByteArrayAsync lacks Cancelling - so it cannot be used with cts.Token, but maybe you can accomplish your task using GetAsync - which supports Cancelling:
ctsDownload = new System.Threading.CancellationTokenSource();
HttpResponseMessage response = await httpClient.GetAsync(requestUri, cts.Token);
Then you can get your content from response.
And when you want to Cancel your Task it can look like this:
private void cancelBtn_Click(object sender, RoutedEventArgs e)
{
if (this.cts != null)
this.cts.Cancel();
}
When you Cancel task an Exception will be thrown.
If you want to cancel your own async Task, a good example you can find at Stephen Cleary blog.
EDIT - you can also build your own method (for example with HttpWebRequest) which will support Cancelling:
For this purpose you will have to extend HttpWebRequest (under WP it lacks GetResponseAsync):
// create a static class in your namespace
public static class Extensions
{
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest webRequest)
{
TaskCompletionSource<HttpWebResponse> taskComplete = new TaskCompletionSource<HttpWebResponse>();
webRequest.BeginGetResponse(
asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
catch (Exception exc) { taskComplete.SetException(exc); }
}, webRequest);
return taskComplete.Task;
}
}
Then your method can look like this:
public async Task<Byte[]> GetBytesAsync(DataRequestParam datarequesparam, CancellationToken ct)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(datarequesparam.TargetUri);
request.Method = "GET";
request.Credentials = new NetworkCredential(datarequesparam.AuthentificationLogin, datarequesparam.AuthentificationPassword, "bt0d0000");
request.AllowReadStreamBuffering = false;
try
{
if (request != null)
{
using (HttpWebResponse response = await request.GetResponseAsync())
using (Stream mystr = response.GetResponseStream())
using (MemoryStream output = new MemoryStream())
{
const int BUFFER_SIZE = 10 * 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await mystr.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
{
output.Write(buf, 0, bytesread);
ct.ThrowIfCancellationRequested();
}
return output.ToArray();
}
}
else return null;
}
catch (WebException)
{
throw new MyException(MyExceptionsMessages.Webexception);
}
}
You can freely change Buffer Size which will affect how often Cancellation will be checked.
I haven't tried this but I think it should work.