Parse
File Parse screenshot.js
This tree is parsed live from the source file.
Classes
-
{{ item.name }}
- {{ key }}
Not Classes
{{ getTree() }}
Comments
{{ getTreeComments() }}
Source
/*
files:
image-edge-detection.js
offscreen.js
categories: screenshot
---
Version two supplies better functionss and clipping tech.
Add extra methods to the `Scene` to capture screenshots of the canvas.
*/
class Screenshot {
fileFormat = "image/png" // "image/jpeg"
fileQuality = .9
constructor(stage) {
this.stage = stage
}
_stashBlob(uriBlob) {
this.lastStash = uriBlob
}
blobURL(blob) {
/* Given a _blob_ object, creaate an object url (a base 64 representation
of the blob) */
return URL.createObjectURL(blob);
}
revokeURL(url) {
/* Revoke an object url from memory. */
return URL.revokeObjectURL(url)
}
toBlob(callback=undefined) {
/* Call the `canvas.toBlob` function to screenshot the canvas.
Provide a callback to override the internal onScreenshot method
capture function
toBlob(function(blob){})
*/
callback = callback || this.onScreenshot.bind(this)
// const url = URL.createObjectURL(blob)
// Navtive toBlob function call.
return this.stage.canvas.toBlob((blob) => callback && callback(blob));
}
toBlobCropped(crop, callback){
callback = callback || this.onScreenshot.bind(this)
let cb = (blob) => callback && callback(blob)
// let crop = {x: 200, y:300, width: 30, height: 30}
let canvas = this.stage.canvas
return asObjectWithCrop.bind(this.stage)(canvas, this.fileFormat, this.fileQuality, crop)
// return this.stage.canvas.toBlob(cb)
}
onScreenshot(blob) {
this._stashBlob(blob)
}
createImgElement() {
/* generate a new `<img>` with the src as a new blob of the canvas.
Append to the body to present.
*/
const newImg = document.createElement("img");
this.toBlob((blob)=>{
let url = this.blobURL(blob)
newImg.onload = () => { URL.revokeObjectURL(url) };
newImg.src = url;
});
return newImg
}
downloadImage(name='polypoint-screenshot.png'){
/* Perform an image _download_ of the canvas, rendered through toBlob
This will push a new file to the client.
*/
let anchorClick = (blob) => {
const anchor = document.createElement('a');
anchor.download = name; // optional, but you can give the file a name
anchor.href = this.blobURL(blob);
anchor.click(); // ✨ magic!
// remove it to save on memory
setTimeout(()=> {
let _stage = this
_stage.revokeURL(anchor.href)
}, 500)
}
return this.toBlob(anchorClick)
}
downloadCroppedImage(name='polypoint-screenshot.png', background=undefined, borderRadius=10, dimensions=undefined){
/* grab the placement, and create a new download image with cropping.*/
if(background != undefined) {
return this.downloadCroppedImageAlphaComposite(name, background, borderRadius, dimensions)
}
let stage = this.stage
, ctx = stage.ctx
, d = dimensions || stage.dimensions
, w = d.width
, h = d.height
const initImageData = ctx.getImageData(0, 0, w, h)
let edges = detectEdges(initImageData.data, initImageData.width)
const innerPadding = 10
let offscreen = stage.offscreen.create({
width: edges.width + (innerPadding * 2)
, height: edges.height + (innerPadding * 2)
})
const imageData = ctx.getImageData(
edges.left, edges.top,
edges.width, edges.height
)
let offCtx = offscreen.getContext('2d')
offCtx.rect(0, 0, edges.width + (innerPadding * 2), edges.height + (innerPadding * 2));
offCtx.fillStyle = '#222'
offCtx.fill()
// offCtx.drawImage(offscreen, innerPadding,+ innerPadding, edges.width, edges.height, 0, 0, edges.width, edges.height);
offCtx.putImageData(imageData, 0 + innerPadding, 0 + innerPadding);
setTimeout(()=>{
let cb = (blob) => {
const anchor = document.createElement('a');
anchor.download = name
anchor.href = this.blobURL(blob);
anchor.click()
let _stage = this
// setTimeout(()=> _stage.revokeURL(anchor.href), 1000)
setTimeout(()=> {
let _stage = this
_stage.revokeURL(anchor.href)
}, 500)
}
offscreen.convertToBlob().then(cb);
}, 1)
}
downloadCroppedImageAlphaComposite(name='polypoint-screenshot.png',
background=undefined, borderRadius=10, dimensions=undefined){
let stage = this.stage
, ctx = stage.ctx
, d = dimensions || stage.dimensions
, w = d.width
, h = d.height
const initImageData = ctx.getImageData(0, 0, w, h)
let edges = detectEdges(initImageData.data, initImageData.width)
const innerPadding = 10
let offscreen = stage.offscreen.create({
width: edges.width + (innerPadding * 2),
height: edges.height + (innerPadding * 2)
})
const imageData = ctx.getImageData(
edges.left, edges.top,
edges.width, edges.height
)
let offCtx = offscreen.getContext('2d')
// Draw background
offCtx.fillStyle = background
// offCtx.fillRect(0, 0, offscreen.width, offscreen.height)
offCtx.roundRect(0, 0, offscreen.width, offscreen.height, 10)
offCtx.fill()
// Create temp canvas for proper blending
let tempCanvas = document.createElement('canvas')
tempCanvas.width = imageData.width
tempCanvas.height = imageData.height
let tempCtx = tempCanvas.getContext('2d')
tempCtx.putImageData(imageData, 0, 0)
// Draw blended image on top
offCtx.drawImage(
tempCanvas,
0, 0, imageData.width, imageData.height,
innerPadding, innerPadding, imageData.width, imageData.height
)
setTimeout(()=>{
let cb = (blob) => {
const anchor = document.createElement('a');
anchor.download = name
anchor.href = this.blobURL(blob);
anchor.click()
let _stage = this
// setTimeout(()=> _stage.revokeURL(anchor.href), 1000)
setTimeout(()=> {
let _stage = this
_stage.revokeURL(anchor.href)
}, 500)
}
offscreen.convertToBlob().then(cb);
}, 1)
}
// asDownloadLink(name="polypoint-screenshot.png") {
// const linkObjectUrl = document.createElement("a");
// linkObjectUrl.download = name
// linkObjectUrl.innerHTML = 'Download'
// linkObjectUrl.onclick = function(e) {
// setTimeout(()=> URL.revokeObjectURL(linkObjectUrl), 1000)
// linkObjectUrl.remove()
// }
// document.body.appendChild(linkObjectUrl);
// let cb = (url) => {
// linkObjectUrl.href = url
// }
// this.toBlob(cb);
// }
}
Polypoint.head.install(Screenshot)
Polypoint.head.lazierProp('Stage',
function screenshot() {
console.log('make screenshot', this)
return new Screenshot(this)
}
)
asObjectUrl = async function(width, height, callback) {
let quality = .8
let canvas = stage.canvas
let objectUrl = await canvas.toObjectURL("image/jpeg", quality);
// let dataUrl = canvas.toDataURL("image/webp", quality);
// set object URLs
// linkObjectUrl.href = objectUrl;
let p = asObjectUrl()
return p.then((d)=>console.log('got data'));
// return p//.then(console.log);
}
const asObject = async function(mimeType="image/jpeg", quality = 0.85) {
let promiseFunc = (resolve, reject) => {
let caller = (blob) => {
if (!blob) {
reject("Error creating blob");
return;
}
const blobUrl = URL.createObjectURL(blob);
resolve(blobUrl);
};
this.toBlob(caller, mimeType, quality);
}
return new Promise(promiseFunc);
};
const asObjectWithCrop = async function(canvas, mimeType = "image/jpeg", quality = 0.85, crop = null) {
// const canvas = this;
const innerPadding = 20;
const promiseFunc = (resolve, reject) => {
let targetCanvas = canvas;
if (crop) {
const { x, y, width, height } = crop;
targetCanvas = document.createElement("canvas");
targetCanvas.width = width + innerPadding;
targetCanvas.height = height + innerPadding;
const ctx = targetCanvas.getContext("2d");
ctx.rect(0, 0, width, height);
ctx.fillStyle = '#222'
ctx.fill()
// ctx.putImageData(canvas, 0, 0);
ctx.drawImage(canvas, x + innerPadding, y + innerPadding, width, height, 0, 0, width, height);
}
targetCanvas.toBlob((blob) => {
if (!blob) {
reject("Error creating blob");
return;
}
// const blobUrl = URL.createObjectURL(blob);
// resolve(blobUrl);
resolve(blob);
}, mimeType, quality);
};
return new Promise(promiseFunc);
};
// HTMLCanvasElement.prototype.toObjectURL = asObjectWithCrop;
copy