var canvasPromise = html2canvas(document.body, {
allowTaint: true,
useCORS: true
});
canvasPromise.then(function(canvas) {
document.body.appendChild(canvas);
console.log(canvas);
canvas.toDataURL('image/png');
});
рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рдЖрдпрд╛ (рд╡рд╛рджреЗ рдореЗрдВ) DOMException: 'HTMLCanvasElement' рдкрд░ 'toDataURL' рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: рджрд╛рдЧреА рдХреИрдирд╡рд╛рд╕ рдирд┐рд░реНрдпрд╛рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдореЗрд░реЗ рдкрд╛рд╕ рднреА рд╡рд╣реА рдореБрджреНрджреЗ рд╣реИрдВред
рдХреНрдпрд╛ рдЖрдкрдХреЛ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдпрд╛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛?
рдореИрдВ рдлрд╝рд╛рдпрд░рдлрд╝реЙрдХреНрд╕ 61.0.2 рдореЗрдВ рд╡рд╣реА рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдФрд░ рдЕрдиреБрдорддрд┐ рджреЗрдиреЗ рдХреЗ рдмрд╛рд╡рдЬреВрдж рдореБрдЭреЗ рд╕реБрд░рдХреНрд╖рд╛ рддреНрд░реБрдЯрд┐ рдорд┐рд▓ рд░рд╣реА рд╣реИ
рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛтАЛтАЛрдореБрдЭреЗ рдкрддрд╛ рд╣реИ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдореЗрд░реЗ рдкрд╛рд╕ рд╡рд░реНрдХрдЕрд░рд╛рдЙрдВрдб рд╣реИ: рдкреНрд░рддреНрдпреЗрдХ рдЫрд╡рд┐ рдХреЛ рдмреЗрд╕ 64 рдореЗрдВ рдмрджрд▓реЗрдВред рдЗрд╕ рддрд░рд╣, рдЖрдк рдЗрд╕реЗ рдХреИрдирд╡рд╛рд╕ рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рднрд▓реЗ рд╣реА рдпрд╣ рдореВрд▓ рд░реВрдк рд╕реЗ рднрд┐рдиреНрди рдбреЛрдореЗрди рд╕реЗ рд╣реЛред
рдХреНрдпрд╛ рдЖрдкрдиреЗ рдЗрд╕реЗ рджреЗрдЦрд╛ рд╣реИ: CORS_enabled_image
рдпрджрд┐ рд╡рд┐рджреЗрд╢реА рд╕рд╛рдордЧреНрд░реА рдХрд╛ рд╕реНрд░реЛрдд HTML рд╣реИ рддрддреНрд╡, рдХреИрдирд╡рд╛рд╕ рдХреА рд╕рд╛рдордЧреНрд░реА рдХреЛ рдкреБрдирдГ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдирд╣реАрдВ рд╣реИред
рдЬреИрд╕реЗ рд╣реА рдЖрдк рдХрд┐рд╕реА рдХреИрдирд╡рд╛рд╕ рдореЗрдВ рдХреЛрдИ рдбреЗрдЯрд╛ рдЦреАрдВрдЪрддреЗ рд╣реИрдВ рдЬреЛ рдмрд┐рдирд╛ CORS рдЕрдиреБрдореЛрджрди рдХреЗ рдХрд┐рд╕реА рдЕрдиреНрдп рдореВрд▓ рд╕реЗ рд▓реЛрдб рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛, рдХреИрдирд╡рд╛рд╕ рджрд╛рдЧрджрд╛рд░ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред
рдореИрдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░реЗрд╢рди рд╡рд┐рдХрд▓реНрдкреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ:
html2canvas(document.body, {
allowTaint: true,
foreignObjectRendering: true
});
рдирдорд╕реНрддреЗ, рд╣рдореЗрдВ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ред рд╣рдордиреЗ @dorklord23 рд╕реБрдЭрд╛рд╡ рдХрд╛ рдкрд╛рд▓рди рдХрд┐рдпрд╛ рдХреНрдпреЛрдВрдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдПрдХ рдкреНрд░реЙрдХреНрд╕реА url рдерд╛ рдЬрд┐рд╕рдиреЗ рд░реВрдкрд╛рдВрддрд░рдг рдХрд┐рдпрд╛ рдерд╛ред
рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЛ рдпрд╣ рдорджрджрдЧрд╛рд░ рд▓рдЧрд╛ рддреЛ рд╕рдорд╛рдзрд╛рди рдерд╛:
html2canvas(document.body, {
proxy: this._proxyURL,
allowTaint: true,
onclone: (cloned) => convertAllImagesToBase64(this._proxyURL, cloned),
}).then((canvas) => {
this._postmessageChannel.send(`get.screenshot:${canvas.toDataURL('image/png')}`);
});
рдЬрд╣рд╛рдВ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдп ConvertAllImagesToBase64 рд╣реИ:
const convertAllImagesToBase64 = (proxyURL, cloned) => {
const pendingImagesPromises = [];
const pendingPromisesData = [];
const images = cloned.getElementsByTagName('img');
for (let i = 0; i < images.length; i += 1) {
// First we create an empty promise for each image
const promise = new Promise((resolve, reject) => {
pendingPromisesData.push({
index: i, resolve, reject,
});
});
// We save the promise for later resolve them
pendingImagesPromises.push(promise);
}
for (let i = 0; i < images.length; i += 1) {
// We fetch the current image
fetch(`${proxyURL}?url=${images[i].src}`)
.then((response) => response.json())
.then((data) => {
const pending = pendingPromisesData.find((p) => p.index === i);
images[i].src = data;
pending.resolve(data);
})
.catch((e) => {
const pending = pendingPromisesData.find((p) => p.index === i);
pending.reject(e);
});
}
// This will resolve only when all the promises resolve
return Promise.all(pendingImagesPromises);
};
export { convertAllImagesToBase64 };
рд╡реИрд╕реЗ рдпрд╣ рдЙрд╕ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд▓рд┐рдП рдкрд░реАрдХреНрд╖рдг рд╣реИрдВ (рд╣рдо рдкрд░реАрдХреНрд╖рдг рдФрд░ рдореЙрдХрдлрд╝реЗрдЪ рдкреИрдХреЗрдЬ рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рдЬреЗрд╕реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВ):
import { convertAllImagesToBase64 } from '../images';
fetch.resetMocks();
// Mock fetch to respond different for each image so we can assert that the image return the correct response
// Also make one of the response be delayed (2 seconds) to simulate the response is not in the same order we do the call (network latency, image size, etc)
fetch.mockImplementation((url) => {
if (url.includes('imagesrc1')) {
return Promise.resolve(new Response(JSON.stringify('data:image/png;base64,1')));
} else if (url.includes('imagesrc2')) {
return new Promise((resolve) => setTimeout(resolve(new Response(JSON.stringify('data:image/png;base64,2'))), 2000));
} else if (url.includes('imagesrc3')) {
return Promise.resolve(new Response(JSON.stringify('data:image/png;base64,3')));
}
return Promise.resolve(new Response(JSON.stringify('')));
});
const mocksImages = [
{ id: 1, src: 'imagesrc1' },
{ id: 2, src: 'imagesrc2' },
{ id: 3, src: 'imagesrc3' },
];
const mockClone = {
getElementsByTagName: jest.fn(() => mocksImages),
};
describe('utils/images', () => {
it('convertAllImagesToBase64. Expect to call 3 times to the correct enpoint using the image source', async () => {
const allPromises = convertAllImagesToBase64('http://localhost/fake_proxy', mockClone);
// Expect the clone elements gets all the image tags
expect(mockClone.getElementsByTagName).toBeCalledWith('img');
allPromises.then(() => {
// Expect to have done the 3 fetch calls and with the correct params
expect(fetch).toBeCalledTimes(3);
expect(fetch).toHaveBeenNthCalledWith(1, 'http://localhost/fake_proxy?url=imagesrc1');
expect(fetch).toHaveBeenNthCalledWith(2, 'http://localhost/fake_proxy?url=imagesrc2');
expect(fetch).toHaveBeenNthCalledWith(3, 'http://localhost/fake_proxy?url=imagesrc3');
// Expect that our images where updated properly
expect(mocksImages).toContainEqual({
id: 1, src: 'data:image/png;base64,1',
});
expect(mocksImages).toContainEqual({
id: 2, src: 'data:image/png;base64,2',
});
expect(mocksImages).toContainEqual({
id: 3, src: 'data:image/png;base64,3',
});
});
});
});
рд░реВрдмреА рдмреИрдХрдПрдВрдб рд╕рдорд╛рдкрди рдмрд┐рдВрджреБ:
require 'base64'
require 'net/http'
module Api
module V1
class ImageProxyController < ApiController
def index
url = URI.parse(params[:url])
image = Net::HTTP.get_response(url)
render json: data_url(image).to_json, callback: params[:callback]
end
private
def data_url(image)
"data:#{image.content_type};base64,#{Base64.encode64(image.body)}"
end
end
end
end
рдореБрдЭреЗ рдЖрд╢рд╛ рд╣реИ рдХрд┐ рдХрд┐рд╕реА рдХреЛ рдпрд╣ рдорджрджрдЧрд╛рд░ рд▓рдЧреЗрдЧрд╛ред рдореБрдЭреЗ рдЙрдореНрдореАрдж рд╣реИ рдХрд┐ рдпрд╣ рдХрд┐рд╕реА рдХреЛ рдЙрддрдирд╛ рд╕рдордп рдирд┐рд╡реЗрд╢ рдирд╣реАрдВ рдХрд░рдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИ рдЬрд┐рддрдирд╛ рд╣рдордиреЗ рдЗрд╕реЗ рдареАрдХ рд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдерд╛ред
рдпрджрд┐ рдЖрдк рдХреЛрдИ рд╕реБрдзрд╛рд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рддреЛ рдХреГрдкрдпрд╛ рд╕реБрдЭрд╛рд╡ рджреЗрдВред
рд╕рд╛рджрд░ред
рдпрджрд┐ рдЖрдк рдиреАрдЪреЗ рдХреА рддрд░рд╣ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдХреНрдпрд╛ рд╣реЛрдЧрд╛?
const TempImage = window.Image
const Image = function() {
const img = new TempImage()
img.crossOrigin = 'anonymous'
return img
}
рдПрдХ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛ рдФрд░ рдпрд╣ рдХрд╛рдо рдХрд░ рд░рд╣рд╛ рд╣реИ
html2canvas рдХреЛ рдХреЙрд▓ рдХрд░рддреЗ рд╕рдордп, CORS true рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
html2canvas(selectorElement, {useCORS:true} )
//рдХреБрдЫ рдХрд░реЛ
});
рд╕рд╣реА html2canvas.js рдлрд╝рд╛рдЗрд▓ред рдЯрд╛рдЗрдкреЛ рдХреА рдЧрд▓рддреА рд╣реИ
рдЗрд╕рдореЗрдВ "рдЕрдирд╛рдо" рдХреЛ "рдмреЗрдирд╛рдореА" рдореЗрдВ рдмрджрд▓реЗрдВ рдпрджрд┐ рдмреНрд▓реЙрдХ
рдЕрдЧрд░ (isInlineBase64Image(src) || тАЛтАЛuseCORS) {
img.crossOrigin = 'рдмреЗрдирд╛рдореА';
}
var canvasPromise = html2canvas(document.body, { allowTaint: true, useCORS: true }); canvasPromise.then(function(canvas) { document.body.appendChild(canvas); console.log(canvas); canvas.toDataURL('image/png'); });
рджреЛрд╖ рд░рд┐рдкреЛрд░реНрдЯ:
рдзреНрдпрд╛рди рдореЗрдВ рдирд╣реАрдВ рдЖрдпрд╛ (рд╡рд╛рджреЗ рдореЗрдВ) DOMException: 'HTMLCanvasElement' рдкрд░ 'toDataURL' рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдиреЗ рдореЗрдВ рд╡рд┐рдлрд▓: рджрд╛рдЧреА рдХреИрдирд╡рд╛рд╕ рдирд┐рд░реНрдпрд╛рдд рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
- html2canvas рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд╕рд╛рде рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛ рдЧрдпрд╛:
- рдХреНрд░реЛрдо ремрен.реж.реж.рейрейрепрем.репреп
- рд╡рд┐рдВрдбреЛрдЬ 10
рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рд╕рдВрдкрддреНрддрд┐ 'useCORS: true' рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдпрджрд┐ рдЖрдк 'allowTaint: true' рд╕рдВрдкрддреНрддрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдЖрдк рдЕрдкрдиреЗ рдХреИрдирд╡рд╛рд╕ рдХреЛ рджрд╛рдЧреА рдХреИрдирд╡рд╛рд╕ рдореЗрдВ рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддреЗ рд╣реИрдВ
рдЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ:
var canvasPromise = html2canvas(document.body, {
useCORS: true
});
canvasPromise.then(function(canvas) {
document.body.appendChild(canvas);
console.log(canvas);
canvas.toDataURL('image/png');
});
рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛:
var canvasPromise = html2canvas(document.body, {
allowTaint: true,
useCORS: true
});
canvasPromise.then(function(canvas) {
document.body.appendChild(canvas);
console.log(canvas);
canvas.toDataURL('image/png');
});
рд╣реИрд▓реЛ, html2canvas рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫрд╛ рдХрд╛рдоред
рджреБрдЦ рдХреА рдмрд╛рдд рд╣реИ рдХрд┐ рдореБрдЭреЗ рдПрдХ рд╣реА рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝ рд░рд╣рд╛ рд╣реИ, рдХреНрдпрд╛ рдХрд┐рд╕реА рдиреЗ рдЗрд╕реЗ рд╣рд▓ рдХрд┐рдпрд╛ рд╣реИ?
рдкрд╣рд▓реЗ рд╕реЗ рд╣реА @motarock рдФрд░
downloadQRCode = (fileName) => {
html2canvas(document.getElementById('generated-qr-code'), {
useCORS: true,
// allowTaint: false,
// logging: true,
}).then((canvas) => {
// document.body.appendChild(canvas); // checking
const data = canvas.toDataURL('image/jpeg');
const element = document.createElement('a');
element.setAttribute('href', data);
element.setAttribute('download', fileName + '.jpeg');
document.body.appendChild(element);
element.click();
// document.body.removeChild(element);
console.log("%c data", "font-size:2em;", data, fileName);
console.log("%c canvas", "font-size:2em;", canvas );
this.setState({
imageSrc: data // setting the src of a img tag to check the result. Nothing in it either..
})
});
рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдзрдиреНрдпрд╡рд╛рдж
рдореЗрд░реЗ рдкрд╛рд╕ рднреА рд╡рд╣реА рдореБрджреНрджреЗ рд╣реИрдВред
рдХреЛрдИ рдЗрд╕ рдореБрджреНрджреЗ рдХреЛ рдареАрдХ рдХрд░ рд╕рдХрддрд╛ рд╣реИ?
:( рдПрдХ рд╣реА рдореБрджреНрджрд╛ред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдиреЗрд╕реНрдЯреЗрдб рдПрд╕рд╡реАрдЬреА рдХреЗ рд╕рд╛рде рдПрдЪрдЯреАрдПрдордПрд▓ рд╣реИ рдФрд░ рдпрд╣ рдкреНрд░рд╕реНрддреБрдд рдирд╣реАрдВ рдХрд░реЗрдЧрд╛
рдкрд╣рд▓реЗ рд╕реЗ рд╣реА @motarock рдФрд░
рдореЗрд░реЗ рдкрд╛рд╕ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рд╣реИ рдЬрдм рдореИрдВ рдПрд╕рдПрд╕рдПрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛, рдПрд╕рдПрд╕рдПрд▓ рдХреЗ рд╕рд╛рде рд╕рд╣реА рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ
рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА
рдореЗрд░реЗ рдкрд╛рд╕ рднреА рд╡рд╣реА рдореБрджреНрджреЗ рд╣реИрдВред
рдХреНрдпрд╛ рдЖрдкрдХреЛ рдХреЛрдИ рд╕рдорд╛рдзрд╛рди рдпрд╛ рд╕рдорд╛рдзрд╛рди рдорд┐рд▓рд╛?