Firefox 如何为新标签页生成页面缩略图?
How does Firefox generate page thumbnails for new tab page?
在 Firefox 中,默认的新标签页包含一个带有页面域名和缩略图的网页推荐列表。如果足够大,缩略图可以是网站图标,也可以是网页的预览图像。比如这个example.
我正在尝试使用类似于 Firefox 的缩略图创建我自己的新标签页版本。网上的解决方案大多建议部署服务器(如via node.js) or use a service (e.g. URL2PNG)。
因此,我很好奇Firefox是如何在客户端生成缩略图的(如果是服务器端请指正)。有没有推荐的libraries/frameworks(比如html2canvas虽然不能截图其他网站)?
不确定这对您的情况有多大用处,但它使用(非标准,内部)CanvasRenderingContext2D.drawWindow() API 将 window 的快照呈现为中间 canvas,然后将其复制到目标缩小的 canvas 元素。
您可以在 toolkit/components/thumbnails/PageThumbUtils.jsm 中看到执行此操作的代码:
/** *
* Given a browser window, this creates a snapshot of the content
* and returns a canvas with the resulting snapshot of the content
* at the thumbnail size. It has to do this through a two step process:
*
* 1) Render the content at the window size to a canvas that is 2x the thumbnail size
* 2) Downscale the canvas from (1) down to the thumbnail size
*
* This is because the thumbnail size is too small to render at directly,
* causing pages to believe the browser is a small resolution. Also,
* at that resolution, graphical artifacts / text become very jagged.
* It's actually better to the eye to have small blurry text than sharp
* jagged pixels to represent text.
*
* @params aWindow - the window to create a snapshot of.
* @params aDestCanvas destination canvas to draw the final
* snapshot to. Can be null.
* @param aArgs (optional) Additional named parameters:
* fullScale - request that a non-downscaled image be returned.
* @return Canvas with a scaled thumbnail of the window.
*/
createSnapshotThumbnail(aWindow, aDestCanvas, aArgs) {
if (Cu.isCrossProcessWrapper(aWindow)) {
throw new Error("Do not pass cpows here.");
}
let fullScale = aArgs ? aArgs.fullScale : false;
let [contentWidth, contentHeight] = this.getContentSize(aWindow);
let [thumbnailWidth, thumbnailHeight] = aDestCanvas ?
[aDestCanvas.width, aDestCanvas.height] :
this.getThumbnailSize(aWindow);
// If the caller wants a fullscale image, set the desired thumbnail dims
// to the dims of content and (if provided) size the incoming canvas to
// support our results.
if (fullScale) {
thumbnailWidth = contentWidth;
thumbnailHeight = contentHeight;
if (aDestCanvas) {
aDestCanvas.width = contentWidth;
aDestCanvas.height = contentHeight;
}
}
let intermediateWidth = thumbnailWidth * 2;
let intermediateHeight = thumbnailHeight * 2;
let skipDownscale = false;
// If the intermediate thumbnail is larger than content dims (hiDPI
// devices can experience this) or a full preview is requested render
// at the final thumbnail size.
if ((intermediateWidth >= contentWidth ||
intermediateHeight >= contentHeight) || fullScale) {
intermediateWidth = thumbnailWidth;
intermediateHeight = thumbnailHeight;
skipDownscale = true;
}
// Create an intermediate surface
let snapshotCanvas = this.createCanvas(aWindow, intermediateWidth,
intermediateHeight);
// Step 1: capture the image at the intermediate dims. For thumbnails
// this is twice the thumbnail size, for fullScale images this is at
// content dims.
// Also by default, canvas does not draw the scrollbars, so no need to
// remove the scrollbar sizes.
let scale = Math.min(Math.max(intermediateWidth / contentWidth,
intermediateHeight / contentHeight), 1);
let snapshotCtx = snapshotCanvas.getContext("2d");
snapshotCtx.save();
snapshotCtx.scale(scale, scale);
snapshotCtx.drawWindow(aWindow, 0, 0, contentWidth, contentHeight,
PageThumbUtils.THUMBNAIL_BG_COLOR,
snapshotCtx.DRAWWINDOW_DO_NOT_FLUSH);
snapshotCtx.restore();
// Part 2: Downscale from our intermediate dims to the final thumbnail
// dims and copy the result to aDestCanvas. If the caller didn't
// provide a target canvas, create a new canvas and return it.
let finalCanvas = aDestCanvas ||
this.createCanvas(aWindow, thumbnailWidth, thumbnailHeight);
let finalCtx = finalCanvas.getContext("2d");
finalCtx.save();
if (!skipDownscale) {
finalCtx.scale(0.5, 0.5);
}
finalCtx.drawImage(snapshotCanvas, 0, 0);
finalCtx.restore();
return finalCanvas;
},
在 Firefox 中,默认的新标签页包含一个带有页面域名和缩略图的网页推荐列表。如果足够大,缩略图可以是网站图标,也可以是网页的预览图像。比如这个example.
我正在尝试使用类似于 Firefox 的缩略图创建我自己的新标签页版本。网上的解决方案大多建议部署服务器(如via node.js) or use a service (e.g. URL2PNG)。
因此,我很好奇Firefox是如何在客户端生成缩略图的(如果是服务器端请指正)。有没有推荐的libraries/frameworks(比如html2canvas虽然不能截图其他网站)?
不确定这对您的情况有多大用处,但它使用(非标准,内部)CanvasRenderingContext2D.drawWindow() API 将 window 的快照呈现为中间 canvas,然后将其复制到目标缩小的 canvas 元素。
您可以在 toolkit/components/thumbnails/PageThumbUtils.jsm 中看到执行此操作的代码:
/** *
* Given a browser window, this creates a snapshot of the content
* and returns a canvas with the resulting snapshot of the content
* at the thumbnail size. It has to do this through a two step process:
*
* 1) Render the content at the window size to a canvas that is 2x the thumbnail size
* 2) Downscale the canvas from (1) down to the thumbnail size
*
* This is because the thumbnail size is too small to render at directly,
* causing pages to believe the browser is a small resolution. Also,
* at that resolution, graphical artifacts / text become very jagged.
* It's actually better to the eye to have small blurry text than sharp
* jagged pixels to represent text.
*
* @params aWindow - the window to create a snapshot of.
* @params aDestCanvas destination canvas to draw the final
* snapshot to. Can be null.
* @param aArgs (optional) Additional named parameters:
* fullScale - request that a non-downscaled image be returned.
* @return Canvas with a scaled thumbnail of the window.
*/
createSnapshotThumbnail(aWindow, aDestCanvas, aArgs) {
if (Cu.isCrossProcessWrapper(aWindow)) {
throw new Error("Do not pass cpows here.");
}
let fullScale = aArgs ? aArgs.fullScale : false;
let [contentWidth, contentHeight] = this.getContentSize(aWindow);
let [thumbnailWidth, thumbnailHeight] = aDestCanvas ?
[aDestCanvas.width, aDestCanvas.height] :
this.getThumbnailSize(aWindow);
// If the caller wants a fullscale image, set the desired thumbnail dims
// to the dims of content and (if provided) size the incoming canvas to
// support our results.
if (fullScale) {
thumbnailWidth = contentWidth;
thumbnailHeight = contentHeight;
if (aDestCanvas) {
aDestCanvas.width = contentWidth;
aDestCanvas.height = contentHeight;
}
}
let intermediateWidth = thumbnailWidth * 2;
let intermediateHeight = thumbnailHeight * 2;
let skipDownscale = false;
// If the intermediate thumbnail is larger than content dims (hiDPI
// devices can experience this) or a full preview is requested render
// at the final thumbnail size.
if ((intermediateWidth >= contentWidth ||
intermediateHeight >= contentHeight) || fullScale) {
intermediateWidth = thumbnailWidth;
intermediateHeight = thumbnailHeight;
skipDownscale = true;
}
// Create an intermediate surface
let snapshotCanvas = this.createCanvas(aWindow, intermediateWidth,
intermediateHeight);
// Step 1: capture the image at the intermediate dims. For thumbnails
// this is twice the thumbnail size, for fullScale images this is at
// content dims.
// Also by default, canvas does not draw the scrollbars, so no need to
// remove the scrollbar sizes.
let scale = Math.min(Math.max(intermediateWidth / contentWidth,
intermediateHeight / contentHeight), 1);
let snapshotCtx = snapshotCanvas.getContext("2d");
snapshotCtx.save();
snapshotCtx.scale(scale, scale);
snapshotCtx.drawWindow(aWindow, 0, 0, contentWidth, contentHeight,
PageThumbUtils.THUMBNAIL_BG_COLOR,
snapshotCtx.DRAWWINDOW_DO_NOT_FLUSH);
snapshotCtx.restore();
// Part 2: Downscale from our intermediate dims to the final thumbnail
// dims and copy the result to aDestCanvas. If the caller didn't
// provide a target canvas, create a new canvas and return it.
let finalCanvas = aDestCanvas ||
this.createCanvas(aWindow, thumbnailWidth, thumbnailHeight);
let finalCtx = finalCanvas.getContext("2d");
finalCtx.save();
if (!skipDownscale) {
finalCtx.scale(0.5, 0.5);
}
finalCtx.drawImage(snapshotCanvas, 0, 0);
finalCtx.restore();
return finalCanvas;
},