mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-11 21:58:41 +02:00
MozReview-Commit-ID: IF010Y5ERks Differential Revision: https://phabricator.services.mozilla.com/D8505 --HG-- rename : browser/extensions/screenshots/webextension/assertIsBlankDocument.js => browser/extensions/screenshots/assertIsBlankDocument.js rename : browser/extensions/screenshots/webextension/assertIsTrusted.js => browser/extensions/screenshots/assertIsTrusted.js rename : browser/extensions/screenshots/webextension/background/analytics.js => browser/extensions/screenshots/background/analytics.js rename : browser/extensions/screenshots/webextension/background/auth.js => browser/extensions/screenshots/background/auth.js rename : browser/extensions/screenshots/webextension/background/communication.js => browser/extensions/screenshots/background/communication.js rename : browser/extensions/screenshots/webextension/background/deviceInfo.js => browser/extensions/screenshots/background/deviceInfo.js rename : browser/extensions/screenshots/webextension/background/main.js => browser/extensions/screenshots/background/main.js rename : browser/extensions/screenshots/webextension/background/selectorLoader.js => browser/extensions/screenshots/background/selectorLoader.js rename : browser/extensions/screenshots/webextension/background/senderror.js => browser/extensions/screenshots/background/senderror.js rename : browser/extensions/screenshots/webextension/background/startBackground.js => browser/extensions/screenshots/background/startBackground.js rename : browser/extensions/screenshots/webextension/background/takeshot.js => browser/extensions/screenshots/background/takeshot.js rename : browser/extensions/screenshots/webextension/blank.html => browser/extensions/screenshots/blank.html rename : browser/extensions/screenshots/webextension/blobConverters.js => browser/extensions/screenshots/blobConverters.js rename : browser/extensions/screenshots/webextension/build/buildSettings.js => browser/extensions/screenshots/build/buildSettings.js rename : browser/extensions/screenshots/webextension/build/inlineSelectionCss.js => browser/extensions/screenshots/build/inlineSelectionCss.js rename : browser/extensions/screenshots/webextension/build/onboardingCss.js => browser/extensions/screenshots/build/onboardingCss.js rename : browser/extensions/screenshots/webextension/build/onboardingHtml.js => browser/extensions/screenshots/build/onboardingHtml.js rename : browser/extensions/screenshots/webextension/build/selection.js => browser/extensions/screenshots/build/selection.js rename : browser/extensions/screenshots/webextension/build/shot.js => browser/extensions/screenshots/build/shot.js rename : browser/extensions/screenshots/webextension/build/thumbnailGenerator.js => browser/extensions/screenshots/build/thumbnailGenerator.js rename : browser/extensions/screenshots/webextension/catcher.js => browser/extensions/screenshots/catcher.js rename : browser/extensions/screenshots/webextension/clipboard.js => browser/extensions/screenshots/clipboard.js rename : browser/extensions/screenshots/webextension/domainFromUrl.js => browser/extensions/screenshots/domainFromUrl.js rename : browser/extensions/screenshots/webextension/icons/back-highlight.svg => browser/extensions/screenshots/icons/back-highlight.svg rename : browser/extensions/screenshots/webextension/icons/back.svg => browser/extensions/screenshots/icons/back.svg rename : browser/extensions/screenshots/webextension/icons/cancel.svg => browser/extensions/screenshots/icons/cancel.svg rename : browser/extensions/screenshots/webextension/icons/cloud.svg => browser/extensions/screenshots/icons/cloud.svg rename : browser/extensions/screenshots/webextension/icons/copied-notification.svg => browser/extensions/screenshots/icons/copied-notification.svg rename : browser/extensions/screenshots/webextension/icons/copy.svg => browser/extensions/screenshots/icons/copy.svg rename : browser/extensions/screenshots/webextension/icons/done.svg => browser/extensions/screenshots/icons/done.svg rename : browser/extensions/screenshots/webextension/icons/download.svg => browser/extensions/screenshots/icons/download.svg rename : browser/extensions/screenshots/webextension/icons/help-16.svg => browser/extensions/screenshots/icons/help-16.svg rename : browser/extensions/screenshots/webextension/icons/icon-highlight-32-v2.svg => browser/extensions/screenshots/icons/icon-highlight-32-v2.svg rename : browser/extensions/screenshots/webextension/icons/icon-v2.svg => browser/extensions/screenshots/icons/icon-v2.svg rename : browser/extensions/screenshots/webextension/icons/icon-welcome-face-without-eyes.svg => browser/extensions/screenshots/icons/icon-welcome-face-without-eyes.svg rename : browser/extensions/screenshots/webextension/icons/menu-fullpage.svg => browser/extensions/screenshots/icons/menu-fullpage.svg rename : browser/extensions/screenshots/webextension/icons/menu-myshot-white.svg => browser/extensions/screenshots/icons/menu-myshot-white.svg rename : browser/extensions/screenshots/webextension/icons/menu-myshot.svg => browser/extensions/screenshots/icons/menu-myshot.svg rename : browser/extensions/screenshots/webextension/icons/menu-visible.svg => browser/extensions/screenshots/icons/menu-visible.svg rename : browser/extensions/screenshots/webextension/icons/onboarding-1.png => browser/extensions/screenshots/icons/onboarding-1.png rename : browser/extensions/screenshots/webextension/icons/onboarding-2.png => browser/extensions/screenshots/icons/onboarding-2.png rename : browser/extensions/screenshots/webextension/icons/onboarding-4.png => browser/extensions/screenshots/icons/onboarding-4.png rename : browser/extensions/screenshots/webextension/icons/onboarding-5.png => browser/extensions/screenshots/icons/onboarding-5.png rename : browser/extensions/screenshots/webextension/log.js => browser/extensions/screenshots/log.js rename : browser/extensions/screenshots/webextension/makeUuid.js => browser/extensions/screenshots/makeUuid.js rename : browser/extensions/screenshots/webextension/manifest.json => browser/extensions/screenshots/manifest.json rename : browser/extensions/screenshots/webextension/onboarding/slides.html => browser/extensions/screenshots/onboarding/slides.html rename : browser/extensions/screenshots/webextension/onboarding/slides.js => browser/extensions/screenshots/onboarding/slides.js rename : browser/extensions/screenshots/webextension/randomString.js => browser/extensions/screenshots/randomString.js rename : browser/extensions/screenshots/webextension/selector/callBackground.js => browser/extensions/screenshots/selector/callBackground.js rename : browser/extensions/screenshots/webextension/selector/documentMetadata.js => browser/extensions/screenshots/selector/documentMetadata.js rename : browser/extensions/screenshots/webextension/selector/shooter.js => browser/extensions/screenshots/selector/shooter.js rename : browser/extensions/screenshots/webextension/selector/ui.js => browser/extensions/screenshots/selector/ui.js rename : browser/extensions/screenshots/webextension/selector/uicontrol.js => browser/extensions/screenshots/selector/uicontrol.js rename : browser/extensions/screenshots/webextension/selector/util.js => browser/extensions/screenshots/selector/util.js rename : browser/extensions/screenshots/webextension/sitehelper.js => browser/extensions/screenshots/sitehelper.js extra : rebase_source : ef20dd4f7efd19de76dd4a16a9aae43f5560fd69 extra : source : 426257ad4b83e3cffc628f76ae8bd55c2fa4fbaf
150 lines
5.4 KiB
JavaScript
150 lines
5.4 KiB
JavaScript
this.thumbnailGenerator = (function () {let exports={}; // This is used in webextension/background/takeshot.js,
|
|
// server/src/pages/shot/controller.js, and
|
|
// server/scr/pages/shotindex/view.js. It is used in a browser
|
|
// environment.
|
|
|
|
// Resize down 1/2 at a time produces better image quality.
|
|
// Not quite as good as using a third-party filter (which will be
|
|
// slower), but good enough.
|
|
const maxResizeScaleFactor = 0.5;
|
|
|
|
// The shot will be scaled or cropped down to 210px on x, and cropped or
|
|
// scaled down to a maximum of 280px on y.
|
|
// x: 210
|
|
// y: <= 280
|
|
const maxThumbnailWidth = 210;
|
|
const maxThumbnailHeight = 280;
|
|
|
|
/**
|
|
* @param {int} imageHeight Height in pixels of the original image.
|
|
* @param {int} imageWidth Width in pixels of the original image.
|
|
* @returns {width, height, scaledX, scaledY}
|
|
*/
|
|
function getThumbnailDimensions(imageWidth, imageHeight) {
|
|
const displayAspectRatio = 3 / 4;
|
|
const imageAspectRatio = imageWidth / imageHeight;
|
|
let thumbnailImageWidth, thumbnailImageHeight;
|
|
let scaledX, scaledY;
|
|
|
|
if (imageAspectRatio > displayAspectRatio) {
|
|
// "Landscape" mode
|
|
// Scale on y, crop on x
|
|
const yScaleFactor = (imageHeight > maxThumbnailHeight) ? (maxThumbnailHeight / imageHeight) : 1.0;
|
|
thumbnailImageHeight = scaledY = Math.round(imageHeight * yScaleFactor);
|
|
scaledX = Math.round(imageWidth * yScaleFactor);
|
|
thumbnailImageWidth = Math.min(scaledX, maxThumbnailWidth);
|
|
} else {
|
|
// "Portrait" mode
|
|
// Scale on x, crop on y
|
|
const xScaleFactor = (imageWidth > maxThumbnailWidth) ? (maxThumbnailWidth / imageWidth) : 1.0;
|
|
thumbnailImageWidth = scaledX = Math.round(imageWidth * xScaleFactor);
|
|
scaledY = Math.round(imageHeight * xScaleFactor);
|
|
// The CSS could widen the image, in which case we crop more off of y.
|
|
thumbnailImageHeight = Math.min(scaledY, maxThumbnailHeight,
|
|
maxThumbnailHeight / (maxThumbnailWidth / imageWidth));
|
|
}
|
|
|
|
return {
|
|
width: thumbnailImageWidth,
|
|
height: thumbnailImageHeight,
|
|
scaledX,
|
|
scaledY,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param {dataUrl} String Data URL of the original image.
|
|
* @param {int} imageHeight Height in pixels of the original image.
|
|
* @param {int} imageWidth Width in pixels of the original image.
|
|
* @param {String} urlOrBlob 'blob' for a blob, otherwise data url.
|
|
* @returns A promise that resolves to the data URL or blob of the thumbnail image, or null.
|
|
*/
|
|
function createThumbnail(dataUrl, imageWidth, imageHeight, urlOrBlob) {
|
|
// There's cost associated with generating, transmitting, and storing
|
|
// thumbnails, so we'll opt out if the image size is below a certain threshold
|
|
const thumbnailThresholdFactor = 1.20;
|
|
const thumbnailWidthThreshold = maxThumbnailWidth * thumbnailThresholdFactor;
|
|
const thumbnailHeightThreshold = maxThumbnailHeight * thumbnailThresholdFactor;
|
|
|
|
if (imageWidth <= thumbnailWidthThreshold &&
|
|
imageHeight <= thumbnailHeightThreshold) {
|
|
// Do not create a thumbnail.
|
|
return Promise.resolve(null);
|
|
}
|
|
|
|
const thumbnailDimensions = getThumbnailDimensions(imageWidth, imageHeight);
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const thumbnailImage = new Image();
|
|
let srcWidth = imageWidth;
|
|
let srcHeight = imageHeight;
|
|
let destWidth, destHeight;
|
|
|
|
thumbnailImage.onload = function() {
|
|
destWidth = Math.round(srcWidth * maxResizeScaleFactor);
|
|
destHeight = Math.round(srcHeight * maxResizeScaleFactor);
|
|
if (destWidth <= thumbnailDimensions.scaledX || destHeight <= thumbnailDimensions.scaledY) {
|
|
srcWidth = Math.round(srcWidth * (thumbnailDimensions.width / thumbnailDimensions.scaledX));
|
|
srcHeight = Math.round(srcHeight * (thumbnailDimensions.height / thumbnailDimensions.scaledY));
|
|
destWidth = thumbnailDimensions.width;
|
|
destHeight = thumbnailDimensions.height;
|
|
}
|
|
|
|
const thumbnailCanvas = document.createElement("canvas");
|
|
thumbnailCanvas.width = destWidth;
|
|
thumbnailCanvas.height = destHeight;
|
|
const ctx = thumbnailCanvas.getContext("2d");
|
|
ctx.imageSmoothingEnabled = false;
|
|
|
|
ctx.drawImage(
|
|
thumbnailImage,
|
|
0, 0, srcWidth, srcHeight,
|
|
0, 0, destWidth, destHeight);
|
|
|
|
if (thumbnailCanvas.width <= thumbnailDimensions.width ||
|
|
thumbnailCanvas.height <= thumbnailDimensions.height) {
|
|
if (urlOrBlob === "blob") {
|
|
thumbnailCanvas.toBlob((blob) => {
|
|
resolve(blob);
|
|
});
|
|
} else {
|
|
resolve(thumbnailCanvas.toDataURL("image/png"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
srcWidth = destWidth;
|
|
srcHeight = destHeight;
|
|
thumbnailImage.src = thumbnailCanvas.toDataURL();
|
|
};
|
|
thumbnailImage.src = dataUrl;
|
|
});
|
|
}
|
|
|
|
function createThumbnailUrl(shot) {
|
|
const image = shot.getClip(shot.clipNames()[0]).image;
|
|
if (!image.url) {
|
|
return Promise.resolve(null);
|
|
}
|
|
return createThumbnail(
|
|
image.url, image.dimensions.x, image.dimensions.y, "dataurl");
|
|
}
|
|
|
|
function createThumbnailBlobFromPromise(shot, blobToUrlPromise) {
|
|
return blobToUrlPromise.then(dataUrl => {
|
|
const image = shot.getClip(shot.clipNames()[0]).image;
|
|
return createThumbnail(
|
|
dataUrl, image.dimensions.x, image.dimensions.y, "blob");
|
|
});
|
|
}
|
|
|
|
if (typeof exports !== "undefined") {
|
|
exports.getThumbnailDimensions = getThumbnailDimensions;
|
|
exports.createThumbnailUrl = createThumbnailUrl;
|
|
exports.createThumbnailBlobFromPromise = createThumbnailBlobFromPromise;
|
|
}
|
|
|
|
return exports;
|
|
})();
|
|
null;
|
|
|