Fix SVG images

This commit is contained in:
Yuri Papouski 2022-09-08 11:33:44 +00:00
parent 2d03b6e8a2
commit 357a9a029f
2 changed files with 58 additions and 38 deletions

View File

@ -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)) {
const [, inlinedSvg] = this.src.split(',');
const svgElement = deserializeSvg(inlinedSvg);
const { public setup(img: HTMLImageElement) {
width: {baseVal: widthBaseVal}, if (this.isSvg()) return;
height: {baseVal: heightBaseVal}
} = svgElement; if (this.isInlinedSvg()) {
const [, inlinedSvg] = this.src.split(',');
const svgElement = deserializeSvg(inlinedSvg);
const {
width: {baseVal: widthBaseVal},
height: {baseVal: heightBaseVal}
} = 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.intrinsicHeight = heightBaseVal.value;
return;
} }
this.intrinsicWidth = widthBaseVal.value;
this.intrinsicHeight = heightBaseVal.value;
return;
} }
this.intrinsicWidth = img.naturalWidth;
this.intrinsicHeight = img.naturalHeight;
} }
} }

View File

@ -270,24 +270,35 @@ 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 box = contentBox(container); const isContainerWSizes = container.intrinsicWidth > 0 && container.intrinsicHeight > 0;
const path = calculatePaddingBoxPath(curves); const isSVGContainer =
this.path(path); container instanceof SVGElementContainer ||
this.ctx.save(); (container instanceof ImageElementContainer && container.isSVG);
this.ctx.clip(); if (isContainerWSizes || isSVGContainer) {
this.ctx.drawImage( const box = contentBox(container);
image, const path = calculatePaddingBoxPath(curves);
0, this.path(path);
0, this.ctx.save();
container.intrinsicWidth, this.ctx.clip();
container.intrinsicHeight, if (isContainerWSizes) {
box.left, this.ctx.drawImage(
box.top, image,
box.width, 0,
box.height 0,
); container.intrinsicWidth,
this.ctx.restore(); container.intrinsicHeight,
box.left,
box.top,
box.width,
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();
}
} }
} }
@ -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}`);