Я использую библиотеку html2canvas для захвата снимков экрана, передавая имя класса и сохраняя файл изображения в виде большого двоичного объекта. Однако при сохранении или загрузке изображения возникает проблема с элементами, имеющими background-image: url(data:image/svg+xml;base64,...)
(изображение SVG), но изображения PNG не затрагиваются. Я использую html2canvas версии 1.4.1.
function captureImg(className) {
const bannerElement = document.querySelector('.' + className);
return html2canvas(bannerElement, {
scale: 2,
backgroundColor: null,
}).then(canvas => {
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (blob) {
const file = new File([blob], 'banner-screenshot.png', {
type: 'image/png'
});
resolve(file);
} else {
reject(new Error('Failed to convert canvas to blob'));
}
}, 'image/png');
});
}).finally(() => {
}).catch(error => {
console.error('Error capturing the banner:', error);
});
}
function captureImgNow() {
captureImg('basic-box').then(file =\> {
const formData = new FormData();
formData.append('file_img', file);
formData.append('error_now', error_now);
formData.append('user_learn_id', user_learn_id);
formData.append('lesson_id', lesson_id);
formData.append('detail_id', detail_id);
formData.append('type', 'wrong');
formData.append('max_error', max_error);
$.ajax({
url: '/save-user-note-exam-failed',
method: 'POST',
contentType: 'application/json',
data: formData,
contentType: false,
processData: false,
cache: false,
success: function (response) {
console.info('captureImgNow');
},
error: function (xhr) {
}
});
})
}
Это изображение, которое я хочу
Это результат
Это этот CSS
Я попробовал dom-to-image, но скорость довольно медленная и не подходит для моего проекта.
<img width = "200px" height = "200px" style = "z-index: 1000; position: absolute; top: 50%; left: 50%;" src = "<%= item.image_background_gray == null ? item.image_background : item.image_background_gray%>" alt = "test">
Это тест изображения
Это результат теста
Вы можете попробовать написать этот код
async function convertSvgUrlToCanvas(url) {
const response = await fetch(url);
const svgText = await response.text();
const svgElement = new DOMParser().parseFromString(svgText, 'image/svg+xml').documentElement;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = new Image();
const svgData = `data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElement))}`;
img.src = svgData;
return new Promise((resolve) => {
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
resolve(canvas);
};
});
}
async function handleSvgBackgrounds(element) {
const elements = element.querySelectorAll('*');
for (const el of elements) {
const style = window.getComputedStyle(el);
const backgroundImage = style.getPropertyValue('background-image');
if (backgroundImage.startsWith('url("data:image/svg+xml')) {
const urlMatch = backgroundImage.match(/url\("(.+)"\)/);
if (urlMatch) {
const svgUrl = urlMatch[1];
const svgCanvas = await convertSvgUrlToCanvas(svgUrl);
// Replace the SVG background with the canvas image
el.style.backgroundImage = `url(${svgCanvas.toDataURL()})`;
}
}
}
}
async function captureImg(className) {
const bannerElement = document.querySelector('.' + className);
await handleSvgBackgrounds(bannerElement);
return html2canvas(bannerElement, {
scale: 2,
backgroundColor: null,
}).then(canvas => {
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (blob) {
const file = new File([blob], 'banner-screenshot.png', {
type: 'image/png'
});
resolve(file);
} else {
reject(new Error('Failed to convert canvas to blob'));
}
}, 'image/png');
});
}).catch(error => {
console.error('Error capturing the banner:', error);
});
}
function captureImgNow() {
captureImg('basic-box').then(file => {
const formData = new FormData();
formData.append('file_img', file);
formData.append('error_now', error_now);
formData.append('user_learn_id', user_learn_id);
formData.append('lesson_id', lesson_id);
formData.append('detail_id', detail_id);
formData.append('type', 'wrong');
formData.append('max_error', max_error);
$.ajax({
url: '/save-user-note-exam-failed',
method: 'POST',
data: formData,
contentType: false,
processData: false,
cache: false,
success: function (response) {
console.info('captureImgNow');
},
error: function (xhr) {
console.error('Error uploading the image:', xhr);
}
});
}).catch(error => {
console.error('Error in captureImgNow:', error);
});
}
Теперь вы можете попробовать!! я обновил
Замечательно, что я добавил encodeURIComponent
в код. Полный код const svgData = `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgElement))))}`;
Это сработало. Большое спасибо!
К сожалению, в этой части:
const svgElements = element.querySelectorAll('[style* = "background-image: url(data:image/svg+xml;base64,"]');
Мои URL-адреса не такие короткие. Они вызываются из переменной сервера, например:<div background-image: url('<%= examDt.image ? examDt.image%>>
На моей странице довольно много таких переменных, потому что это игра. Невозможно получить все элементы SVG таким способом.