take-shot
Version:
Screenshots with JavaScript
115 lines • 6.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const bounds_1 = require("./css/layout/bounds");
const color_1 = require("./css/types/color");
const document_cloner_1 = require("./dom/document-cloner");
const node_parser_1 = require("./dom/node-parser");
const cache_storage_1 = require("./core/cache-storage");
const foreignobject_renderer_1 = require("./render/canvas/foreignobject-renderer");
const context_1 = require("./core/context");
const loading_1 = require("./utils/loading");
const imageMap = {
png: 'image/png',
jpeg: 'image/jpeg',
webp: 'image/webp'
};
const takeShot = (element, options = {}) => {
return renderElement(element, options);
};
exports.default = takeShot;
if (typeof window !== 'undefined') {
cache_storage_1.CacheStorage.setContext(window);
}
const renderElement = async (element, opts) => {
if (!element || typeof element !== 'object') {
return Promise.reject('Invalid element provided as first argument');
}
const { removeLoading, insertLoading } = (0, loading_1.useLoading)(element, opts.loading);
insertLoading();
const ownerDocument = element.ownerDocument;
if (!ownerDocument) {
throw new Error(`Element is not attached to a Document`);
}
const defaultView = ownerDocument.defaultView;
if (!defaultView) {
throw new Error(`Document is not attached to a Window`);
}
const resourceOptions = {
allowTaint: opts.allowTaint ?? false,
imageTimeout: opts.imageTimeout ?? 15000
};
const contextOptions = {
logging: opts.logging ?? true,
...resourceOptions
};
const windowOptions = {
windowWidth: opts.windowWidth ?? defaultView.innerWidth,
windowHeight: opts.windowHeight ?? defaultView.innerHeight,
scrollX: opts.scrollX ?? defaultView.pageXOffset,
scrollY: opts.scrollY ?? defaultView.pageYOffset
};
const windowBounds = new bounds_1.Bounds(windowOptions.scrollX, windowOptions.scrollY, windowOptions.windowWidth, windowOptions.windowHeight);
const context = new context_1.Context(contextOptions, windowBounds);
const cloneOptions = {
allowTaint: opts.allowTaint ?? false,
onclone: opts.onclone,
ignoreElements: opts.ignoreElements,
cssRuleSelector: opts.cssRuleSelector,
inlineImages: true
};
context.logger.debug(`Starting document clone with size ${windowBounds.width}x${windowBounds.height} scrolled to ${-windowBounds.left},${-windowBounds.top}`);
const documentCloner = new document_cloner_1.DocumentCloner(context, element, cloneOptions);
const clonedElement = documentCloner.documentElement;
if (!clonedElement) {
return Promise.reject(`Unable to find element in cloned iframe`);
}
const imagePlaceholder = opts.imagePlaceholder || 'data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' width=\'36\' height=\'36\' viewBox=\'0 0 36 36\' fill=\'none\' stroke-width=\'1.5\'%3E%3Crect width=\'36\' height=\'36\' fill=\'white\'/%3E%3Cpath d=\'M20 15.3333H20.0067M12 20.6667L15.3333 17.3333C15.952 16.738 16.7147 16.738 17.3333 17.3333L20.6667 20.6667M19.3333 19.3333L20 18.6667C20.6187 18.0713 21.3813 18.0713 22 18.6667L24 20.6667M12 14C12 13.4696 12.2107 12.9609 12.5858 12.5858C12.9609 12.2107 13.4696 12 14 12H22C22.5304 12 23.0391 12.2107 23.4142 12.5858C23.7893 12.9609 24 13.4696 24 14V22C24 22.5304 23.7893 23.0391 23.4142 23.4142C23.0391 23.7893 22.5304 24 22 24H14C13.4696 24 12.9609 23.7893 12.5858 23.4142C12.2107 23.0391 12 22.5304 12 22V14Z\' stroke=\'%233B3C40\' stroke-linecap=\'round\' stroke-linejoin=\'round\'/%3E%3C/svg%3E';
await documentCloner.embed(opts.filterFontFace, imagePlaceholder);
const { width, height, left, top } = (0, node_parser_1.isBodyElement)(clonedElement) || (0, node_parser_1.isHTMLElement)(clonedElement)
? (0, bounds_1.parseDocumentSize)(clonedElement.ownerDocument)
: (0, bounds_1.parseBounds)(context, clonedElement);
const backgroundColor = parseBackgroundColor(context, clonedElement, opts.backgroundColor);
const renderOptions = {
canvas: opts.canvas,
backgroundColor,
scale: opts.scale ?? defaultView.devicePixelRatio ?? 1,
x: (opts.x ?? 0) + left,
y: (opts.y ?? 0) + top,
width: opts.width ?? Math.ceil(width),
height: opts.height ?? Math.ceil(height)
};
const renderer = new foreignobject_renderer_1.ForeignObjectRenderer(context, renderOptions);
const canvas = await renderer.render(clonedElement);
context.logger.debug(`Finished rendering`);
const toImage = (type, quality) => {
const _type = type ? imageMap[type] : undefined;
const _quality = quality && typeof quality === 'number' && quality > 0.9 ? 0.9 : quality;
if (_type)
return canvas.toDataURL(_type, _quality);
};
removeLoading();
return toImage(opts.type, opts.quality);
};
const parseBackgroundColor = (context, element, backgroundColorOverride) => {
const ownerDocument = element.ownerDocument;
// http://www.w3.org/TR/css3-background/#special-backgrounds
const documentBackgroundColor = ownerDocument.documentElement
? (0, color_1.parseColor)(context, getComputedStyle(ownerDocument.documentElement).backgroundColor)
: color_1.COLORS.TRANSPARENT;
const bodyBackgroundColor = ownerDocument.body
? (0, color_1.parseColor)(context, getComputedStyle(ownerDocument.body).backgroundColor)
: color_1.COLORS.TRANSPARENT;
const defaultBackgroundColor = typeof backgroundColorOverride === 'string'
? (0, color_1.parseColor)(context, backgroundColorOverride)
: backgroundColorOverride === null
? color_1.COLORS.TRANSPARENT
: 0xffffffff;
return element === ownerDocument.documentElement
? (0, color_1.isTransparent)(documentBackgroundColor)
? (0, color_1.isTransparent)(bodyBackgroundColor)
? defaultBackgroundColor
: bodyBackgroundColor
: documentBackgroundColor
: defaultBackgroundColor;
};
//# sourceMappingURL=index.js.map