Das Skript bietet vier Optionen für die Erstellung eines Screenshots einer Seite
JavaScript
// SavePageAsPNG.uc.js
(async func => CustomizableUI.createWidget({
id: "SavePageAsPNG",
label: "Save Page As PNG",
tooltiptext: "Save Page As PNG",
localized: false,
// defaultArea: CustomizableUI.AREA_NAVBAR,
onCreated(btn) {
var win = btn.ownerGlobal;
new win.Function("_id, xhtmlns, addDestructor", func.toString().slice(7, -1)).call(
btn, this.id, "http://www.w3.org/1999/xhtml",
destructor => win.addEventListener("unload", destructor, {once: true})
);
btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAGwSURBVHjarJPPaxNBGIafmd1km23saqtRaLB6kFYl2ELpRayCVL20RvCmJwk9ePNWvPsXtCA9eNCDeO0hLemPo96LYAuKkRhtsBViEtI0rrt+GyFQ1oMkfjAf883M+8w7w4zyfZ9uwsxms10RzCBNTd3sSLy2lvsDCCKzWMCKGHgotOTAlpamJPm+jCmFL00bmmbD5WlmsKXTdBltB3bcxowaLWJwsTpi4bvNVu1JMmVn5cmcqTB6/DAg3hcjGpUFskjZjlgFKdmvVIiISKlfUhlyQMVPywgDjvX1YCjpOBZ2fZ+9+TuUpxcZuz7Ebl7ArkfM0dgDcOAFCvfwHTi9URJJi2RCqEuPmRxPUXn9imodLo1D6orGjMHW6govZqfDDkYviDXBlZ4vsFsrk8vXqZRWeDY8hz55lvvpGU7sFEn0RhhTtTBg/tETCvlNdj68papsUoND3Lh6iyPOOYrvv/JufYNrqcssbW8zkjwdBnz7/JKL50/x4F4at9GgsFckX/2IefQHZyb6mbl9l2LpE8ff1PnufWkD/t87yC1v/pvi4V8AwZvuNFS33/m3AAMAhEeAiqLmty4AAAAASUVORK5CYII=");
}
}))(() => {
((main, parts) => this._handleClick = () => {
var df = MozXULElement.parseXULToFragment(`
<menupopup>
<menuitem class="menuitem-iconic"
image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAOwSURBVHjaYmBiYuJvamo+xiIsLLL3uaazMUAAMTY3txxjAAFubq7/ZiYm/wECACIA3f8AGhobzGhoaP8QFRr/6enp/wT5+fgBLS0tAOLi4gCnp6cAAoixtrbuFBsb6x+QNnZ2jo0MXz9/+Qdk/wfhO3fu/Gc5cuwoA4NqHEOoszjDrVu3GFiAogxJtiwMagrCQHMeMgAEoHhsdRCG4Tj463+rxGFIqN2CYI7wBpiaWhzPheF5SMhIKliCYiQtyTC4hvSLcu7cHYQQl5SSDyFGa23UWkfvfXTORWNMpiIYH2NV1xXN5gvq9kfqNjtSStF7mkAhBPTXHm3TYL1qsV2+8LyfIaXEbRjAyuzpUOCcI+cMYgzp31hCnft+fgII6Cm95oiICOd///4CFTAwAOWBgBFIM7Lw8vLZM5w7d+7/t2/fwA4DOfDp02d/QQ4GWv1z6tSpU5g+ffrI8OnTJyagFUx2Tu5MsnIyTDk52UyfPn5k/vXr9x+mjx8+MsTFxTGERMUzVK09yCAsn8AwY+ZMhlevX0Pc9PTZM4a3b94wXHjwmaEsu5th87GpQIcyMdy+fZvh79+/DEwfP35giIuPZ3hzbTeDCtcjhngnEwZVVRWGz58/g+ON5dOnz6BYYKioqGY4eOggg5SuBYORkRHDixcvQL5hZNTR0flnY2PD+O8fKAwYgGHwHyTMwMzMwrBt2zZHgAA9Uz1Lw1AUPWlKE1vFlEIFHRoKQgcRtDSLIAiCgoJuiovYP6DopnR1EdRYHO3W6tbg5K5LwclmVQviRwutpSaQtI3P+yIK7/Eu94t77jkPiqIcGUaZ5vlmlvXFbNui12LEBSPo/uU29/EYrYQ1m01WqVRYPn++FQiHI3Mj8RG4jst7wHFcFAoFaFoGsixBliRoGc338dg3AQuKojc2OoZ+vzcZ4JRwQNQAxVIJsVgMuVwO8/OL2D29xPjSHvpCHAf7+36M57iuSzUdnzISg4d3AvxgVqHrJ5BCIcxu7KCdWoLx3MFLaBjOxDJSC1lIsowzXUfVNFEnJflrJi2i1WrBtm1MpzNgAoN5U8TtySE61Sccb6/jIjuF3uMduo5DOWk/l9fwxQr0o+6J+rSqqlxjQq1WQ9kw8PH2CoF5cLtd8gaRSCSwsrqKZDJJu3A8WZbFer2hB2nLAc5ZNBplHFskEsEmSUcURV8q+GXTH5ffBo1OUzNFGUa7/cm4eGcEIbA2MBBW6df8VnC1s3/zv8mfScchaq+GhgavfwBr4dP0kYqtcwAAAABJRU5ErkJggg=="
label="Save whole page as PNG"
value="all"/>
<menuitem class="menuitem-iconic"
image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAOwSURBVHjaYmBiYuJvamo+xiIsLLL3uaazMUAAMTY3txxjAAFubq7/ZiYm/wECACIA3f8AGhobzGhoaP8QFRr/6enp/wT5+fgBLS0tAOLi4gCnp6cAAoixtrbuFBsb6x+QNnZ2jo0MXz9/+Qdk/wfhO3fu/Gc5cuwoA4NqHEOoszjDrVu3GFiAogxJtiwMagrCQHMeMgAEoHhsdRCG4Tj463+rxGFIqN2CYI7wBpiaWhzPheF5SMhIKliCYiQtyTC4hvSLcu7cHYQQl5SSDyFGa23UWkfvfXTORWNMpiIYH2NV1xXN5gvq9kfqNjtSStF7mkAhBPTXHm3TYL1qsV2+8LyfIaXEbRjAyuzpUOCcI+cMYgzp31hCnft+fgII6Cm95oiICOd///4CFTAwAOWBgBFIM7Lw8vLZM5w7d+7/t2/fwA4DOfDp02d/QQ4GWv1z6tSpU5g+ffrI8OnTJyagFUx2Tu5MsnIyTDk52UyfPn5k/vXr9x+mjx8+MsTFxTGERMUzVK09yCAsn8AwY+ZMhlevX0Pc9PTZM4a3b94wXHjwmaEsu5th87GpQIcyMdy+fZvh79+/DEwfP35giIuPZ3hzbTeDCtcjhngnEwZVVRWGz58/g+ON5dOnz6BYYKioqGY4eOggg5SuBYORkRHDixcvQL5hZNTR0flnY2PD+O8fKAwYgGHwHyTMwMzMwrBt2zZHgAA9Uz1Lw1AUPWlKE1vFlEIFHRoKQgcRtDSLIAiCgoJuiovYP6DopnR1EdRYHO3W6tbg5K5LwclmVQviRwutpSaQtI3P+yIK7/Eu94t77jkPiqIcGUaZ5vlmlvXFbNui12LEBSPo/uU29/EYrYQ1m01WqVRYPn++FQiHI3Mj8RG4jst7wHFcFAoFaFoGsixBliRoGc338dg3AQuKojc2OoZ+vzcZ4JRwQNQAxVIJsVgMuVwO8/OL2D29xPjSHvpCHAf7+36M57iuSzUdnzISg4d3AvxgVqHrJ5BCIcxu7KCdWoLx3MFLaBjOxDJSC1lIsowzXUfVNFEnJflrJi2i1WrBtm1MpzNgAoN5U8TtySE61Sccb6/jIjuF3uMduo5DOWk/l9fwxQr0o+6J+rSqqlxjQq1WQ9kw8PH2CoF5cLtd8gaRSCSwsrqKZDJJu3A8WZbFer2hB2nLAc5ZNBplHFskEsEmSUcURV8q+GXTH5ffBo1OUzNFGUa7/cm4eGcEIbA2MBBW6df8VnC1s3/zv8mfScchaq+GhgavfwBr4dP0kYqtcwAAAABJRU5ErkJggg=="
label="Save visible part of the page as PNG"
value="page"/>
<menuitem class="menuitem-iconic"
image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKaSURBVHjaYpx94sPD44//CDG9+/SDp8bsBw9AADEmrX7zmQEIGF+//fD/w8dPDAABxNix6/nbcA0GIQYoYGJiZGSQFBdmOHnqLAMrKwsDQAAxJq958/n/f4jsm2//GBifP3v+/8cfiMDDj/8ZmHi5ORl4gPjPn18M///9ZWDh5uVm4GJkYfj56zcD9z9GBoAAYmwH2aL8UwimDRk8+fyfgYWRgZFBgI+b4TsWBR+BtoNcxcDDwwW2R1iQn2HvgcMMX799Y/j6/TvDzz+/GVj+/fvPvO0BC8N/oGpGhv8ML3m0GS59EwWbcP/9XwaAAGSRwQ3CMAxFfxq3TgrqiSMswARMwSJMxZEdGAXBAEiQquICJMFuekDqwTlY38/Wi9kf78OqNTO8kndretBh+1puuvl+R8Dpwm9iruG8xPP/tIGzhULc1OB6voJJXxGjQpumGpsKCc8wEqISwGJfA1P1IYCEmCegkTmqLIELT/8KC+/x+cbxBpEPOl8zbn0q5voWXdcipQQrgZiC/QlQORmzNBAEUfjt7N4ichBUDIKCWNsJhiBiZ2mZf5XC0v/gT7C10lqwNMVBkBC9kKAmt7e+uQtJxBS6cNwy7L2b981bTrz/fnmIxnHTYN081i1F8PQacddDzm0M+UfAYPw/gfyTlqMNVfOJVxIGpfxNgMcZRwoYpkVpe1ezLn/jplc7B2wWb+1gwwfuvxg31lwi7MAimOU4E+IevuXoXt+gILTE1aQ1VBJnwNYR9ltXFKCweM9RWFpYCnjWiukU7dYJLs7PUMyKuglNAZt6GVncZ7SgIU2ZJ8M/bLqVQEFYN9hJPQ5201pgvhztjnk2ZhOYh+esd/vY39ZPZYWBXlURqZ4Qwg8uZXU3gM7p3vAbsXveewxHZWUAAAAASUVORK5CYII="
label="Save selected page element as PNG"
value="click"/>
<menuitem class="menuitem-iconic"
image="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAFo9M/3AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAL/SURBVHjaYijccvd25ZHvv5n4RSUVQs2vswAEECOIxwACy+8v/3/30Zv/AAHE0Hb6y+//UPDv4///LD/+MjJ8+PqF4cvnnww/vgkxAAQQY8Xhb78YgQCsj5mFgQGm/P+v///fvvj/n+n/fwaGe//vMexg2Mrw7BsDA8vXHwwMPN/5GdQ/mzG8BbIBAoiRfdqvX8xf/rBCDAEaAWL8ByOgmZwMLBXGvxnrzLgYVj9cyfCL+TfDj9+/Gd7//sAQw5vK8PEXAwMTRBsD0Li3DNKikgwC4twM3NIMDF9/fGf4CVTA8u0fM+ODjwwM7qJZDH8/MTBI/GFgUAba/QYo+fEnAwNAADKoXQVhIAjOJYfgsxIR/AwRi/yBlY3gz9j7FUI+wt7CwkbEzs7CNIo2Yl53t3duElDBhYXZZXaWGbHYKW0M4b+cex7WG9FaxmxGfNcfYNH3T+pr/LcSzu1h3Wx11EU2eOkYYRSi7jVgrQeb1TDtzFHkLgu13GQIBgGkJ6GFxva8h6XqX0kgRlF+AfkEw4S7ujEGbKnAzDa6GNEYLvOh2N6wOUGaVXHKayqQsHeiHgyfqKJ51sbxjvAWoG1qWWkYiKJnZhKTpgapK1tEslRw50+4camIGz/ObfcuBP0HBREEn12I+MBUadPM5HomqbWgi8kJydzHOfdctXmU29Vhbhqq8leNfxQyLP6lWgjjdxds9Yxs95ZRVAo+h8yFqEau2fHEKjpKqgojRDg+H0iw1gb212NY2oC/MCxz5DxGaYgPsKrGsnRYUEusnvKb4MNqnBlN5aZD8q54Hb2gP+gj62bohOyKdVxgobTBk3vE7cMzDhYPkVA0NW0xaBrlk6BZtRN20I16SMIWPt0CJlLQowqJStE2YwqnQRbE2ZwazrYURDquL5zcnCINU4xdiYo7QXXo4TesSMaIGGRTJ6jnqBxvkJNwfhFa2Ovu1jlrwXjD2gZ9wITeKVhImEFXgXcIgrvri/udqySztpDZemJurTzK70h/3h1xY3xpvwGLI42vrCwxmAAAAABJRU5ErkJggg=="
label="Save selected page area as PNG"
value="clipping"/>
</menupopup>
`);
var popup = df.firstChild;
popup.setAttribute("context", "");
popup.addEventListener("command", e => popup.handleCommand(e));
popup.handleCommand = e => {
var name = _id + ":DataURLReady";
main = main.replace("%MESSAGE_NAME%", name);
var urls = {}, configurable = true, enumerable = true;
Object.entries(parts).forEach(([key, part]) => Object.defineProperty(urls, key, {
configurable, enumerable, get() {
var value = `data:;charset=utf-8,({${
encodeURIComponent(main + part)
}%0A}).init("${key}")`;
Object.defineProperty(urls, key, {configurable, enumerable, value});
return value;
}}));
// Get tab name without non-saved characters and extra spaces
var getTabLabel = () => {
var label = gBrowser.selectedTab.label;
var label = label.replace(/[:+.\\\/<>?*|"]+/g, " ").replace(/\s\s+/g, " ");
return label.substring(0, 50);
}
var listener = msg => {
var fp = makeFilePicker();
// fp.init(window, "Save As…", fp.modeSave);
fp.init(
!("inIsolatedMozBrowser" in window.browsingContext.originAttributes)
? window.browsingContext
: window
, "Save As…", fp.modeSave);
fp.appendFilter("", "*.png");
var fileName = getTabLabel();
fileName = fileName.replace(/[:\\\/<>?*|"]+/g, '').replace(/\s+/g, '_').slice(0, 100).replace(/^\s+|\s+$/g, '');
var fileDate = (function () {
var d = new Date(), z = function(n){return (n < 10 ? '0' : '') + n};
return '[' + z(d.getFullYear()) + '_' + z(d.getMonth()+1) + '_' + z(d.getDate()) + '\u2014' + z(d.getHours()) + '_' + z(d.getMinutes()) + '_' + z(d.getSeconds()) + ']';
})();
fp.defaultString = fileName + "_" + fileDate + ".png";
fp.open(res => res == fp.returnCancel || !fp.file || makeWebBrowserPersist().saveURI(
Services.io.newURI(msg.data), document.nodePrincipal,
null, null, null, null, null, fp.file, null, null
));
}
messageManager.addMessageListener(name, listener);
addDestructor(() => messageManager.removeMessageListener(name, listener));
(popup.handleCommand = e => gBrowser.selectedBrowser.messageManager
.loadFrameScript(urls[e.target.value], false)
)(e);
}
this.append(df);
(this._handleClick = () => popup.openPopup(this, "after_start"))();
})(`
init(cmd) {
cmd.startsWith("c")
? this[cmd].init(this[cmd].parent = this)
: this[cmd]();
},
capture(win, x, y, width, height) {
var canvas = win.document.createElementNS("${xhtmlns}", "canvas");
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
var tryDraw = ind => {
try {ctx.drawWindow(win, x, y, canvas.width, canvas.height, "white")}
catch(ex) {canvas.height = ind * canvas.width; tryDraw(--ind);}
}
tryDraw(17);
sendAsyncMessage("%MESSAGE_NAME%", canvas.toDataURL("image/png"));
},
`, {
all: `all() {
var win = content;
this.capture(win, 0, 0, win.innerWidth + win.scrollMaxX, win.innerHeight + win.scrollMaxY);
}`,
page: `page() {
var win = content, doc = win.document, body = doc.body, html = doc.documentElement;
var scrX = (body.scrollLeft || html.scrollLeft) - html.clientLeft;
var scrY = (body.scrollTop || html.scrollTop) - html.clientTop;
this.capture(win, scrX, scrY, win.innerWidth, win.innerHeight);
}`,
clipping: `clipping: {
handleEvent(e) {
if (e.button) return false;
e.preventDefault();
e.stopPropagation();
switch(e.type) {
case "mousedown":
this.downX = e.pageX;
this.downY = e.pageY;
this.bs.left = this.downX + "px";
this.bs.top = this.downY + "px";
this.body.appendChild(this.box);
this.flag = true;
break;
case "mousemove":
if (!this.flag) return;
this.moveX = e.pageX;
this.moveY = e.pageY;
if (this.downX > this.moveX) this.bs.left = this.moveX + "px";
if (this.downY > this.moveY) this.bs.top = this.moveY + "px";
this.bs.width = Math.abs(this.moveX - this.downX) + "px";
this.bs.height = Math.abs(this.moveY - this.downY) + "px";
break;
case "mouseup":
this.uninit();
break;
}
},
init() {
var win = {};
Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager)
.getFocusedElementForWindow(content, true, win);
this.win = win.value;
this.doc = this.win.document;
this.body = this.doc.body;
if (!HTMLBodyElement.isInstance(this.body)) {
Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService)
.showAlertNotification("${self.image}", ${JSON.stringify(self.label)}, "Не удается захватить!");
return false;
}
this.flag = null;
this.box = this.doc.createElement("div");
this.bs = this.box.style;
this.bs.border = "red dashed 1px";
this.bs.position = "absolute";
this.bs.zIndex = "2147483647";
this.defaultCursor = this.win.getComputedStyle(this.body, "").cursor;
this.body.style.cursor = "crosshair";
["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.addEventListener(type, this, true));
},
uninit() {
var pos = [this.win, parseInt(this.bs.left), parseInt(this.bs.top), parseInt(this.bs.width), parseInt(this.bs.height)];
this.body.style.cursor = this.defaultCursor;
this.body.removeChild(this.box);
this.parent.capture.apply(this, pos);
["click", "mouseup", "mousemove", "mousedown"].forEach(type=> this.doc.removeEventListener(type, this, true));
}
}`,
click: `click: {
getPosition() {
var html = this.doc.documentElement;
var body = this.doc.body;
var rect = this.target.getBoundingClientRect();
return [
this.win,
Math.round(rect.left) + (body.scrollLeft || html.scrollLeft) - html.clientLeft,
Math.round(rect.top) + (body.scrollTop || html.scrollTop) - html.clientTop,
parseInt(rect.width),
parseInt(rect.height)
];
},
highlight() {
this.orgStyle = this.target.hasAttribute("style") ? this.target.style.cssText : false;
this.target.style.cssText += "outline: red 1px solid; outline-offset: 1px; -moz-outline-radius: 2px;";
},
lowlight() {
if (this.orgStyle) this.target.style.cssText = this.orgStyle;
else this.target.removeAttribute("style");
},
handleEvent(e) {
switch(e.type){
case "click":
if (e.button) return;
e.preventDefault();
e.stopPropagation();
this.lowlight();
this.parent.capture.apply(this, this.getPosition());
this.uninit();
break;
case "mouseover":
if (this.target) this.lowlight();
this.target = e.target;
this.highlight();
break;
}
},
init() {
this.win = content;
this.doc = content.document;
["click", "mouseover"].forEach(type=> this.doc.addEventListener(type, this, true));
},
uninit() {
this.target = false;
["click", "mouseover"].forEach(type=> this.doc.removeEventListener(type, this, true));
}
}`
});
});
Alles anzeigen