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
Modern Angular with Signals and Signal Store:New Rules for Your Architecture @enterJS Advanced Angular Day 2025
manfredsteyer
PRO
0
230
The Modern View Layer Rails Deserves: A Vision For 2025 And Beyond @ RailsConf 2025, Philadelphia, PA
marcoroth
2
510
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
540
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
660
#QiitaBash MCPのセキュリティ
ryosukedtomita
1
1.4k
猫と暮らす Google Nest Cam生活🐈 / WebRTC with Google Nest Cam
yutailang0119
0
160
10 Costly Database Performance Mistakes (And How To Fix Them)
andyatkinson
0
440
ISUCON研修おかわり会 講義スライド
arfes0e2b3c
1
450
状態遷移図を書こう / Sequence Chart vs State Diagram
orgachem
PRO
1
130
AIともっと楽するE2Eテスト
myohei
7
2.8k
たった 1 枚の PHP ファイルで実装する MCP サーバ / MCP Server with Vanilla PHP
okashoi
1
270
なんとなくわかった気になるブロックテーマ入門/contents.nagoya 2025 6.28
chiilog
1
280
Featured
See All Featured
Visualization
eitanlees
146
16k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Docker and Python
trallard
44
3.5k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
Into the Great Unknown - MozCon
thekraken
40
1.9k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
5.9k
How to train your dragon (web standard)
notwaldorf
96
6.1k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
281
13k
Why You Should Never Use an ORM
jnunemaker
PRO
58
9.4k
Fashionably flexible responsive web design (full day workshop)
malarkey
407
66k
Building Flexible Design Systems
yeseniaperezcruz
328
39k
Music & Morning Musume
bryan
46
6.6k
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