mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Fix SVG images
This commit is contained in:
parent
2d03b6e8a2
commit
357a9a029f
@ -4,39 +4,47 @@ import {serializeSvg, deserializeSvg} from '../../core/features';
|
|||||||
|
|
||||||
export class ImageElementContainer extends ElementContainer {
|
export class ImageElementContainer extends ElementContainer {
|
||||||
src: string;
|
src: string;
|
||||||
intrinsicWidth: number;
|
intrinsicWidth: number = 0;
|
||||||
intrinsicHeight: number;
|
intrinsicHeight: number = 0;
|
||||||
|
isSVG: boolean;
|
||||||
|
|
||||||
private static INLINE_SVG = /^data:image\/svg\+xml/i;
|
private static SVG = /\.svg$/i;
|
||||||
|
private static INLINED_SVG = /^data:image\/svg\+xml/i;
|
||||||
private static IS_FIRE_FOX = /firefox/i.test(navigator?.userAgent);
|
private static IS_FIRE_FOX = /firefox/i.test(navigator?.userAgent);
|
||||||
|
|
||||||
constructor(context: Context, img: HTMLImageElement) {
|
constructor(context: Context, img: HTMLImageElement) {
|
||||||
super(context, img);
|
super(context, img);
|
||||||
this.src = img.currentSrc || img.src;
|
this.src = img.currentSrc || img.src;
|
||||||
this.intrinsicWidth = img.naturalWidth;
|
this.isSVG = this.isSvg() || this.isInlinedSvg();
|
||||||
this.intrinsicHeight = img.naturalHeight;
|
|
||||||
this.update();
|
|
||||||
this.context.cache.addImage(this.src);
|
this.context.cache.addImage(this.src);
|
||||||
}
|
}
|
||||||
|
|
||||||
private update() {
|
private isInlinedSvg = () => ImageElementContainer.INLINED_SVG.test(this.src);
|
||||||
if (!this.intrinsicWidth || !this.intrinsicHeight || ImageElementContainer.IS_FIRE_FOX) {
|
private isSvg = () => ImageElementContainer.SVG.test(this.src);
|
||||||
if (ImageElementContainer.INLINE_SVG.test(this.src)) {
|
|
||||||
|
public setup(img: HTMLImageElement) {
|
||||||
|
if (this.isSvg()) return;
|
||||||
|
|
||||||
|
if (this.isInlinedSvg()) {
|
||||||
const [, inlinedSvg] = this.src.split(',');
|
const [, inlinedSvg] = this.src.split(',');
|
||||||
const svgElement = deserializeSvg(inlinedSvg);
|
const svgElement = deserializeSvg(inlinedSvg);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
width: {baseVal: widthBaseVal},
|
width: {baseVal: widthBaseVal},
|
||||||
height: {baseVal: heightBaseVal}
|
height: {baseVal: heightBaseVal}
|
||||||
} = svgElement;
|
} = svgElement;
|
||||||
|
|
||||||
|
if (ImageElementContainer.IS_FIRE_FOX) {
|
||||||
widthBaseVal.valueAsString = widthBaseVal.value.toString();
|
widthBaseVal.valueAsString = widthBaseVal.value.toString();
|
||||||
heightBaseVal.valueAsString = heightBaseVal.value.toString();
|
heightBaseVal.valueAsString = heightBaseVal.value.toString();
|
||||||
this.src = serializeSvg(svgElement, 'base64');
|
img.src = serializeSvg(svgElement, 'base64');
|
||||||
|
}
|
||||||
|
|
||||||
this.intrinsicWidth = widthBaseVal.value;
|
this.intrinsicWidth = widthBaseVal.value;
|
||||||
this.intrinsicHeight = heightBaseVal.value;
|
this.intrinsicHeight = heightBaseVal.value;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
this.intrinsicWidth = img.naturalWidth;
|
||||||
|
this.intrinsicHeight = img.naturalHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,12 +270,18 @@ export class CanvasRenderer extends Renderer {
|
|||||||
curves: BoundCurves,
|
curves: BoundCurves,
|
||||||
image: HTMLImageElement | HTMLCanvasElement
|
image: HTMLImageElement | HTMLCanvasElement
|
||||||
): void {
|
): void {
|
||||||
if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
|
if (image) {
|
||||||
|
const isContainerWSizes = container.intrinsicWidth > 0 && container.intrinsicHeight > 0;
|
||||||
|
const isSVGContainer =
|
||||||
|
container instanceof SVGElementContainer ||
|
||||||
|
(container instanceof ImageElementContainer && container.isSVG);
|
||||||
|
if (isContainerWSizes || isSVGContainer) {
|
||||||
const box = contentBox(container);
|
const box = contentBox(container);
|
||||||
const path = calculatePaddingBoxPath(curves);
|
const path = calculatePaddingBoxPath(curves);
|
||||||
this.path(path);
|
this.path(path);
|
||||||
this.ctx.save();
|
this.ctx.save();
|
||||||
this.ctx.clip();
|
this.ctx.clip();
|
||||||
|
if (isContainerWSizes) {
|
||||||
this.ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
image,
|
image,
|
||||||
0,
|
0,
|
||||||
@ -287,9 +293,14 @@ export class CanvasRenderer extends Renderer {
|
|||||||
box.width,
|
box.width,
|
||||||
box.height
|
box.height
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
// As usual it won't work in FF. https://bugzilla.mozilla.org/show_bug.cgi?id=700533
|
||||||
|
this.ctx.drawImage(image, box.left, box.top, box.width, box.height);
|
||||||
|
}
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async renderNodeContent(paint: ElementPaint): Promise<void> {
|
async renderNodeContent(paint: ElementPaint): Promise<void> {
|
||||||
this.applyEffects(paint.getEffects(EffectTarget.CONTENT));
|
this.applyEffects(paint.getEffects(EffectTarget.CONTENT));
|
||||||
@ -303,6 +314,7 @@ 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);
|
||||||
|
container.setup(image);
|
||||||
this.renderReplacedElement(container, curves, image);
|
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}`);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user