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
160
(не)идеальные картинки и другая пиксельная магия (ufadevconf))
Оптимизация web-изображений, котики и wasm
Polina Gurtovaya
November 30, 2019
Tweet
Share
More Decks by Polina Gurtovaya
See All by Polina Gurtovaya
Не учите алгоритмы
hellsquirrel
1
890
Давайте все заблокируем
hellsquirrel
0
280
Wasmысле?
hellsquirrel
0
190
Магия декларативныx схем.
hellsquirrel
0
320
ML for HolyJS
hellsquirrel
0
120
Идеальный способ заблюрить белочку
hellsquirrel
0
130
ML/DL на фронте
hellsquirrel
0
170
InsertableStreams
hellsquirrel
0
75
WebRTC-404
hellsquirrel
0
490
Other Decks in Programming
See All in Programming
Ruby's Line Breaks
yui_knk
2
480
S3静的ホスティング+Next.js静的エクスポート で格安webアプリ構築
iharuoru
0
220
Devin入門と最近のアップデートから見るDevinの進化 / Introduction to Devin and the Evolution of Devin as Seen in Recent Update
rkaga
9
4.8k
これだけは知っておきたいクラス設計の基礎知識 version 2
masuda220
PRO
24
6.1k
小田原でみんなで一句詠みたいな #phpcon_odawara
stefafafan
0
320
Bedrock×MCPで社内ブログ執筆文化を育てたい!
har1101
6
900
PHP で学ぶ OAuth 入門
azuki
1
130
プロダクト横断分析に役立つ、事前集計しないサマリーテーブル設計
hanon52_
2
390
Building Scalable Mobile Projects: Fast Builds, High Reusability and Clear Ownership
cyrilmottier
2
260
AWS で実現する安全な AI エージェントの作り方 〜 Bedrock Engineer の実装例を添えて 〜 / how-to-build-secure-ai-agents
gawa
8
710
SQL Server ベクトル検索
odashinsuke
0
170
RuboCop: Modularity and AST Insights
koic
0
100
Featured
See All Featured
Embracing the Ebb and Flow
colly
85
4.6k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Six Lessons from altMBA
skipperchong
27
3.7k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.3k
Facilitating Awesome Meetings
lara
54
6.3k
Gamification - CAS2011
davidbonilla
81
5.2k
Adopting Sorbet at Scale
ufuk
76
9.3k
It's Worth the Effort
3n
184
28k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Fontdeck: Realign not Redesign
paulrobertlloyd
83
5.5k
Large-scale JavaScript Application Architecture
addyosmani
512
110k
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