У меня есть забавный маленький виджет, который предлагает пользователям выбирать из списка из 114 животных. Пользовательский интерфейс включает в себя маленькие эскизы каждого вида, все одинакового размера (100x70). Общая сумма миниатюр составляет 2,1 млн.
Я не собираюсь делать 114 запросов к серверу, поэтому я использовал ImageMagick, чтобы сделать одно ОЧЕНЬ длинное изображение (11400x70), которое уменьшается до 960K. Поэтому задача состоит в том, чтобы разделить это длинное изображение на 114 маленьких изображений на клиенте. (РЕДАКТИРОВАТЬ: мне нужно, чтобы каждое животное представляло собой свое собственное изображение, потому что пользовательский интерфейс фильтрует список, например, "показывать мне только травоядных").
Первоначально у меня был сложный подход, когда я рисовал это большое изображение на холсте после загрузки строки base64 объединенного изображения, вытягивал ImageData для каждого животного, рисовал ТО на второй холст, а затем вытягивал dataURL:
var combined_canvas = document.createElement('canvas');
var combined_ctx = combined_canvas.getContext('2d');
var indv_canvas = document.createElement('canvas');
var indv_ctx = indv_canvas.getContext('2d');
combined_canvas.width = 11400; combined_canvas.height = 70;
indv_canvas.width = 100; indv_canvas.height = 70;
var image = new Image();
image.onload = function() {
combined_ctx.drawImage(image, 0, 0); // paint combined image
// loop through the list of 114 animals
Object.keys(master_list).forEach((d, i) => {
// get the image data just for this animal in sequence
var imageData = combined_ctx.getImageData(i * 100, 0, 100, 70);
// paint that image data to the second canvas
indv_ctx.putImageData(imageData, 0, 0);
var img = document.createElement('img');
img.src = indv_canvas.toDataURL();
document.getElementById("animal_thumbnails").appendChild(img);
});
};
image.src = combined_images; // the base64 of the combined image
Естественно, было бы НАМНОГО проще сделать 114 CSS-спрайтов, что также предотвратило бы небольшую потерю качества из-за того, как Canvas рисует изображения. Но я не очень хорошо понимаю, как браузеры хранят одно и то же изображение, размещенное много раз с разными смещениями.
В случае, если клиент дублирует объединенное изображение в памяти, я просматриваю около 100 МБ для всех этих миниатюр. Я надеюсь, что даже самый худший браузер умнее этого, но это слишком далеко, чтобы я не знал.
Причина, по которой я загружаю изображение как base64, заключается в том, что у меня была еще одна идея - декодировать base64 с помощью atob()
и разрезать его с помощью jpg-js, в соответствии с qaru.site/questions/127771/.... Но jpg-js добавляет около 300 КБ при минимизации, и я не уверен, что он когда-либо действительно предназначался для клиента.
Что касается использования памяти, пожалуйста, смотрите этот пост и этот пост
Поэтому задача состоит в том, чтобы разделить это длинное изображение на 114 маленьких изображений на клиенте.
Для чего нужно нарезать длинное изображение. Я хотел бы сохранить его как одно изображение и использовать как спрайт CSS и показывать все изображения.
Если ваши изображения имеют фиксированное измерение, цикл JavaScript может отображать все изображения на странице. Или вы могли бы использовать инструмент, как это, чтобы получить положение животных и иметь его в файле CSS. Но я бы предпочел метод цикла JS.
Код будет что-то вроде этого
var imageItem = "";
var x = 0;
for (var i = 0; i < 144, i++) {
imageItem += "<li style='background-position: "+ x + " 0'></li>";
x = x + 100; // this is the width of the each image
}
someElement.innerHtml = "<ul class='img-container'>" + imageItem + "</ul>";
В CSS
.img-container li {
width: 100px;
height: 70px;
background-image : url('../your-long-image.jpg');
background-repeat: no-repeat;
}
Посмотрите этот пример, я использую только одно изображение, я изменяю положение смещения, чтобы показать разные места на одном и том же изображении.
var imageItem = "";
var x = 0;
for (var i = 0; i < 3; i++) {
imageItem += "<li style='background-position: "+ x + "px 0'>ss</li>";
x = x - 125; // this is the width of the each image
}
document.getElementById("container").innerHTML = "<ul class='img-container'>" + imageItem + "</ul>";
.img-container li {
width: 125px;
height: 200px;
border: 1px solid green;
background-image : url('https://images-wixmp-ed30a86b8c4ca887773594c2.wixmp.com/intermediary/f/c9702304-c06d-4500-90b7-b6b6168093f8/db9n9km-ee485eb1-1ecc-4cd8-b845-f16900bde9e0.png');
background-repeat: no-repeat;
float:left;
list-style: none;
}
<div id="container"></div>