mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Only use foreignObject rendering if browser is capable of rendering images
This commit is contained in:
parent
c28263ddc2
commit
c013e49192
@ -1,6 +1,8 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
import {createForeignObjectSVG, loadSerializedSVG} from './renderer/ForeignObjectRenderer';
|
||||||
|
|
||||||
const testRangeBounds = document => {
|
const testRangeBounds = document => {
|
||||||
const TEST_HEIGHT = 123;
|
const TEST_HEIGHT = 123;
|
||||||
|
|
||||||
@ -72,40 +74,45 @@ const testSVG = document => {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isGreenPixel = data => data[0] === 0 && data[1] === 255 && data[2] === 0 && data[3] === 255;
|
||||||
|
|
||||||
const testForeignObject = document => {
|
const testForeignObject = document => {
|
||||||
const img = new Image();
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = 1;
|
const size = 100;
|
||||||
canvas.height = 1;
|
canvas.width = size;
|
||||||
|
canvas.height = size;
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.fillStyle = 'rgb(0, 255, 0)';
|
||||||
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
const greenImageSrc = canvas.toDataURL();
|
||||||
|
img.src = greenImageSrc;
|
||||||
|
const svg = createForeignObjectSVG(size, size, img);
|
||||||
ctx.fillStyle = 'red';
|
ctx.fillStyle = 'red';
|
||||||
ctx.fillRect(0, 0, 1, 1);
|
ctx.fillRect(0, 0, size, size);
|
||||||
|
|
||||||
img.src = `data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><foreignObject><img src="${encodeURIComponent(
|
return loadSerializedSVG(svg)
|
||||||
canvas.toDataURL()
|
.then(img => {
|
||||||
)}" /></foreignObject></svg>`;
|
|
||||||
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const onload = () => {
|
|
||||||
try {
|
|
||||||
ctx.drawImage(img, 0, 0);
|
ctx.drawImage(img, 0, 0);
|
||||||
canvas.toDataURL();
|
const data = ctx.getImageData(0, 0, size, size).data;
|
||||||
} catch (e) {
|
ctx.fillStyle = 'red';
|
||||||
return resolve(false);
|
ctx.fillRect(0, 0, size, size);
|
||||||
}
|
|
||||||
|
|
||||||
return resolve(true);
|
const node = document.createElement('div');
|
||||||
};
|
node.style.backgroundImage = `url(${greenImageSrc})`;
|
||||||
|
node.style.height = `${size}px`;
|
||||||
img.onload = onload;
|
// Firefox 55 does not render inline <img /> tags
|
||||||
img.onerror = () => resolve(false);
|
return isGreenPixel(data)
|
||||||
|
? loadSerializedSVG(createForeignObjectSVG(size, size, node))
|
||||||
if (img.complete === true) {
|
: Promise.reject(false);
|
||||||
setTimeout(() => {
|
})
|
||||||
onload();
|
.then(img => {
|
||||||
}, 50);
|
ctx.drawImage(img, 0, 0);
|
||||||
}
|
// Edge does not render background-images
|
||||||
});
|
return isGreenPixel(ctx.getImageData(0, 0, size, size).data);
|
||||||
|
})
|
||||||
|
.catch(e => false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FEATURES = {
|
const FEATURES = {
|
||||||
|
@ -19,36 +19,48 @@ export default class ForeignObjectRenderer {
|
|||||||
this.ctx.scale(this.options.scale, this.options.scale);
|
this.ctx.scale(this.options.scale, this.options.scale);
|
||||||
|
|
||||||
options.logger.log(`ForeignObject renderer initialized with scale ${this.options.scale}`);
|
options.logger.log(`ForeignObject renderer initialized with scale ${this.options.scale}`);
|
||||||
|
const svg = createForeignObjectSVG(
|
||||||
|
options.bounds.width,
|
||||||
|
options.bounds.height,
|
||||||
|
this.element
|
||||||
|
);
|
||||||
|
|
||||||
|
return loadSerializedSVG(svg).then(img => {
|
||||||
|
if (options.backgroundColor) {
|
||||||
|
this.ctx.fillStyle = options.backgroundColor.toString();
|
||||||
|
this.ctx.fillRect(0, 0, options.bounds.width, options.bounds.height);
|
||||||
|
}
|
||||||
|
this.ctx.drawImage(img, 0, 0);
|
||||||
|
return this.canvas;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createForeignObjectSVG = (width: number, height: number, node: Node) => {
|
||||||
const xmlns = 'http://www.w3.org/2000/svg';
|
const xmlns = 'http://www.w3.org/2000/svg';
|
||||||
const svg = document.createElementNS(xmlns, 'svg');
|
const svg = document.createElementNS(xmlns, 'svg');
|
||||||
const foreignObject = document.createElementNS(xmlns, 'foreignObject');
|
const foreignObject = document.createElementNS(xmlns, 'foreignObject');
|
||||||
svg.setAttributeNS(null, 'width', options.bounds.width);
|
svg.setAttributeNS(null, 'width', width);
|
||||||
svg.setAttributeNS(null, 'height', options.bounds.height);
|
svg.setAttributeNS(null, 'height', height);
|
||||||
|
|
||||||
foreignObject.setAttributeNS(null, 'width', '100%');
|
foreignObject.setAttributeNS(null, 'width', '100%');
|
||||||
foreignObject.setAttributeNS(null, 'height', '100%');
|
foreignObject.setAttributeNS(null, 'height', '100%');
|
||||||
foreignObject.setAttributeNS(null, 'externalResourcesRequired', 'true');
|
foreignObject.setAttributeNS(null, 'externalResourcesRequired', 'true');
|
||||||
svg.appendChild(foreignObject);
|
svg.appendChild(foreignObject);
|
||||||
|
|
||||||
foreignObject.appendChild(this.element);
|
foreignObject.appendChild(node);
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadSerializedSVG = (svg: Node) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => {
|
img.onload = () => resolve(img);
|
||||||
if (options.backgroundColor) {
|
|
||||||
this.ctx.fillStyle = options.backgroundColor.toString();
|
|
||||||
this.ctx.fillRect(0, 0, options.bounds.width, options.bounds.height);
|
|
||||||
}
|
|
||||||
this.ctx.drawImage(img, 0, 0);
|
|
||||||
resolve(this.canvas);
|
|
||||||
};
|
|
||||||
|
|
||||||
img.onerror = reject;
|
img.onerror = reject;
|
||||||
|
|
||||||
img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
|
img.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(
|
||||||
new XMLSerializer().serializeToString(svg)
|
new XMLSerializer().serializeToString(svg)
|
||||||
)}`;
|
)}`;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user