← Усі статті

Стиснути й обрізати фото у вкладці, без відправки в хмару

HelpMyIMG стискає й обрізає фото у вкладці: близько 120 мс проти 4,2 с у хмарі, мінус 70–85% ваги, файл не їде на сервер.

Стиснути й обрізати фото у вкладці, без відправки в хмару
Зміст

Коротко

Нотатка ставить просте питання: навіщо відправляти родинне фото, скан паспорта чи файл клієнта на чужий сервер, щоб обрізати край, стиснути вагу або прибрати тло.

Сервіс HelpMyIMG лишає ці кроки в пам’яті вкладки. Пікселі рахує фоновий Web Worker, результат кодується у WebP.

У таблиці автора локальна обробка триває близько 120 мс проти 4,2 с у хмарного API, файл легший на 70–85%, ціна — $0 проти платної підписки.

Що сталося

Автор починає з побутової сцени. Родинні знімки, скани документів і матеріали клієнта «пливуть через океан», хоча задача — стерти білі пікселі по краю.

«Через океан» тут — назва самої відправки. Файл їде на чужий сервер, хоча правка могла лишитися на машині, де знімок уже відкритий.

Далі автор описує вітрину типового конвертера. Текст закликає вивантажити зображення в «рушій», смуга очікування триває близько 30 секунд, і екран повідомляє: безкоштовну спробу на місяць уже витрачено, висока чіткість коштує $19,99 на місяць.

HelpMyIMG зібраний як відповідь на цю вітрину. Обрізка на холсті, стиснення, кодування WebP і сегментація (нею зазвичай вирізають тло) відбуваються в пісочниці вкладки. Для самої операції мережа не потрібна.

Пікселі не рахує головний потік сторінки. Знімок передається в Web Worker, а малювання йде на OffscreenCanvas, тож вкладка не завмирає, поки збирається файл.

Уривок із нотатки має такий вигляд. Якість за замовчуванням — 0.82. У коментарі до коду автор пише про зменшення розміру на 70–85% приблизно за 40 мс і без мережевого обміну. Це оцінка кроку кодування, не цифра з порівняльної таблиці нижче.

export async function compressImageWorker(imageBitmap, quality = 0.82) {
  const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height);
  const ctx = canvas.getContext('2d', { willReadFrequently: true });
  ctx.drawImage(imageBitmap, 0, 0);
  const blob = await canvas.convertToBlob({ type: 'image/webp', quality });
  return blob;
}

Цей крок можна переказати без назв API. На вхід приходить готовий ImageBitmap. Далі створюється OffscreenCanvas того самого розміру, на нього лягає знімок, і холст віддає файл WebP із заданою якістю. Повертається сам файл, а не адреса на сервері.

Прапорець willReadFrequently стоїть у виклику контексту рівно так, як його написав автор. Нотатка не пояснює, навіщо він увімкнений, і не додає окремий замір «з прапорцем і без».

Окремо він стверджує, що базові дії — сегментація, обрізка, стиснення, кодування WebP — можуть іти в пам’яті браузера на сучасних WebAssembly і Canvas зі швидкістю 60 кадрів на секунду. До цієї фрази нотатка не додає окремий замір пристрою.

Порівняння, яке він публікує цілком:

Платний хмарний API зображень HelpMyIMG у браузері
Ліміт 50 спроб на місяць на безкоштовному рівні Без ліміту сервісу, межа — можливості комп’ютера
Мережа фото на 12 МБ їде в хмару 0 КБ, без відправки
Затримка обробки 4,2 с, повний цикл HTTP 120 мс, локальний WASM із SIMD
Ціна $19,90 на місяць $0, безкоштовно і відкрито

Ціна чужого сервісу в нотатці названа двічі, і безкоштовна межа теж двічі. Вітрина каже про одну спробу на місяць і $19,99. Таблиця — про 50 спроб на безкоштовному рівні і $19,90 на місяць. Це не два тести швидкості, а два формулювання тарифу. Власний рядок автор позначає як $0.

Живий приклад він ставить на сторінку сервісу.

Чому це важливо

Скан паспорта чи фото клієнта — не випадковий знімок з мережі. Щойно файл опиняється на чужому API, ця інфраструктура його вже бачила, навіть якщо просили лише зрізати біле поле.

Родина тримає альбом, людина з анкетою — документ, студія — теку замовника. Суперечка в нотатці одна: не віддавати оригінал за правку, яку вкладка здатна зробити на місці.

У таблиці це показано як корисне навантаження: 12 МБ проти 0 КБ. Нуль кілобайт означає, що знімок не покидає машину, а не що сервіс уміє ще щось, про що нотатка мовчить.

120 мс і 4,2 с — це робота на місці проти повного циклу запиту. До хмарної цифри додаються черга, ліміт спроб і підписка. Вітрина пише $19,99 на місяць, таблиця — $19,90. Обидва числа в автора стосуються чужого сервісу; за свій він ставить $0.

Фоновий потік потрібен не заради гарної назви API. Поки пікселі рахуються на OffscreenCanvas усередині Web Worker, головний потік сторінки лишається плавним. Людина гортає сторінку, а не дивиться на вдавану смугу в 30 секунд.

Обмеження чесне, і воно в тій самій таблиці: «без ліміту» впирається в комп’ютер. Слабкий ноутбук не стає хмарним кластером від того, що запит не пішов у мережу.

На практиці

Тут дві окремі рішення. Конфіденційний файл або файл клієнта не варто вивантажувати лише для обрізки й стиснення. Важкі пікселі не варто рахувати на головному потоці, якщо сторінка має й далі відповідати на дії.

Авторський начерк — не готовий продукт, а форма кроку. Її можна звірити зі своєю сторінкою.

  1. Для обрізки, стиснення, WebP і вирізання тла через сегментацію спершу перевірте, чи вистачає пам’яті вкладки, і лише потім думайте про відправку на сервер.
  2. Передайте ImageBitmap у Web Worker і малюйте на OffscreenCanvas, а не на холсті сторінки.
  3. Кодуйте через convertToBlob із типом image/webp. У прикладі якість за замовчуванням — 0.82; коментар обіцяє мінус 70–85% розміру приблизно за 40 мс без мережі.
  4. Звіряйте очікування з опублікованою таблицею: близько 120 мс локально проти 4,2 с повного циклу HTTP, 0 КБ проти 12 МБ, $0 проти підписки близько $19,90–$19,99 на місяць.
  5. Пам’ятайте про стелю комп’ютера: у таблиці немає безмежної хмари, є межа машини користувача.
  6. Не переносьте у свій продукт фразу про 60 кадрів на секунду як власний замір — у нотатці це заява про можливість, без окремої методики.

Підсумок

Біле поле на скані не варте квитка через океан. У цій нотатці обрізка, стиснення, WebP і сегментація лишаються в пам’яті вкладки: OffscreenCanvas у Web Worker, близько 120 мс проти 4,2 с, файл на 70–85% легший, ціна $0 проти платної хмари.

Поки знімок не їде, чужий сервер його не бачить. Далі межу ставить уже не тариф, а машина, на якій відкрита вкладка.

Коментарі

Завантаження коментарів…