Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
(не)идеальные картинки и другая пиксельная маги...
Search
Polina Gurtovaya
November 30, 2019
Programming
0
170
(не)идеальные картинки и другая пиксельная магия (ufadevconf))
Оптимизация web-изображений, котики и wasm
Polina Gurtovaya
November 30, 2019
Tweet
Share
More Decks by Polina Gurtovaya
See All by Polina Gurtovaya
Не учите алгоритмы
hellsquirrel
1
950
Давайте все заблокируем
hellsquirrel
0
300
Wasmысле?
hellsquirrel
0
220
Магия декларативныx схем.
hellsquirrel
0
340
ML for HolyJS
hellsquirrel
0
140
Идеальный способ заблюрить белочку
hellsquirrel
0
150
ML/DL на фронте
hellsquirrel
0
190
InsertableStreams
hellsquirrel
0
85
WebRTC-404
hellsquirrel
0
510
Other Decks in Programming
See All in Programming
新メンバーも今日から大活躍!SREが支えるスケールし続ける組織のオンボーディング
honmarkhunt
1
330
Node-RED を(HTTP で)つなげる MCP サーバーを作ってみた
highu
0
120
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
420
すべてのコンテキストを、 ユーザー価値に変える
applism118
2
1.1k
技術同人誌をMCP Serverにしてみた
74th
1
510
Hypervel - A Coroutine Framework for Laravel Artisans
albertcht
1
110
Deep Dive into ~/.claude/projects
hiragram
10
2.2k
なんとなくわかった気になるブロックテーマ入門/contents.nagoya 2025 6.28
chiilog
1
250
AIコーディング道場勉強会#2 君(エンジニア)たちはどう生きるか
misakiotb
1
270
Goで作る、開発・CI環境
sin392
0
190
Modern Angular with Signals and Signal Store:New Rules for Your Architecture @enterJS Advanced Angular Day 2025
manfredsteyer
PRO
0
170
「Cursor/Devin全社導入の理想と現実」のその後
saitoryc
0
680
Featured
See All Featured
The World Runs on Bad Software
bkeepers
PRO
69
11k
Embracing the Ebb and Flow
colly
86
4.7k
Writing Fast Ruby
sferik
628
62k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.8k
Making Projects Easy
brettharned
116
6.3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
940
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Mobile First: as difficult as doing things right
swwweet
223
9.7k
Measuring & Analyzing Core Web Vitals
bluesmoon
7
500
Scaling GitHub
holman
459
140k
Transcript
(не)идеальные картинки и другая пиксельная магия
2
3
4
Готовить графический контент нелегко
Показать пользователю картинку нужного качества как можно быстрее 6
Шаг 1: Транспорт
Вы используете HTTP/2 Вы используете CDN (например, cloudflare) Все ок
со сжатием (gzip / brotli) Все ок с кешированием 8 Убедитесь, что:
9 Шаг 2: Понимание
10 Картинка выражает какую-то идею, воспринимается в контексте и подразумевает
некую реакцию пользователя
Качество зависит от контекста Картинка это основной контент — качество
повыше Картинка это вспомогательный контент — качество пониже Иногда картинку нужно заменить интерактивным элементом 11
12 Шаг 3: Выбираем правильный формат
13 Когда SVG заходят хорошо Часть изображения можно представить как
набор геометрических примитивов Есть интерактивность Нужно цеплять маркеры к фону Нужно много размеров 13
В остальных случаях пробуйте все подходящие форматы и выбирайте лучший
14
svgo/svgr/svgomg 15 Оптимизируйте SVG
Время растровой графики 16
Что такое пиксель ? 17 abstract pixel hardware pixel CSS
pixel
18 Несколько чисел, хранящие информацию о цвете и прозрачности. color
model — то как хранится цвет Abstract pixel R G B Y Cb Cr — luma (Y) + chroma(Cb Cr).
Y Cb Cr 19
CSS pixel Абсолютная единица измерения Сколько-то миллиметров Сколько именно миллиметров
зависит от устройства 20
Device pixel ratio СSS pixel height / hardware pixel height
21
original image: 400 x 400 22 <img src="cupcake.jpg" style="width:200px" >
devicePixelRatio: 2
original image: 400 x 400 23 <img src="cupcake.jpg" style="width:400px" >
devicePixelRatio: 2
Upscaling 24
Подбирайте картинку под контейнер Размер картинки = размер контейнера dpr
25
Зачем cжимать картинки? Картинка 400 x 400 3 канала, 1
byte на канал 3 400 400 1 byte = 480Kb 26
Два способа сжатия Losseless (GIF, PNG, WEBP) Lossy (JPG, WEBP,
…) 27
28 Encoder
GIF Intraframe — есть Interframe— нет Алгоритм сжатия не очень
крутой (LZW) Losseless 256 цветов (любых) 29
РNG 30 black-rect-sketch.png 506 Байт black-rect-opti.png 91 Байт
31 Чтобы разобраться в чём дело, давайте напишем свой PNG-декодер
Анатомия PNG контейнера 32 splitToChunks(bytesFromFile)
33 const reader = new FileReader(); reader.onload = event =>
console.log(splitToChunks(event.target.result)) <input type="file" ref={input} onChange={() => { const file = input.current.files[0]; reader.current.readAsArrayBuffer(file); }} />
34
IHDR chunk width height bitDepth colorType 35
Сравниваем 2 черных квадрата 36
Допиливаем декодер 37 #include "emscripten.h" #include "zlib.h" EMSCRIPTEN_KEEPALIVE int decompress(/*
... */) { //... inflate(/* ... */); //... return pointer } emcc -O3 -s WASM=1 … decompressor.wasm
38 import decompressJS from './wasm/decompress'; import decompressModule from './wasm/decompress.wasm'; mod.destroyAll(inputPointer,
resultPointer); // ... somehow run wasm and create 'mod' object const inputPointer = mod.createBuffer(); mod.HEAP8.set(getIDAT(chunkData), inputPointer); const resultPointer = mod.decompress(/* ...*/); const decompressedData = new Uint8Array( mod.HEAP8.buffer, resultPointer, size ); const imgData = processDecopressedData(decompressedData); canvas.current.getContext('2d').putImageData(imgData); // ...
39
40 Еще немножко трюков 40 Подключаем OpenCV Натравливаем OpenCV на
наши байтики faceCascade.detectMultiScale(src, dst, 1.3, 3, 0);
41
PNG многое умеет Режим GrayScale Может грузиться постепенно 42
JPEG Сжатие с потерями… 43
Разбиваем изображение на блоки 8 x 8 44
Y Cb Cr. Каждый канал отдельно 45
Применяем магическое преобразование 46 [[169 171 174 177 179 179
177 177] [171 173 176 179 180 180 178 177] [174 176 179 181 182 182 180 179] [176 178 180 183 184 183 181 180] [174 180 186 189 186 180 176 173] [182 185 187 188 186 182 178 176] [188 187 186 187 187 184 180 176] [185 185 186 189 190 188 181 175]] [[420.6 1.2 -21.9 1.5 0.1 -0.4 -0.3 -0.6] [-25.2 -17.6 3.7 -2.9 0.1 -0.4 0.7 -0. ] [ -1.7 -0.8 2.8 4.9 -0. 0. 0.6 -0.2] [ -3.8 4.1 -1.9 -3.4 0.4 -0.3 -0.4 0.2] [ -1.9 -2.7 -4. -0.2 0.1 -0. -0.1 -0.1] [ 2.2 -0.9 5.8 2. 0.5 -0.3 0. 0.2] [ 0.8 -0.7 -0.4 -0.5 -0.4 -0.3 0.5 -0.1] [ -1.4 1.8 -2.5 -1.1 -0.2 0.3 -0.1 0.4]]
Применяем магическое преобразование 47 [[420.6 1.2 -21.9 1.5 0.1 -0.4
-0.3 -0.6] [-25.2 -17.6 3.7 -2.9 0.1 -0.4 0.7 -0. ] [ -1.7 -0.8 2.8 4.9 -0. 0. 0.6 -0.2] [ -3.8 4.1 -1.9 -3.4 0.4 -0.3 -0.4 0.2] [ -1.9 -2.7 -4. -0.2 0.1 -0. -0.1 -0.1] [ 2.2 -0.9 5.8 2. 0.5 -0.3 0. 0.2] [ 0.8 -0.7 -0.4 -0.5 -0.4 -0.3 0.5 -0.1] [ -1.4 1.8 -2.5 -1.1 -0.2 0.3 -0.1 0.4]]
Quantization 48 [[420.6 1.2 -21.9 1.5 0.1 -0.4 -0.3 -0.6]
[-25.2 -17.6 3.7 -2.9 0.1 -0.4 0.7 -0. ] [ -1.7 -0.8 2.8 4.9 -0. 0. 0.6 -0.2] [ -3.8 4.1 -1.9 -3.4 0.4 -0.3 -0.4 0.2] [ -1.9 -2.7 -4. -0.2 0.1 -0. -0.1 -0.1] [ 2.2 -0.9 5.8 2. 0.5 -0.3 0. 0.2] [ 0.8 -0.7 -0.4 -0.5 -0.4 -0.3 0.5 -0.1] [ -1.4 1.8 -2.5 -1.1 -0.2 0.3 -0.1 0.4]] [[53 0 -2 0 0 0 0 0] [-2 -1 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]] [[ 8 8 8 9 13 19 28 43] [ 8 9 10 14 17 20 27 38] [ 8 10 12 16 22 31 46 68] [ 9 14 16 20 27 37 53 78] [ 13 17 22 27 35 47 66 95] [ 19 20 31 37 47 62 85 119] [ 28 27 46 53 66 85 113 156] [ 43 38 68 78 95 119 156 209]]
Progressive JPEG Мы просто присылаем часть табличек для всех блоков
49
WebP WebP это куча форматов в одном контейнере Может быть
lossless и lossy Поддерживает прозрачность Может быть lossy для цвета и lossless для прозрачности Не может грузиться постепенно 50
Lossless и lossy WebP Lossy — основано на сжатии VP8
кодека Lossless — запилили отдельно 51
VP8X chunk alpha EXIF animation width height 52
Особенности lossy WebP Lossless алгоритм эффективней чем тот, что использует
JPEG Adaptive quantization 53
Как работают современные video-encoders Разбивают картинку на блоки Предсказывают новые
блоки на основе предыдущих 54
А можем еще лучше? WebP использует компрессию из VP8 видео
кодека… Что если взять видео кодек посовременнее? 55
А можем еще лучше? ffmpeg -i file.png \ -map_metadata -1
\ -an -c:v libaom-av1 -crf 24 \ -b:v 0 -an -vframe 1 -strict experimental result.mp4 <video muted src={video} type="video/mp4; codecs=av01.0.05M.08” /> 56
Как использовать AV1 57 evl.ms/blog/better-web-video-with-av1-codec
58 Инструменты
imgproxy 59 imgproxy.net
60 imgproxy с <picture> const getUrl = (imgproxyUrl, src, size,
dpr, extension) => `${imgproxyUrl}/fit/${dpr * size}/${dpr * size}/sm/0/plain/${src}${extension || ''}`; const createPicture = (imgproxyUrl, src, size) => ` <picture> <source srcset="${getUrl(imgproxyUrl, src, size, 1, '@webp')} @1x, ${getUrl(imgproxyUrl, src, size, 2, '@webp')} @2x" type="image/webp" /> <img src="${src}" srcset="${getUrl(imgproxyUrl, src, size, 1)} @1x, ${getUrl(imgproxyUrl, src, size, 2)} @2x" alt="a yummy cupcake" /> </picture>`
Squoosh 61
Еще полезные инструменты 62 libvips optipng libwebp mozjpeg ImageMagic ImageOptim
63
64 evl.ms/blog/images-done-right-web-graphics-good-to-the-last-byte-optimization-techniques
65 Спасибо! @polina_gurtovaya @pgurtovaya
[email protected]
65 @evilmartians @evilmartians_ru evilmartians.com