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 {
src: string;
intrinsicWidth: number;
intrinsicHeight: number;
intrinsicWidth: number = 0;
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);
constructor(context: Context, img: HTMLImageElement) {
super(context, img);
this.src = img.currentSrc || img.src;
this.intrinsicWidth = img.naturalWidth;
this.intrinsicHeight = img.naturalHeight;
this.update();
this.isSVG = this.isSvg() || this.isInlinedSvg();
this.context.cache.addImage(this.src);
}
private update() {
if (!this.intrinsicWidth || !this.intrinsicHeight || ImageElementContainer.IS_FIRE_FOX) {
if (ImageElementContainer.INLINE_SVG.test(this.src)) {
const [, inlinedSvg] = this.src.split(',');
const svgElement = deserializeSvg(inlinedSvg);
private isInlinedSvg = () => ImageElementContainer.INLINED_SVG.test(this.src);
private isSvg = () => ImageElementContainer.SVG.test(this.src);
const {
width: {baseVal: widthBaseVal},
height: {baseVal: heightBaseVal}
} = svgElement;
public setup(img: HTMLImageElement) {
if (this.isSvg()) return;
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();
heightBaseVal.valueAsString = heightBaseVal.value.toString();
this.src = serializeSvg(svgElement, 'base64');
this.intrinsicWidth = widthBaseVal.value;
this.intrinsicHeight = heightBaseVal.value;
return;
img.src = serializeSvg(svgElement, 'base64');
}
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,
image: HTMLImageElement | HTMLCanvasElement
): void {
if (image && container.intrinsicWidth > 0 && container.intrinsicHeight > 0) {
const box = contentBox(container);
const path = calculatePaddingBoxPath(curves);
this.path(path);
this.ctx.save();
this.ctx.clip();
this.ctx.drawImage(
image,
0,
0,
container.intrinsicWidth,
container.intrinsicHeight,
box.left,
box.top,
box.width,
box.height
);
this.ctx.restore();
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 path = calculatePaddingBoxPath(curves);
this.path(path);
this.ctx.save();
this.ctx.clip();
if (isContainerWSizes) {
this.ctx.drawImage(
image,
0,
0,
container.intrinsicWidth,
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) {
try {
const image = await this.context.cache.match(container.src);
container.setup(image);
this.renderReplacedElement(container, curves, image);
} catch (e) {
this.context.logger.error(`Error loading image ${container.src}`);