Как конвертировать несколько изображений в base64 с помощью canvas
Я храню изображения в кодировке base64, и на данный момент я могу создать только один код (я пытаюсь создать два, но, похоже, второй перезаписывается). Я не понимаю общую концепцию рисования на холсте, поэтому я считаю, что это корень моей проблемы при попытке решить эту проблему.
текущее поведение: он хранит один и тот же DataUrl в локальном хранилище дважды. Это действительно регистрирует правильную информацию. зеленый значок хранится, но не красный
Как мне закодировать несколько изображений base64 с помощью canvas?
HTML:
<head>
...
<link id="favicon" rel="icon" src="/assets/favicon-red-16x16.ico.png">
</head>
<body>
...
<!-- hidden images to store -->
<img id="favicon-green" rel="icon" src="/assets/favicon-green-16x16.ico.png" width="16" height="16" />
<img id="favicon-red" rel="icon" src="/assets/favicon-red-16x16.ico.png" width="16" height="16" />
...
</body>
ЯШ:
// cache images
function storeImages() {
// my sorry attempt to create two canvas elements for two image encodings
var canvasGreen = document.createElement('canvas');
var canvasRed = document.createElement('canvas');
// painting both images
var ctxGreen = canvasGreen.getContext('2d');
var ctxRed = canvasRed.getContext('2d');
// getting both images from DOM
var favGreen = document.getElementById('favicon-green');
var favRed = document.getElementById('favicon-red');
// checking if images are already stored
var base64Green = localStorage.getItem('greenFavicon');
var base64Red = localStorage.getItem('redFavicon');
console.log('storing...')
if (base64Green == null && window.navigator.onLine || base64Red == null && window.navigator.onLine) {
ctxGreen.drawImage(favGreen, 0, 0);
ctxRed.drawImage(favRed, 0, 0);
// getting images (the DataUrl is currently the same for both)
base64Green = canvasGreen.toDataURL();
base64Red = canvasRed.toDataURL();
localStorage.setItem('greenFavicon', base64Green);
localStorage.setItem('redFavicon', base64Red);
console.log("are they equal : ", base64Green == base64Red); // returns true
}
}
storeImages();
1 ответ
Я не вижу ничего особенно плохого в вашем коде. Если код не является прямым копированием и вставкой, я бы внимательно посмотрел его, чтобы убедиться, что вы не переключаете красный и зеленый.
Там не должно быть никаких удивительных механизмов, когда дело доходит до преобразования холстов в URL-адреса данных.
Вот быстрый пример двух:
const a = document.createElement('canvas');
const b = document.createElement('canvas');
const aCtx = a.getContext('2d');
const bCtx = b.getContext('2d');
aCtx.fillStyle = '#000';
aCtx.fillRect(0, 0, a.width, a.height);
const aUrl = a.toDataURL();
const bUrl = b.toDataURL();
console.log(aUrl == bUrl, aUrl, bUrl);
console.log('First difference index:', Array.prototype.findIndex.call(aUrl, (aChar, index) => aChar !== bUrl[index]));
Обратите внимание, что они разные. Тем не менее, обратите внимание, что они также очень похожи, и вам придется пройти довольно далеко, чтобы начать видеть различия (в моем примере, персонаж 70). Я бы дважды проверил, что они на самом деле одинаковы (сравнивая их, как я). Может быть, это выглядит так же.
Еще одна вещь, которую вы можете сделать, которая больше относится к стилю кода, но также может помочь со случайными зелеными и красными смешиваниями, - это создать функцию для сохранения только одного, а затем вызвать его дважды.
const saveImage = (imageId, key) => {
if (localStorage.getItem(key)) {
return; // already saved
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const image = document.getElementById(imageId);
ctx.drawImage(image, 0, 0);
if (window.navigator.onLine) {
localStorage.setItem(key, canvas.toDataURL());
}
}
saveImage('favicon-green', 'greenFavicon');
saveImage('favicon-red', 'redFavicon');
Это не только очищает ваш код и делает его СУХИМЫМ, но и помогает избежать случайного смешения красного и зеленого в вашей функции.
После некоторых комментариев я понял, что вы пытаетесь нарисовать изображения на холсте до их загрузки. Это заставит его рисовать пустые изображения, но в остальном ведет себя так, как будто работает нормально.
Вы можете быстро проверить это, запустив консоль:
console.log(image.width === 0);
после установки переменной изображения. Если значение равно true, то изображение еще не загружено (перед загрузкой изображения будут иметь ширину и высоту 0). Вы должны обязательно дождаться загрузки изображения, прежде чем пытаться его сохранить.
Лучший способ сделать это с addEventListener()
:
document.getElementById('favicon-green').addEventListener('load', () => {
saveImage('favicon-green', 'greenFavicon');
});
Есть еще одна загвоздка в том, что если изображение каким-то образом уже загружено к моменту запуска кода, оно никогда не сработает. Вам также нужно посмотреть на ширину изображения. Вот функция, которая делает все это для вас, и возвращает Promise
так что вы знаете, что это сделано:
const saveImage = (imageId, key) => new Promise(resolve => {
if (localStorage.getItem(key)) {
return resolve(); // already saved
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const image = document.getElementById(imageId);
const onImageLoaded = () => {
ctx.drawImage(image, 0, 0);
if (window.navigator.onLine) {
localStorage.setItem(key, canvas.toDataURL());
}
resolve();
}
if (image.width > 0) {
onImageLoaded();
} else {
image.addEventListener('load', onImageLoaded);
}
});
saveImage('favicon-green', 'greenFavicon').then(() => console.log('saved'));