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
140
(не)идеальные картинки и другая пиксельная магия (ufadevconf))
Оптимизация web-изображений, котики и wasm
Polina Gurtovaya
November 30, 2019
Tweet
Share
More Decks by Polina Gurtovaya
See All by Polina Gurtovaya
Не учите алгоритмы
hellsquirrel
1
820
Давайте все заблокируем
hellsquirrel
0
260
Wasmысле?
hellsquirrel
0
150
Магия декларативныx схем.
hellsquirrel
0
310
ML for HolyJS
hellsquirrel
0
79
Идеальный способ заблюрить белочку
hellsquirrel
0
99
ML/DL на фронте
hellsquirrel
0
140
InsertableStreams
hellsquirrel
0
60
WebRTC-404
hellsquirrel
0
460
Other Decks in Programming
See All in Programming
What’s New in Compose Multiplatform - A Live Tour (droidcon London 2024)
zsmb
1
470
最新TCAキャッチアップ
0si43
0
140
Jakarta EE meets AI
ivargrimstad
0
120
弊社の「意識チョット低いアーキテクチャ」10選
texmeijin
5
24k
Snowflake x dbtで作るセキュアでアジャイルなデータ基盤
tsoshiro
2
520
Tauriでネイティブアプリを作りたい
tsucchinoko
0
370
Flutterを言い訳にしない!アプリの使い心地改善テクニック5選🔥
kno3a87
1
150
LLM生成文章の精度評価自動化とプロンプトチューニングの効率化について
layerx
PRO
2
190
카카오페이는 어떻게 수천만 결제를 처리할까? 우아한 결제 분산락 노하우
kakao
PRO
0
110
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
290
Compose 1.7のTextFieldはPOBox Plusで日本語変換できない
tomoya0x00
0
190
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
410
Designing for humans not robots
tammielis
250
25k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
6.9k
How to Ace a Technical Interview
jacobian
276
23k
BBQ
matthewcrist
85
9.3k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5k
RailsConf 2023
tenderlove
29
900
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.5k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.8k
Building a Scalable Design System with Sketch
lauravandoore
459
33k
Docker and Python
trallard
40
3.1k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
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