Реалізація накладення фільтрів на фотографії в мобільному застосунку
Карусельні стрічки з попередніми переглядами фільтрів — як в Instagram. Користувач листає пальцем та в реальному часі бачить результат. Якщо попередній перегляд гальмує або застосування фінального фільтра займає 2+ секунди, UX зруйнований. Вся техніка тут — про швидкість.
Як працюють фільтри на рівні GPU
Фільтр — це побітне перетворення: беремо RGBA-значення кожного піксела, застосовуємо математику, записуємо нове значення. Наївна реалізація на CPU для 12 Мп фото займе 200–400 мс. GPU обробляє ті самі пікселі паралельно за 5–15 мс.
iOS. Два шляхи: CIFilter (Core Image) та Metal шейдери.
CIFilter — простіше, вбудовано в систему. Для більшості фотофільтрів достатньо: CIColorMonochrome, CIPhotoEffectChrome, CIVignette, CIColorCurves (iOS 16+). Будуємо ланцюжок фільтрів через filter.outputImage → наступний фільтр. CIContext(options: [.useSoftwareRenderer: false]) обов'язковий — інакше рендеринг на CPU.
Metal потрібен, коли хочеться ефектів, яких немає в CIFilter: дуотон із користувацькими кольорами, зональні регулювання, LUT-фільтри високої розділення. Пишемо fragment shader на MSL:
fragment float4 duotoneFilter(VertexOut in [[stage_in]],
texture2d<float> texture [[texture(0)]]) {
float4 color = texture.sample(sampler, in.texCoord);
float luma = dot(color.rgb, float3(0.299, 0.587, 0.114));
return mix(shadowColor, highlightColor, luma);
}
Android. GPUImage (бібліотека) — порт популярних iOS-фільтрів на OpenGL ES. GPUImageFilter, GPUImageFilterGroup для ланцюжків. Для попереднього перегляду — GPUImageView показує результат безпосередньо на SurfaceTexture без проміжного Bitmap. У новіших проектах дивимося в сторону Vulkan через RenderScript Intrinsics Replacement Toolkit.
Flutter. image (pub.dev) — обробка на CPU, повільно для попереднього перегляду в реальному часі. Для реального часу — ColorFiltered віджет із ColorFilter.matrix() для базових коригувань. Складні фільтри — через Flutter Texture + нативний код OpenGL/Metal на боці платформи.
LUT-фільтри: Професійний підхід
Look Up Table — 3D-таблиця 64×64×64 (або 16×16×16 для мобільних). Кожний RGB-вхід дає RGB-вихід через інтерполяцію. Дизайнер створює LUT в Lightroom/Photoshop, розробник підключає як текстуру в шейдер. На iOS — CIColorCube або CIColorCubeWithColorSpace. Одна LUT-текстура замінює набір кольорокорегуючих операцій.
Попередній перегляд каруселі без гальм
Генеруємо попередній перегляд заздалегідь: при завантаженні екрана створюємо зменшену копію (300×300 пх) через UIGraphicsImageRenderer, пропускаємо через кожний фільтр, кешуємо в NSCache. Користувач листає карусель — картинки вже готові. Фіналь рендеринг у повній розділеності запускається тільки після вибору фільтра.
Збереження налаштувань фільтра
Користувач вибрав «Хром» з інтенсивністю 0.7 — при повернені до посту це значення повинно відновитися. Зберігаємо не готове зображення, а параметри фільтра (filterName, intensity) — це дозволяє редагувати фото після збереження чернетки без втрати якості.
Фіналь рендеринг у повній розділеності запускаємо тільки перед публікацією або експортом. Це зберігає оригінал недоторканим і дає можливість відмінити фільтр в будь-який момент.
Орієнтири за часом
Набір із 6–10 CIFilter-фільтрів із карусельним попереднім переглядом — 3–4 дні. LUT-система з користувацькими шейдерами Metal/OpenGL — 5–7 днів.







