mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Fixed handling of svg images with no width/height attributes
Such images were not appearing in resulting canvas when using firefox. The details of the problem are explained in https://bugzilla.mozilla.org/show_bug.cgi?id=700533 and https://webcompat.com/issues/64352 but a rough summary is that firefox won't render svg with no width/height attribute via drawImage. This fix thus recreates the missing attributes from the viewport one when they are missing
This commit is contained in:
parent
007a73293a
commit
9bc852f9f5
@ -265,29 +265,64 @@ export class CanvasRenderer extends Renderer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
renderReplacedElement(
|
async fixSVGImage(
|
||||||
|
container: ReplacedElementContainer,
|
||||||
|
image: HTMLImageElement | HTMLCanvasElement
|
||||||
|
): Promise<HTMLImageElement | HTMLCanvasElement> {
|
||||||
|
if (image instanceof HTMLImageElement && container.intrinsicWidth == 0 && container.intrinsicHeight == 0) {
|
||||||
|
// in such case we will to use the viewport attribute
|
||||||
|
// and we preprocess the svg image and add the width/height svg attributes to it so that drawImage works on firefox
|
||||||
|
// See https://bugzilla.mozilla.org/show_bug.cgi?id=700533 and https://webcompat.com/issues/64352
|
||||||
|
var img: HTMLImageElement = image;
|
||||||
|
var response = await fetch(img.src);
|
||||||
|
var str = await response.text();
|
||||||
|
var doc = new window.DOMParser().parseFromString(str, 'text/xml');
|
||||||
|
var svgElem = doc.documentElement;
|
||||||
|
if (svgElem) {
|
||||||
|
var viewBox = svgElem.getAttribute('viewBox');
|
||||||
|
var match = viewBox?.match(/\w+ \w+ (\w+) (\w+)/);
|
||||||
|
if (match) {
|
||||||
|
var viewBoxWidth = match[1];
|
||||||
|
var viewBoxHeight = match[2];
|
||||||
|
container.intrinsicWidth = +viewBoxWidth;
|
||||||
|
container.intrinsicHeight = +viewBoxHeight;
|
||||||
|
svgElem.setAttribute('width', viewBoxWidth);
|
||||||
|
svgElem.setAttribute('height', viewBoxHeight);
|
||||||
|
var svgData = new XMLSerializer().serializeToString(svgElem);
|
||||||
|
img.src = 'data:image/svg+xml;base64,' + btoa(svgData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
async renderReplacedElement(
|
||||||
container: ReplacedElementContainer,
|
container: ReplacedElementContainer,
|
||||||
curves: BoundCurves,
|
curves: BoundCurves,
|
||||||
image: HTMLImageElement | HTMLCanvasElement
|
image: HTMLImageElement | HTMLCanvasElement
|
||||||
): void {
|
) {
|
||||||
if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
|
if (image) {
|
||||||
const box = contentBox(container);
|
// Special fix for displaying svg images with no width/height attributes
|
||||||
const path = calculatePaddingBoxPath(curves);
|
var img = await this.fixSVGImage(container, image);
|
||||||
this.path(path);
|
if (container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
|
||||||
this.ctx.save();
|
const box = contentBox(container);
|
||||||
this.ctx.clip();
|
const path = calculatePaddingBoxPath(curves);
|
||||||
this.ctx.drawImage(
|
this.path(path);
|
||||||
image,
|
this.ctx.save();
|
||||||
0,
|
this.ctx.clip();
|
||||||
0,
|
this.ctx.drawImage(
|
||||||
container.intrinsicWidth,
|
img,
|
||||||
container.intrinsicHeight,
|
0,
|
||||||
box.left,
|
0,
|
||||||
box.top,
|
container.intrinsicWidth,
|
||||||
box.width,
|
container.intrinsicHeight,
|
||||||
box.height
|
box.left,
|
||||||
);
|
box.top,
|
||||||
this.ctx.restore();
|
box.width,
|
||||||
|
box.height
|
||||||
|
);
|
||||||
|
this.ctx.restore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,20 +338,20 @@ export class CanvasRenderer extends Renderer {
|
|||||||
if (container instanceof ImageElementContainer) {
|
if (container instanceof ImageElementContainer) {
|
||||||
try {
|
try {
|
||||||
const image = await this.context.cache.match(container.src);
|
const image = await this.context.cache.match(container.src);
|
||||||
this.renderReplacedElement(container, curves, image);
|
await this.renderReplacedElement(container, curves, image);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.error(`Error loading image ${container.src}`);
|
this.context.logger.error(`Error loading image ${container.src}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container instanceof CanvasElementContainer) {
|
if (container instanceof CanvasElementContainer) {
|
||||||
this.renderReplacedElement(container, curves, container.canvas);
|
await this.renderReplacedElement(container, curves, container.canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container instanceof SVGElementContainer) {
|
if (container instanceof SVGElementContainer) {
|
||||||
try {
|
try {
|
||||||
const image = await this.context.cache.match(container.svg);
|
const image = await this.context.cache.match(container.svg);
|
||||||
this.renderReplacedElement(container, curves, image);
|
await this.renderReplacedElement(container, curves, image);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.context.logger.error(`Error loading svg ${container.svg.substring(0, 255)}`);
|
this.context.logger.error(`Error loading svg ${container.svg.substring(0, 255)}`);
|
||||||
}
|
}
|
||||||
@ -903,7 +938,6 @@ export class CanvasRenderer extends Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stack = parseStackingContexts(element);
|
const stack = parseStackingContexts(element);
|
||||||
|
|
||||||
await this.renderStack(stack);
|
await this.renderStack(stack);
|
||||||
this.applyEffects([]);
|
this.applyEffects([]);
|
||||||
return this.canvas;
|
return this.canvas;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user