I have a problem with the generation of a PDF with wkhtmlpdf. Here is my investigation:
1- Generation of PDF with static Google Map image in default mode (default size)
The web page and PDF contain the image.
2- Generation of PDF with static Google Map image with business licence (customize size)
The web page contains the image, the PDF not.
3- In command line
If I run in command line the wkhtmlpdf instruction, I receive this exception code:
Exit with code 1 due to http error: 1202
The only difference between the both is the url parameters &client=XXXXX and &signature=YYY are added for the business call at Google.
I didn't find a description for this http error code on the net and I wonder me if it's really a right http error code.
I am not an expert with wkhtmltopdf.
This is actually issue #1502 and is fixed in the development version, for which you can download a snapshot from the website.
So, the description for this error code is: PDF generated OK, but some request(s) did not return HTTP 200.
In waiting the final version, I decided to load the Google Map image in local and after put a reference in the web page.
With this solution, I don't have any exception while the generation of PDF.
Below is the code to load and save the Google Map image.
String myUrl = "http://www.lesoir.be/sites/default/files/imagecache/475x317/2014/04/02/1670051557_B972392274Z.1_20140402231342_000_GIT27H8H9.2-0.jpg";
URL imageURL = new URL(myUrl);
RenderedImage img = ImageIO.read(imageURL);
File outputfile = new File("C:\\Dev\\Tmp\\Img\\image.jpg");
ImageIO.write(img, "jpg", outputfile);
Related
I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js
I am trying to import a list of files from Google Drive to YouTube. The meta-data and the URL to the file are in a Google spreadsheet, so I wrote some code using Google Apps Script that does the following
Get the selected rows
Retrieve title, description, Google Drive URL
Load the file from Google Drive via DriveApp.getFileById
Upload the blob to YouTube using the title and description via YouTube.Videos.insert
Update the selected row with the YouTube video id from the response
The upload looks something like this
var blob = DriveApp.getFileById(id).getBlob();
var resource = {
snippet: {
title: 'The title',
description: 'A long description ...',
defaultLanguage: 'de',
categoryId: 17,
tags: [ 'Sport', 'Fitness' ],
},
status: {
privacyStatus: 'unlisted'
}
}
try {
var result = YouTube.Videos.insert(resource, "snippet,status", blob);
return result.id;
} catch (err) {
console.log({message: 'Error ' + err.message, error: err});
}
This code has already worked about a year ago. I have adapted it slightly, but now I do not get a response from the YouTube.Videos.insert call. The following is logged inside the catch:
message: Error Empty response
error: Exception: Empty response
Not very helpful.
Before uploading, I do a YouTube.Channels.list
to get a target channel in case there are multiple channels available. For this request, I have to permit access to my data and I am only asked on the first invocation. I also see the script in the list of applications for my Google account. I assume permissions are ok.
Any suggestions on how I can get more information on the issue, or is there something I should do differently?
Regarding the target channel (and this might be a different question), I cannot really use this, as it seems I can only upload to a specific channel, if I am a YouTube content partner (see parameters onBehalfOfContentOwner and onBehalfOfContentOwnerChannel):
Note: This parameter is intended exclusively for YouTube content partners.
I had same problem in my project and here's what I have figured out: if your video file size is more than 10 Mb, you will get Empty response error.
Probably (can't say officialy because no documentation mentions it) this is happening because Google Apps Script's YouTube.Videos.insert (and all other available built-in services) uses UrlFetchApp under the hood, which have restriction of 10 Mb per call: https://developers.google.com/apps-script/guides/services/quotas#current_limitations. You can check it yourself using your sample code: if file is under 10 Mb, it will be uploaded successfully.
As possible workaround, you can use idea from this answer: https://stackoverflow.com/a/44853845/555121
Basically, you will need to open modal window using SpreadsheetApp.getUi().showModalDialog and then perform upload to YouTube via plain JavaScript inside modal dialog, which have no restrictions on transferred data size. Here's good example of YouTube resumable upload implementation: https://github.com/sangnvus/2015SUMJS01/blob/master/WIP/Sources/FlyAwayPlus/FlyAwayPlus/Scripts/youtube-upload.js
I had a co-worker that normally worked with Google Maps and now I am creating my first map. I am using what they developed in the past and making the changes for what I need. They created a script that sets some of the map defaults, so that is why things might look slightly different.
var map = new Map();
map.loadMap();
var kml = new google.maps.KmlLayer({ url: 'http://api.mankatomn.gov/api/engineeringprojectskml', suppressInfoWindows: true });
kml.setMap(map.map);
The map loads. My KML file doesn't load. I don't get any errors in the console. When I replace the url with a different URL http://www.mankato-mn.gov/Maps/StreetConstruction/streetconstruction.ashx?id=122 it'll work just fine. My new feed does validate. Is there a issue with my web service?
Update: After a few days, I am still having the issue. So I am pretty sure this isn't a DNS issue anymore. I created a jsFiddle to see if it is my code or something else. I started with Google's sample code and changed the URL of the KML file to both my web service and to a static version of the generated file. Both are valid KML files. Neither work. If there was a syntax error, wouldn't the API report that?
You can get the status of a KML layer with
kml.getStatus();
which in this case return:
"INVALID_DOCUMENT"
Now, if I request your URL from the browser, I get
<Error>
<Message>An error has occurred.</Message>
</Error>
So it seems if there ever was a valid KML there, it isn't anymore. Assuming from your question I can oly guess it was above weight limit, or you weren't associating it with a valid instance of map.
For getStatus to return something useful, you must wait for Google Maps API to try and load the KML layer you declared. For example, you can add a listener on the status_changed event.
var kmloptions={
url: 'https://dl.dropboxusercontent.com/u/2732434/engineeringprojectskml.kml',
suppressInfoWindows: true
};
var newKml = new google.maps.KmlLayer(kmloptions);
newKml.setMap(map);
google.maps.event.addListenerOnce(newKml, 'status_changed', function () {
console.log('KML status is', newKml.getStatus());
});
in this case (note that I'm using the alternative URL you used in the jsFiddle), I still get INVALID DOCUMENT.
Update: it seems the problem was the encoding of the file (UTF-16 BE is meant to be binary). I converted it to utf-8 and reindented (it's in my public dropbox now)
You can check if the DNS is setup by:
Going to the url in your browser. Do this with cache emptied and history ereased (private mode is best). If it ends up at your server and the right file it is not a DNS problem.
Move the file to a location you're sure it is reachable without any DNS issues. e.g. http://www.mankato-mn.gov/Maps/StreetConstruction/engineeringprojectskml
If the problem persists make sure that your KML syntax and Javascript is 100% correct. Also check out https://developers.google.com/maps/documentation/javascript/examples/layer-kml if you're still having any issues.
CefSharp: 1.25.0 (based on Chromium 25.0.1364.152)
Angular: 1.3.0-beta16
UIRouter: 0.2.10
I'm developing a stand-alone C# application that uses CefSharp Chromium + Angular + UIRouter as the stack upon which the GUI will be relying on.
I hit it off by trying to make the above stack load the sample-code provided here:
http://scotch.io/tutorials/javascript/angular-routing-using-ui-router
For the sake of elegance the HTML + Javascript-libs of the GUI, get cobundled in a single resource file inside the .Net executable of the application.
This resource is then passed programmatically during application-init to the Chromium control (by means of .LoadHtml) to be loaded directly into the browser, aka the HTML is not loaded from a separate .html file residing in the hard-drive or on a remote HTTP server. If the HTML gets loaded from the later ("standard") venues then everything works flawlessly.
I noticed that when loading the HTML directly as a string, as described above, the url of the resulting static web page (aka window.location) is set to 'about:blank'. It appears that angular has some sort of pet peeve with such a url, especially when it comes to using routing:
First of all, the invocation of:
history.pushState(null, "", url);
inside
self.url = function(url, replace) { ... }
throws an exception ala
Error: SecurityError: DOM Exception 18
Error: An attempt was made to break through the security policy of the user agent.
at Browser.self.url (about:blank:8004:21)
at about:blank:10049:24
at Scope.$eval (about:blank:11472:28)
at Scope.$digest (about:blank:11381:31)
at Scope.$apply (about:blank:11493:24)
at about:blank:6818:15
at Object.invoke (about:blank:7814:19)
at doBootstrap (about:blank:6817:16)
at bootstrap (about:blank:6827:14)
at angularInit (about:blank:6796:7)
the url that is passed to .pushState is:
about:blank#/home
which appears to be the result of concatenating 'about:blank' with the default state '/home'.
Secondly, even if the above problem is solved there appears to be a major issue inside:
$rootScope.$watch(function $locationWatch() { ... })
which causes the following error:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
the reason is that when 'window.location' is set to 'about:blank' then
$browser.url()
always returns
about:blank
while
$location.absUrl()
returns
about:blank#/home
causing $watch to fire non-stop.
Is there any proper way to handle this shortcoming of angular when its dealing with web pages loaded directly into the browser in the manner described here?
If there is no workaround for this issue then I'm afraid that I will have to resort to loading the HTML directly from a file in the hard drive, which apart from being slower (can't cache the string to memory for subsequent usages), it's also a noticable deviation from the goal of developing a stand-alone-exe. :(
Thanks in advance and I apologize if this issue has been addressed elsewhere.
By default Firefox allows loading of external files within html file that loaded from "file:///...". but Chrome does not. in CefSharp(Chrome) you can do it in this way:
// Allow angular routing and load external files
BrowserSettings setting = new BrowserSettings();
setting.FileAccessFromFileUrls = CefState.Enabled;
browser.BrowserSettings = setting;
this.Controls.Add(browser);
Most browsers don't allow to do AJAX on the file-system. But Chromium can be tweaked to do so:
browser = new ChromiumWebBrowser(path);
browser.BrowserSettings = new BrowserSettings();
browser.BrowserSettings.FileAccessFromFileUrlsAllowed = true;
For some reason, any document I upload to OneNote via the new REST API is corrupt when viewed from OneNote. Everything else is fine, but the file (for example a Word document) isn't clickable and if you try and open is shows as corrupt.
This is similar to what may happen when there is a problem with the byte array, or its in memory, but that doesn't seem to be the case. I use essentially the same process to upload the file bytes to SharePoint, OneDrive, etc. It's only to OneNote that the file seems to be corrupt.
Here is a simplified version of the C#
HttpRequestMessage createMessage = null;
HttpResponseMessage response = null;
using (var streamContent = new ByteArrayContent(fileBytes))
{
streamContent.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data");
streamContent.Headers.ContentDisposition.Name = fileName;
createMessage = new HttpRequestMessage(HttpMethod.Post, authorizationUrl)
{
Content = new MultipartFormDataContent
{
{
new StringContent(simpleHtml,
System.Text.Encoding.UTF8, "text/html"), "Presentation"
},
{streamContent}
}
};
response = await client.SendAsync(createMessage);
var stream = await response.Content.ReadAsStreamAsync();
successful = response.IsSuccessStatusCode;
}
Does anyone have any thoughts or working code uploading an actual binary document via the OneNote API via a Windows Store app?
The WinStore code sample contains a working example (method: CreatePageWithAttachedFile) of how to upload an attachment.
The slight differences I can think of between the above code snippet and the code sample are that the code sample uploads a pdf file (instead of a document) and the sample uses StreamContent (while the above code snippet uses ByteArrayContent).
I downloaded the code sample and locally modified it to use a document file and ByteArrayContent. I was able to upload the attachment and view it successfully. Used the following to get a byte array from a given stream:
using (BinaryReader br = new BinaryReader(stream))
{
byte[] b = br.ReadBytes(Convert.ToInt32(s.Length));
}
The rest of the code looks pretty similar to the above snippet and overall worked successfully for me.
Here are a few more things to consider while troubleshooting the issue:
Verify the attachment file itself isn't corrupt in the first place. for e.g. can it be opened without the OneNote API being in the mix?
Verify the API returned a 201 Http Status code back and the resulting page contains the attachment icon and allows downloading/viewing the attached file.
So, the issue was (strangely) the addition of the meta Content Type in the tag sent over in the HTML content that's not shown. The documentation refers to adding a type=[mime type] in the object tag, and since the WinStore example didn't do this (it only adds the mime type to the MediaTypeHeaderValue I removed it and it worked perfectly.
Just changing it to this worked:
<object data-attachment=\"" + fileName + "\" data=\"name:" + attachmentPartName + "\" />
Thanks for pointing me in the right direction with the sample code!