webshot does not render local images inside html - javascript

I'm using node-webshot and phantomjs-cli to render an html string to a png image.
The html contains an image tag. The image is not rendered when it is the src attribute points to a local file and no error is raised. However it does render the image when the src points to a http location. I've tried all of the different file path combinations that I can think of, eg
<img src=images/mushrooms.png"/>
<img src=images//mushrooms.png"/>
<img src=c:\images\mushrooms.png"/>
<img src=c:\\images\\mushrooms.png"/>
<img src=file://c:\\images\\mushrooms.png"/>
<img src=file://images//mushrooms.png"/>
etc..
but so far no luck. Interestingly it works fine on my colleague's machine which is a Mac but not on mine which is Windows, and I've tried with two different Windows machines with no success.
Here is some simplified code that focuses on the issue:
'use strict'
const webshot = require('webshot');
console.log('generating');
webshot('<html><head></head><body><img src="c:\\images\\mushrooms.png"/></body></html>', 'output.png', {siteType: 'html'}, function(err) {
console.log(err);
});
/*
webshot('<html><head></head><body><img src="https://s10.postimg.org/pr6zy8249/mushrooms.png"/></body></html>', 'output.png', {siteType: 'html'}, function(err) {
console.log(err);
});
*/
The commented out code block is an example of it working with a web link as the image source but I need it to work off of a local path.
Has anyone had this issue before an know how to solve it?
Thanks

Local files should be accessible via the file: URI Scheme:
<img src="file:///C:/images/mushrooms.png">
Per the specification:
A file URL takes the form:
file://<host>/<path>

I think that you need to set static folders.
Use something like this in your code app.use(express.static(path.join(__dirname, 'public')));
Learn more about it here.

Can be because you never open the quotes.
try:
<img src="images/mushrooms.png"/>

Likely a phantomjs problem, I've run into bugs before and they barely maintain the project to this date. You should consider switching to Headless Chrome, which is new and officially maintained by the Chromium team.
Edit: here's an example
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent('<html><head></head><body><img src="c:\\images\\mushrooms.png"/></body></html>');
await page.screenshot({path: 'output.png'});
await browser.close();
})();
Edit 2: here's the link the node package

Related

Does 'onDidChangeTextDocument()' promise in VScode extension depend on the user's active window to start listening?

I'm a new developer and this is my first Stack Overflow post. I've tried to stick to the format as best as possible. It's a difficult issue for me to explain, so please let me know if there's any problems with this post!
Problem
I'm working on a vscode extension specifically built for Next.js applications and running into issues on an event listener for the onDidChangeText() method. I'm looking to capture data from a JSON file that will always be located in the root of the project (this is automatically generated/updated on each refresh of the test node server for the Next.js app).
Expected Results
The extension is able to look for updates on the file using onDidChangeText(). However, the issue I'm facing is on the initial run of the application. In order for the extension to start listening for changes to the JSON file, the user has to be in the JSON file. It's supposed to work no matter what file the user has opened in vscode. After the user visits the JSON file while the extension is on, it begins to work from every file in the Next.js project folder.
Reproducing this issue is difficult because it requires an extension, npm package, and a next.js demo app, but the general steps are below. If needed, I can provide code for the rest.
1. Start debug session
2. Open Next.js application
3. Run application in node dev
4. Do not open the root JSON file
What I've Tried
Console logs show we are not entering the onDidTextDocumentChange() block until the user opens the root JSON file.
File path to the root folder is correctly generated at all times, and prior to the promise being reached.
Is this potentially an async issue? Or is the method somehow dependent on the Active Window of the user to start looking for changes to that document?
Since the file is both created and updated automatically, we've tested for both, and neither are working until the user opens the root JSON file in their vscode.
Relevant code snippet (this will not work alone but I can provide the rest of the code if necessary. ).
export async function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "Next Step" is now active!');
setupExtension();
const output = vscode.window.createOutputChannel('METRICS');
// this is getting the application's root folder filepath string from its uri
if (!vscode.workspace.workspaceFolders) {
return;
}
const rootFolderPath = vscode.workspace.workspaceFolders[0].uri.path;
// const vscode.workspace.workspaceFolders: readonly vscode.WorkspaceFolder[] | undefined;
// this gives us the fileName - we join the root folder URI with the file we are looking for, which is metrics.json
const fileName = path.join(rootFolderPath, '/metrics.json');
const generateMetrics = vscode.commands.registerCommand(
'extension.generateMetrics',
async () => {
console.log('Succesfully entered registerCommand');
toggle = true;
vscode.workspace.onDidChangeTextDocument(async (e) => {
if (toggle) {
console.log('Succesfully entered onDidChangeTextDocument');
if (e.document.uri.path === fileName) {
// name the command to be called on any file in the application
// this parses our fileName to an URI - we need to do this for when we run openTextDocument below
const fileUri = vscode.Uri.parse(fileName);
// open the file at the Uri path and get the text
const metricData = await vscode.workspace
.openTextDocument(fileUri)
.then((document) => {
return document.getText();
});
}
}
});
});
}
Solved this by adding an "openTextDocument" call inside the "registerCommand" block outside of the "onDidChangeTextDocument" function. This made the extension aware of the 'metrics.json' file without it being open in the user's IDE.

NiodeJS/ How to find size of an externally hosted image without downloading it?

I need to find the sizes/metadata of externally hosted images in a document (e.g., markdown documents that have image tags in it), but need to do it without actually downloading the image.
Is there any way to do this easily on NodeJS/ExpressJs using javascript? Some of the solutions are many years old and not sure if there are better methods now.
You can do what was suggested in comments by only grabbing the HEAD instead of using a GET when you call the image.
Using got or whatever you like (http, axios, etc) you set the method to HEAD and look for content-length.
My example program that grabs a twitter favicon, headers only, looks like this:
const got = require('got');
(async () => {
try {
const response = await got('https://abs.twimg.com/favicons/twitter.ico', { method: 'HEAD' });
console.log(response.headers);
} catch (error) {
console.log('something is broken. that would be a new and different question.');
}
})();
and in the response I see the line I need:
'content-length': '912'
If the server doesn't respect HEAD or doesn't return a content-length header, you are probably out of luck.

How do I display in HTML the cover of an epub book using epub.js?

I'm using EPUB.js and Vue to render an Epub. I want to display the cover images of several epub books so users can click one to then see the whole book.
There's no documentation on how to do this, but there are several methods that indicate that this should be possible.
First off, there's Book.coverUrl() method.
Note that I'm setting an img src property equal to bookCoverSrc in the Vue template. Setting this.bookCoverSrc will automatically update the src of the img tag and cause an image to display (if the src is valid / resolves).
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.book.coverUrl().then((url) => {
this.bookCoverSrc = url;
});
})
The above doesn't work. url is undefined.
Weirdly, there appears to be a cover property directly on book. So, I try:
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.coverSrc = this.book.cover;
});
this.book.cover resolves to OEBPS/#public#vhost#g#gutenberg#html#files#49010#49010-h#images#cover.jpg, so at least locally when I set it to a src results in a request to http://localhost:8080/OEBPS/#public#vhost#g#gutenberg#html#files#49010#49010-h#images#cover.jpg, which 200s but returns no content. Probably a quirk of webpack-dev-server to 200 on that, but if I page through sources in Chrome dev tools I also don't see any indicate that such a URL should resolve.
So, docs not helping. I googled and found this github question from 2015. Their code is like
$("#cover").attr("src", Book.store.urlCache[Book.cover]);
Interesting, nothing in the docks about Book.store.urlCache. As expected, urlCache is undefined, though book.store exists. I don't see anything on there that can help me display a cover image though.
Using epub.js, how can I display a cover image of an Epub file? Note that simply rendering the first "page" of the Epub file (which is usually the cover image) doesn't solve my problem, as I'd like to list a couple epub files' cover images.
Note also that I believe the epub files I'm using do have cover images. The files are Aesop's Fables and Irish Wonders.
EDIT: It's possible I need to use Book.load on the url provided by book.cover first. I did so and tried to console.log it, but it's a massive blog of weirdly encoded text that looks something like:
����
So I think it's an image straight up, and I need to find a way to get that onto the Document somehow?
EDIT2: that big blobby blob is type: string, and I can't atob() or btoa() it.
EDIT3: Just fetching the url provided by this.book.cover returns my index.html, default behavior for webpack-dev-server when it doesn't know what else to do.
EDIT4: Below is the code for book.coverUrl from epub.js
key: "coverUrl",
value: function coverUrl() {
var _this9 = this;
var retrieved = this.loaded.cover.then(function (url) {
if (_this9.archived) {
// return this.archive.createUrl(this.cover);
return _this9.resources.get(_this9.cover);
} else {
return _this9.cover;
}
});
return retrieved;
}
If I use this.archive.createUrl(this.cover) instead of this.resources.get, I actually get a functional URL, that looks like blob:http://localhost:8080/9a3447b7-5cc8-4cfd-8608-d963910cb5f5. I'll try getting that out into src and see what happens.
The reason this was happening to me was because the functioning line of code in the coverUrl function was commented out in the source library epub.js, and a non-functioning line of code was written instead.
So, I had to copy down the entire library, uncomment the good code and delete the bad. Now the function works as it should.
To do so, clone down the entire epub.js project. Copy over the dependencies in that project's package.json to your own. Then, take the src, lib, and libs folders and copy them somewhere into your project. Find a way to disable eslint for the location you put these folders into because the project uses TAB characters for spacing which caused my terminal to hang due to ESLINT exploding.
npm install so you have your and epub.js dependencies in your node_modules.
Open book.js. Uncomment line 661 which looks like
return this.archive.createUrl(this.cover);
and comment out line 662 which looks like
// return this.resources.get(this.cover);
Now you can display an image by setting an img tag's src attribute to the URL returned by book.coverUrl().
this.book = new Epub(this.epubUrl, {});
this.book.ready.then(() => {
this.book.coverUrl().then((url) => {
this.bookCoverSrc = url;
});
})

Electron: how to serve files from appdata

I feel like this is such a basic question but I have been at it for hours and seem to be spinning around the answer. I have an electron app which I also used create-react-app on. I have image files in the appData folder for the electron app and I want to be able to display them in the renderer (using react) using an img tag.
I cannot seem to figure out how to do this. Using an absolute path and file:// for the img src doesn't work. I also tried to register a custom protocol but can't seem to get it to work, I just keep getting file not found (see below). Any ideas or links would be appreciated.
protocol.registerFileProtocol('poster', (request, callback) => {
const url = request.url.substr(9)
console.log(url);
callback({path: app.getPath('appData')+'/posters/'+url})
}, (error) => {
if (error) console.error('Failed to register protocol')
})
The image tag would look something like this:
<img src='poster://test.jpg'/>
What I eventually ended up doing was correcting my original code to use userData instead of appData. I didn't end up solving the part where it was converting to lower case so I just made all of my file names in lower case.
To find the path on your machine where you should put the files you can look at the result of a call to:
app.getPath('userData')
Here is the relevant code in my public/electron.js file:
protocol.registerFileProtocol('poster', (request, callback) => {
const url = request.url.substr(9,request.url.length -10)
callback({path: app.getPath('userData')+'/posters/'+url})
}, (error) => {
if (error) console.error('Failed to register protocol')
})
}
protocol.registerStandardSchemes(['poster'])
In my react code it is just a matter now of prefixing the filename in my image tag with 'poster://' so an image tag looks like:
<img src='poster://poster1.jpg/>

Silently print a PDF file using javascript

The thing I want to build is that by clicking a button I want to trigger the direct print of a PDF file, but without opening or viewing it.
I have PDF as blob file returned from fetch API.
I tried a lot of examples but don't know exactly how to do it
Some examples tried:
// In my case, I had only blobData from PDF, but you can ignore this and set fileURL directly if it is not yours.
const file = new Blob([blobData], { type: 'application/pdf' });
const fileURL = window.URL.createObjectURL(file);
// As the URL is dynamic, we must set src here, but if it's not, just leave it direct on the HTML.
// Also, be careful with React literals. If you do this in a <iframe> defined in JSX, it won't work
// as React will keep src property undefined.
window.frames["my-frame"].src = fileURL;
// Then print:
window.frames["my-frame"].print();
<iframe name="my-frame" id="my-frame" title="my-frame" style="display: none"></iframe>
Also tried library, Print.js: http://printjs.crabbly.com/.
Is there way to print the pdf without visually opening it to the user?
We should support only Chrome browser.
Can someone provide example how to do it in React, Redux application?
try this print-js and this is npm package
install npm package
npm install print-js --save
Add following code
import print from "print-js";
const fileURL = "someurl.com/document.pdf";
const handlePrint = (e) => {
e.preventDefault();
print(fileURL);
};
similar question is here

Categories

Resources