This question already has answers here:
Javascript request fullscreen is unreliable
(5 answers)
Closed 21 days ago.
I have a Unity webGL game I downloaded from the web. I don't know what version of unity it was made in.
It starts playing in a small canvas with other stuff on the page like Unity logo, there is a button on the page that makes it fullscreen. I would like it to be fullscreen as soon as you load the page..
I tried adding this line to the script in index.html, to click the fullscreen button..
fullscreenButton.click();
But I get a load of errors..
here is the full index.html with the javascript in it. You can see the line I added near the bottom. I just tried clicking the button after unityInstance.SetFullscreen(1) is assigned to its onclick event (or whatever it is (I dunno anything about web).
I also tried just calling unityInstance.SetFullscreen(1) but I get the same error.
So how can I make it go fullscreen?
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Unity WebGL Player | QTE</title>
<link rel="shortcut icon" href="TemplateData/favicon.ico">
<link rel="stylesheet" href="TemplateData/style.css">
</head>
<body>
<div id="unity-container" class="unity-desktop">
<canvas id="unity-canvas" width="100%" height="100%"></canvas>
<div id="unity-loading-bar">
<div id="unity-logo"></div>
<div id="unity-progress-bar-empty">
<div id="unity-progress-bar-full"></div>
</div>
</div>
<div id="unity-warning"> </div>
<div id="unity-footer">
<div id="unity-webgl-logo"></div>
<div id="unity-fullscreen-button"></div>
<div id="unity-build-title">QTE</div>
</div>
</div>
<script>
var container = document.querySelector("#unity-container");
var canvas = document.querySelector("#unity-canvas");
var loadingBar = document.querySelector("#unity-loading-bar");
var progressBarFull = document.querySelector("#unity-progress-bar-full");
var fullscreenButton = document.querySelector("#unity-fullscreen-button");
var warningBanner = document.querySelector("#unity-warning");
// Shows a temporary message banner/ribbon for a few seconds, or
// a permanent error message on top of the canvas if type=='error'.
// If type=='warning', a yellow highlight color is used.
// Modify or remove this function to customize the visually presented
// way that non-critical warnings and error messages are presented to the
// user.
function unityShowBanner(msg, type) {
function updateBannerVisibility() {
warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';
}
var div = document.createElement('div');
div.innerHTML = msg;
warningBanner.appendChild(div);
if (type == 'error') div.style = 'background: red; padding: 10px;';
else {
if (type == 'warning') div.style = 'background: yellow; padding: 10px;';
setTimeout(function() {
warningBanner.removeChild(div);
updateBannerVisibility();
}, 5000);
}
updateBannerVisibility();
}
var buildUrl = "Build";
var loaderUrl = buildUrl + "/WebBuild.loader.js";
var config = {
dataUrl: buildUrl + "/WebBuild.data",
frameworkUrl: buildUrl + "/WebBuild.framework.js",
codeUrl: buildUrl + "/WebBuild.wasm",
streamingAssetsUrl: "StreamingAssets",
companyName: "Rat Bashers",
productName: "QTE",
productVersion: "0.1",
showBanner: unityShowBanner,
};
// By default Unity keeps WebGL canvas render target size matched with
// the DOM size of the canvas element (scaled by window.devicePixelRatio)
// Set this to false if you want to decouple this synchronization from
// happening inside the engine, and you would instead like to size up
// the canvas DOM size and WebGL render target sizes yourself.
// config.matchWebGLToCanvasSize = false;
if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
// Mobile device style: fill the whole browser client area with the game canvas:
var meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';
document.getElementsByTagName('head')[0].appendChild(meta);
container.className = "unity-mobile";
// To lower canvas resolution on mobile devices to gain some
// performance, uncomment the following line:
// config.devicePixelRatio = 1;
canvas.style.width = window.innerWidth + 'px';
canvas.style.height = window.innerHeight + 'px';
unityShowBanner('WebGL builds are not supported on mobile devices.');
} else {
// Desktop style: Render the game canvas in a window that can be maximized to fullscreen:
canvas.style.width = "1280px";
canvas.style.height = "720px";
}
loadingBar.style.display = "block";
var script = document.createElement("script");
script.src = loaderUrl;
script.onload = () => {
createUnityInstance(canvas, config, (progress) => {
progressBarFull.style.width = 100 * progress + "%";
}).then((unityInstance) => {
loadingBar.style.display = "none";
unityInstance.SetFullscreen(1);
fullscreenButton.onclick = () => {
unityInstance.SetFullscreen(1);
};
fullscreenButton.click();
}).catch((message) => {
alert(message);
});
};
document.body.appendChild(script);
</script>
</body>
</html>
For security reasons requestFullscreen can only be called in an event handler of a keyboard or click event.
More details: Javascript request fullscreen is unreliable
Related
I want to capture image every time socket.on('takePic') gets triggered. It works fine for the first time. but when the socket.on('takePic') gets triggered second time,the canvas div is just blank and so the img tag.
I have copied the takePicture() function from somewhere and added the setInterval() and localstream variable to stop camera.
how can I fix this?
here is my js code.
const socket = io('http://localhost:3001');
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
let roomId = params.roomId;
socket.emit('joinRoom',roomId);
var takePicture = function () {
// The width and height of the captured photo. We will set the
// width to the value defined here, but the height will be
// calculated based on the aspect ratio of the input stream.
var width = 320; // We will scale the photo width to this
var height = 0; // This will be computed based on the input stream
// |streaming| indicates whether or not we're currently streaming
// video from the camera. Obviously, we start at false.
var streaming = false;
var localstream;
// The various HTML elements we need to configure or control. These
// will be set by the startup() function.
var video = null;
var canvas = null;
var photo = null;
var startbutton = null;
function showViewLiveResultButton() {
if (window.self !== window.top) {
// Ensure that if our document is in a frame, we get the user
// to first open it in its own tab or window. Otherwise, it
// won't be able to request permission for camera access.
document.querySelector(".contentarea").remove();
const button = document.createElement("button");
button.textContent = "View live result of the example code above";
document.body.append(button);
button.addEventListener('click', () => window.open(location.href));
return true;
}
return false;
}
function startup() {
if (showViewLiveResultButton()) { return; }
video = document.getElementById('video');
canvas = document.getElementById('canvas');
photo = document.getElementById('photo');
startbutton = document.getElementById('startbutton');
navigator.mediaDevices.getUserMedia({video: true, audio: false})
.then(function(stream) {
video.srcObject = stream;
localstream = stream;
video.play();
})
.catch(function(err) {
console.log("An error occurred: " + err);
});
video.addEventListener('canplay', function(ev){
if (!streaming) {
height = video.videoHeight / (video.videoWidth/width);
// Firefox currently has a bug where the height can't be read from
// the video, so we will make assumptions if this happens.
if (isNaN(height)) {
height = width / (4/3);
}
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}
}, false);
startbutton.addEventListener('click', function(ev){
takepicture();
ev.preventDefault();
clearInterval(picInterval);
$('#heading').css('display','none')
video.pause();
video.src = "";
localstream.getTracks()[0].stop();
}, false);
clearphoto();
}
// Fill the photo with an indication that none has been
// captured.
function clearphoto() {
var context = canvas.getContext('2d');
context.fillStyle = "#AAA";
context.fillRect(0, 0, canvas.width, canvas.height);
var data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);
}
// Capture a photo by fetching the current contents of the video
// and drawing it into a canvas, then converting that to a PNG
// format data URL. By drawing it on an offscreen canvas and then
// drawing that to the screen, we can change its size and/or apply
// other changes before drawing it.
function takepicture() {
var context = canvas.getContext('2d');
if (width && height) {
canvas.width = width;
canvas.height = height;
context.drawImage(video, 0, 0, width, height);
var data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);
} else {
clearphoto();
}
}
// Set up our event listener to run the startup process
// once loading is complete.
startup();
var i = 10;
let picInterval = setInterval(()=>{
i -= 1;
$('#heading').html(`taking picture in ${i}`);
if(i==0){
$('#startbutton').click()
}
}, 1000)
}
socket.on('takePic',()=>{
takePicture()
})
and this is the html code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>StudentVideo</title>
<link rel="stylesheet" href="css/studentVideo.css">
</head>
<body>
<div class="contentarea">
<h1 id="heading">
</h1>
<p>
This example demonstrates how to set up a media stream using your built-in webcam, fetch an image from that stream, and create a PNG using that image.
</p>
<div class="camera">
<video id="video" width="320" height="240">Video stream not available.</video>
<button id="startbutton">Take photo</button>
</div>
<canvas id="canvas" width="320" height="240">
</canvas>
<div class="output">
<img id="photo" alt="The screen capture will appear in this box." src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAABGlJREFUeF7t1AEJADAMA8HVv5Oa3GAuHq4KwqVkdvceR4AAgYDAGKxASyISIPAFDJZHIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRB46/vA5AUJNVYAAAAASUVORK5CYII=">
</div>
<p>
Visit our article Taking still photos with WebRTC to learn more about the technologies used here.
</p>
</div>
</body>
<script src="https://cdn.socket.io/socket.io-3.0.1.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="js/video.js"></script>
</html>
In the click handler of #startbutton your code calls takepicture and then it goes on to remove the video's src and stop the MediaStream.
So the next time this handler is called, there is no source affected to the video element and thus nothing to be drawn on the canvas anymore.
It's quire unclear why you clear the video in this click handler, so you might want to remove this part of the code, or to move it to a "stop" button instead, but anyway, you would probably be better calling takepicture from your interval directly rather than relying on the event handler.
I am building a chrome extension using Javascript which gets URLs of the opened tabs and saves the html file, but the problem with html is that it does not render images on webpages fully. So i changed my code to loop each URLs of the tabs and then save each html pages as image file automatically in one click on the download icon of the chrome extension. I have been researching for more than 2 days but nothing happened. Please see my code files and guide me. I know there is library in nodejs but i want to perform html to jpeg/png maker using chrome extension only.
Only icons i have not attached which i have used in this extension, all code i have and the text in popup.js which is commented i have tried.
Current output of the attached code
Updated popup.js
File popup.js - This file has functions which gets all the URLs of the opened tabs in the browser window
// script for popup.html
window.onload = () => {
// var html2obj = html2canvas(document.body);
// var queue = html2obj.parse();
// var canvas = html2obj.render(queue);
// var img = canvas.toDataURL("image/png");
let btn = document.querySelector("#btnDL");
btn.innerHTML = "Download";
function display(){
// alert('Click button is pressed')
window.open("image/url");
}
btn.addEventListener('click', display);
}
chrome.windows.getAll({populate:true}, getAllOpenWindows);
function getAllOpenWindows(winData) {
var tabs = [];
for (var i in winData) {
if (winData[i].focused === true) {
var winTabs = winData[i].tabs;
var totTabs = winTabs.length;
console.log("Number of opened tabs: "+ totTabs);
for (var j=0; j<totTabs;j++) {
tabs.push(winTabs[j].url);
// Get the HTML string in the tab_html_string
tab_html_string = get_html_string(winTabs[j].url)
// get the HTML document of each tab
tab_document = get_html_document(tab_html_string)
console.log(tab_document)
let canvasref = document.querySelector("#capture");
canvasref.appendChild(tab_document.body);
html2canvas(document.querySelector("#capture")).then(canvasref => {
document.body.appendChild(canvasref)
var img = canvasref.toDataURL("image/png");
window.open(img)
});
}
}
}
console.log(tabs);
}
function get_html_document(tab_html_string){
/**
* Convert a template string into HTML DOM nodes
*/
var parser = new DOMParser();
var doc = parser.parseFromString(tab_html_string, 'text/html');
return doc;
}
function get_html_string(URL_string){
/**
* Convert a URL into HTML string
*/
let xhr = new XMLHttpRequest();
xhr.open('GET', URL_string, false);
try {
xhr.send();
if (xhr.status != 200) {
alert(`Error ${xhr.status}: ${xhr.statusText}`);
} else {
return xhr.response
}
} catch(err) {
// instead of onerror
alert("Request failed");
}
}
File popup.html - This file represent icon and click functionality on the chrome browser search bar
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
<script src= './html2canvas.min.js'></script>
<script src= './jquery.min.js'></script>
<script src='./popup.js'></script>
<title>Capture extension</title>
<!--
- JavaScript and HTML must be in separate files: see our Content Security
- Policy documentation[1] for details and explanation.
-
- [1]: http://developer.chrome.com/extensions/contentSecurityPolicy.html
-->
</head>
<body>
<button id="btnDL"></button>
</body>
</html>
File manifest.json - This file is used by the chrome browser to execute the chrome extension
{
"manifest_version": 2,
"name": "CIP screen capture",
"description": "One-click download for files from open tabs",
"version": "1.4.0.2",
"browser_action": {
"default_popup": "popup.html"
},
"permissions": [
"downloads", "tabs", "<all_urls>"
],
"options_page": "options.html"
}
You can use the library html2canvas which renders any html element, particularly the body element, and from the resulted canvas you can have your image
<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>
<script>
html2canvas(document.body).then(
(canvas) => {
var img = canvas.toDataURL("image/png");
}
);
</script>
You can get html2canvas from any public CDN, like this one. You don't need nodeJS. Or perhaps directly from the original git repo
<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>
You can also save canvas as a blob
html2canvas(document.body).then(function(canvas) {
// Export canvas as a blob
canvas.toBlob(function(blob) {
// Generate file download
window.saveAs(blob, "yourwebsite_screenshot.png");
});
});
It's possible with vanilla JS, I guess vanilla is more likely to be used on a extension, the drawback is the end result, when a 3rd party library my already fixed the issues you will encounter with fonts and style (html2canvas or whatever).
So, vanilla js, for some reason stack overflow snippet does not permit window.open, demo here: https://jsfiddle.net/j67nqsme/
Few words on how it was implemented:
using html to svg transformation, a 3rd party library can be used here
using canvas to transform svg into pdg or jpg
example can export html or page to svg, png, jpg
it is not bullet proof - rendering can suffer, style, fonts, ratios, media query
Disclaimer: I won't help you debug or find solution of your problem, it is an answer to your question using vanilla js, from there on is your decision what you are using or how you are using it.
Source code bellow:
<html>
<body>
<script>
function export1() {
const html = '<div style="color:red">this is <br> sparta </div>';
renderHtmlToImage(html, 800, 600, "image/png");
}
function export2() {
renderDocumentToImage(window.document, 800, 600, "image/png");
}
// format is: image/jpeg, image/png, image/svg+xml
function exportImage(base64data, width, height, format) {
var img = new Image();
img.onload = function () {
if ("image/svg+xml" == format) {
var w = window.open("");
w.document.write(img.outerHTML);
w.document.close();
}
else {
const canvas = document.createElement("Canvas");
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
var exportImage = new Image();
exportImage.onload = function () {
var w = window.open("");
w.document.write(exportImage.outerHTML);
w.document.close();
}
exportImage.src = canvas.toDataURL(format);
}
}
img.src = base64data;
}
// format is: image/jpeg, image/png, image/svg+xml
function renderHtmlToImage(html, width, height, format) {
var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
+ '<foreignObject width="100%" height="100%">'
+ html2SvgXml(html)
+ '</foreignObject>'
+ '</svg>';
var base64data = "data:image/svg+xml;base64," + btoa(svgData);
exportImage(base64data, width, height, format);
}
function renderDocumentToImage(doc, width, height, format) {
var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
+ '<foreignObject width="100%" height="100%">'
+ document2SvgXml(doc)
+ '</foreignObject>'
+ '</svg>';
var base64data = "data:image/svg+xml;base64," + btoa(svgData);
exportImage(base64data, width, height, format);
}
// plain html to svgXml
function html2SvgXml(html) {
var htmlDoc = document.implementation.createHTMLDocument('');
htmlDoc.write(html);
// process document
return document2SvgXml(htmlDoc);
}
// htmlDocument to
function document2SvgXml(htmlDoc) {
// Set the xmlns namespace
htmlDoc.documentElement.setAttribute('xmlns', htmlDoc.documentElement.namespaceURI);
// Get XML
var svcXml = (new XMLSerializer()).serializeToString(htmlDoc.body);
return svcXml;
}
</script>
<div>
<h3 style="color:blue">My Title</h3>
<div style="color:red">
My Text
</div>
<button onclick="export1()">Export Plain Html</button>
<button onclick="export2()">Export Entire Document</button>
</div>
</body>
</html>
There are 3 ways this could be approached:
Render this in client javascript using an API like HTML2Canvas. It's isolated, runs in the browser, but relies on a re-render that could get details of the captured page wrong (see most issues with H2C). That might be fine if you just want a small preview and don't mind the odd difference. Also be careful as the render is slow and somewhat heavyweight - background renders of large pages may be noticeable by users, but so will waits for the images to render.
Use a service that runs Chrome to visit the page and then screenshot it. You could write this or buy in a service like Site-Shot to do it for you. This requires a service which will have a cost, but can guarantee the render is accurate and ensures the load on the users' machines is minimal.
Use the Chrome tab capture API to screenshot the tab. This is probably the best option for an extension, but currently you can only capture the current active tab. captureOffscreenTab is coming soon, but currently only in Canary behind a flag.
I'd recommend option 3, as by the time you have finished the component you could have access to the new features. If you need to release soon you could use 1 or 2 as a short term solution.
I am trying to make a PDF viewer, and it runs perfectly when I run it through live server on vscode, but for some reason, when I go to my files, right click on the index.html and click open with chrome, firefox, or internet explorer it comes up with 2 errors:
1)GET file://mozilla.github.io/pdf.js/build/pdf.js net::ERR_FILE_NOT_FOUND
main.js:18
2)Uncaught TypeError: Cannot read property 'GlobalWorkerOptions' of undefined
at main.js:18
Here is my index.html code and my main.js code:
Index.html
<!DOCTYPE html>
<html>
<head>
<title>PDF Viewer Attempt 2</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>PDF Name</h1>
<div>
<button id="prev">Previous</button>
<button id="next">Next</button>
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
</div>
<canvas id="the-pdf"></canvas>
<script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>
<script src="js/main.js"></script>
</body>
</html>
main.js:
//Code adapted from https://jsfiddle.net/pdfjs/wagvs9Lf/
// If absolute URL from the remote server is provided, configure the CORS
// header on that server.
var url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf'; //works with this internet pdf
//url = 'pdf.pdf'; // Works with local pdf
// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 0.8,
canvas = document.getElementById('the-pdf'),
ctx = canvas.getContext('2d');
/**
* Get page info from document, resize canvas accordingly, and render page.
* #param num Page number.
*/
function renderPage(num) {
pageRendering = true;
// Using promise to fetch the page
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
// Wait for rendering to finish
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
// New page rendering is pending
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
// Update page counters
document.getElementById('page_num').textContent = num;
}
/**
* If another page rendering in progress, waits until the rendering is
* finised. Otherwise, executes rendering immediately.
*/
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
/**
* Displays previous page.
*/
function onPrevPage() {
if (pageNum <= 1) {
return;
}
pageNum--;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);
/**
* Displays next page.
*/
function onNextPage() {
if (pageNum >= pdfDoc.numPages) {
return;
}
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);
/**
* Asynchronously downloads PDF.
*/
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
// Initial/first page rendering
renderPage(pageNum);
});
Any help is appreciated! This was my first post so let me know if there is anything I can do to format better! Dont worry about that line that says error for now, that is just a paragraph block.
I am trying to display PDF in browser, I found library PDF.js which is most popular and most suggested library. Documentations and are clear, but one I try to use latest official release 2.0.943 document is not rendered, it gets loaded(as I see correct number of pages), but not visible.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<!--<script src="//mozilla.github.io/pdf.js/build/pdf.js"></script>-->
<script src="https://cdn.jsdelivr.net/npm/pdfjs-dist#2.0.943/build/pdf.js"></script>
<h1>PDF.js Previous/Next example</h1>
<div>
<button id="prev">Previous</button>
<button id="next">Next</button>
<span>Page: <span id="page_num"></span> / <span id="page_count"></span></span>
</div>
<canvas id="the-canvas"></canvas>
<script>
$(document).ready(function () {
var pdfData = atob(
'JVBERi0xLjcKCjEgMCBvYmogICUgZW50cnkgcG9pbnQKPDwKICAvVHlwZSAvQ2F0YWxvZwog' +
'IC9QYWdlcyAyIDAgUgo+PgplbmRvYmoKCjIgMCBvYmoKPDwKICAvVHlwZSAvUGFnZXMKICAv' +
'TWVkaWFCb3ggWyAwIDAgMjAwIDIwMCBdCiAgL0NvdW50IDEKICAvS2lkcyBbIDMgMCBSIF0K' +
'Pj4KZW5kb2JqCgozIDAgb2JqCjw8CiAgL1R5cGUgL1BhZ2UKICAvUGFyZW50IDIgMCBSCiAg' +
'L1Jlc291cmNlcyA8PAogICAgL0ZvbnQgPDwKICAgICAgL0YxIDQgMCBSIAogICAgPj4KICA+' +
'PgogIC9Db250ZW50cyA1IDAgUgo+PgplbmRvYmoKCjQgMCBvYmoKPDwKICAvVHlwZSAvRm9u' +
'dAogIC9TdWJ0eXBlIC9UeXBlMQogIC9CYXNlRm9udCAvVGltZXMtUm9tYW4KPj4KZW5kb2Jq' +
'Cgo1IDAgb2JqICAlIHBhZ2UgY29udGVudAo8PAogIC9MZW5ndGggNDQKPj4Kc3RyZWFtCkJU' +
'CjcwIDUwIFRECi9GMSAxMiBUZgooSGVsbG8sIHdvcmxkISkgVGoKRVQKZW5kc3RyZWFtCmVu' +
'ZG9iagoKeHJlZgowIDYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDEwIDAwMDAwIG4g' +
'CjAwMDAwMDAwNzkgMDAwMDAgbiAKMDAwMDAwMDE3MyAwMDAwMCBuIAowMDAwMDAwMzAxIDAw' +
'MDAwIG4gCjAwMDAwMDAzODAgMDAwMDAgbiAKdHJhaWxlcgo8PAogIC9TaXplIDYKICAvUm9v' +
'dCAxIDAgUgo+PgpzdGFydHhyZWYKNDkyCiUlRU9G');
// Loaded via <script> tag, create shortcut to access PDF.js exports.
var pdfjsLib = window['pdfjs-dist/build/pdf'];
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist#2.0.943/build/pdf.worker.js';
//pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
// Using DocumentInitParameters object to load binary data.
var loadingTask = pdfjsLib.getDocument({ data: pdfData });
loadingTask.promise.then(function (pdf) {
console.log('PDF loaded');
// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function (page) {
console.log('Page loaded');
var scale = 1.5;
var viewport = page.getViewport({ scale: scale });
// Prepare canvas using PDF page dimensions
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function () {
console.log('Page rendered');
});
});
}, function (reason) {
// PDF loading error
console.error(reason);
});
});
</script>
</body>
</html>
Official example fiddle: https://jsfiddle.net/pdfjs/wagvs9Lf/?utm_source=website&utm_medium=embed&utm_campaign=wagvs9Lf
My fiddle with minor change(only version): https://jsfiddle.net/94x2ozbq/
From what I figured out: var viewport = page.getViewport({ scale: scale }) returns object with height and width equal to NaN
You need to make a slight modification to the following line in renderPage(), which in current versions takes an object, but in 2.0.943 is expecting a number:
From:
var viewport = page.getViewport({scale: scale});
To:
var viewport = page.getViewport(scale);
Any-Kind-Soul-Out-there,
I spending hours figuring out how could i done the coding in such a way that when after user drawn on the canvas, they can click a btn called "save". After which the canvas's image will appear as a BG img of the webpage.
Even after user close the web browser, the bg img is still there when user open it again. I'm not sure is it possible to do it or not.
Need some help here, if need my full coding i can provide.
Below is my current coding when user clicked "save" btn. (Open new window as an image.)
// Save image
var saveImage = document.createElement("button");
saveImage.innerHTML = "Save canvas";
saveImage.addEventListener("click", function (evt) {
window.open(canvas.toDataURL("image/png"));
evt.preventDefault();
}, false);
document.getElementById("main-content").appendChild(saveImage);
You might use toDataURL to set the background, and localStorage to store 'permanently' the image :
http://jsbin.com/japekuzi/1/
use draw to fill the canvas with random rects, and set button to set and store current canvas as background.
Notice that when you (re)run the jsbin, it stills keeps its latest background.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<canvas id='cv'></canvas>
<button id='dr'>draw</button>
<button id='st'>set</button>
</body>
</html>
JS :
var $=document.getElementById.bind(document);
var cv = $('cv');
var ctx = cv.getContext('2d');
function randFill() {
ctx.clearRect(0,0,cv.width, cv.height);
for(var i=0; i<10; i++) {
var c= 0 | ( Math.random()* 360);
ctx.fillStyle = 'hsl('+c+',75%,75%)';
ctx.fillRect(Math.random()*cv.width*0.8,
Math.random()*cv.height*0.8, 20, 20);
}
}
function set() {
localStorage.setItem("bg", cv.toDataURL());
retrieve();
}
function retrieve() {
var cvURL = localStorage.getItem("bg", cv.toDataURL());
if (!cvURL) return;
document.body.style. backgroundImage ='url('+ cvURL+')';
}
randFill();
retrieve();
$('dr').onclick=randFill;
$('st').onclick=set;