В версии 3.10 Flutter начал поддерживать P3 широкого цветового пространства для отрисовки изображений с помощью Impeller на устройствах iOS. Однако тогда эта поддержка была активна только при наличии изображений или градиентов с широким цветовым пространством. Если вы использовали API Color
, то заметили бы, что отрисовка всё ещё происходит в цветовом пространстве sRGB.
⚠️ Если вас не интересует причина и необходимость корректировки, вы можете сразу перейти к разделу адаптации.
Какие различия между sRGB и P3? Проще говоря, самое очевидное отличие можно видеть на следующих изображениях. На устройствах с поддержкой P3 цветового пространства P3 обеспечивает более широкий спектр цветов, поэтому вы видите более яркие и насыщенные цвета, а большинство мобильных устройств уже поддерживают P3 цветовое пространство в 2024 году.
Просто сравните цветовые пространства sRGB (белый треугольник) и Display P3 (оранжевый треугольник) на следующем изображении. Из пропорций следует, что P3 широкое цветовое пространство может поддерживать как минимум на 25% больше цветов по сравнению со sRGB.
Конечно, в версии 3.10 Flutter поддерживал широкое цветовое пространство только для отрисовки изображений с помощью Impeller, но для использования API Color
всё ещё применялось цветовое пространство sRGB. Это значит, что API для отрисовки широкого цветового пространства в Flutter Widgets пока недоступно.
Поэтому команда Flutter начала работу над рефакторингом объекта Color
в 2023 году, чтобы сделать его способным поддерживать P3 широкое цветовое пространство. Самым очевидным изменением стало то, что ранее диапазон допустимых значений составлял [0, 255], а теперь каждый компонент цвета представлен в виде числа с плавающей запятой в диапазоне [0, 1.0].
Вы, возможно, удивлены тем, почему диапазон [0, 255] был заменён на [0, 1.0], но при этом цветовое пространство стало шире. Это связано с увеличением точности данных после того, как целочисленные значения были заменены на числа с плавающей запятой.> До этого каждое значение цвета в диапазоне [0, 255] представляло собой 8 бит, передаваемые из Dart в движок в виде ARGB (4x8) и упаковываемые в одноцелочисленное число размером 32 бита (альфа-красный-синий-зелёный). Каждый цвет занимает 8 бит (255), затем этот цвет преобразуется в SkColor
Skia и далее в DlColor
, который также представляет собой целочисленное значение.
В Impeller
DlColor
преобразуется вimpeller::Color
, который имеет размер 128 бит, где каждый цвет представлен в виде нормализованного числа с плавающей запятой размером 32 бита. Таким образом, точность данных значительно повышается за счет увеличения количества используемых бит. Почему повышение количества бит важно для поддержки цветового пространства? Потому что P3 охватывает больше цветов, чем позволяют 8 бит на канал, поэтому требуется как минимум 10 бит на канал для представления всех цветов P3.Очевидно, до этого Flutter использовал целочисленное представление sRGB [0, 255], где каждый цвет занимает 8 бит, а вместе они составляют всего 32 бита. В то время как использование представления с плавающей запятой [0–1.0] изменило эту ситуацию:
Начиная с версии 3.27 beta,
dart:ui
теперь используетColor
, который может содержать до 320 бит вместо максимальных 64 бит.
Почему говорится о переходе от 64 бит до 320 бит? Потому что ранее в Color
был только один целый тип данных int
, который в Dart составляет 64 бита, следовательно, Color
мог иметь максимум 64 бита. Теперь же добавлены четыре значения типа double
: a
, r
, g
, b
. Каждое значение double
имеет 64 бита, таким образом, Color
теперь состоит из пяти значений, что даёт ему максимальные 320 бит. Однако в будущем значение value
будет废弃不用.
То есть каждое из
a
,r
,g
,b
теоретически может использовать до 64 бит, если не считатьvalue
,Color
переходит от 64-битного целого числа к 256-битному числу с плавающей запятой.
Затем компоненты отправляют данные о цветах в C++, а ранее было упомянуто, что в слое Engine DlColor
также адаптирован к 128 бит для совместимости с impeller::Color
, то есть DlColor
состоит из четырёх 32-битных значений типа float
, при этом поддерживаются старые версии sRGB цветового пространства.> Не обращайте внимания на различия между Dart/64 и C++/32, это просто особенность языка.
Кроме того, в ColorSpace
добавлена возможность использования displayP3
, что завершает базовую поддержку широкого цветового пространства. Но реальная поддержка P3 доступна пока только на iOS, а для Android потребуется более развитая поддержка Vulkan Impeller для дальнейшей оптимизации.
С изменениями в поддержке цвета внизу, API уровня Color
также претерпели существенные изменения. Эти изменения можно назвать серьезной перестройкой, поскольку изменения цветового пространства сильно влияют на верхний уровень API. Например, рекомендация использовать fromARGB
была заменена на использование Color.from
.
// До
final малиновый = Color.fromARGB(0xff, 0xff, 0x0, 0xff);
// После
final малиновый = Color.from(alpha: 1.0, red: 1.0, green: 0.0, blue: 1.0)
Кроме того, ранее в Color
существовало понятие -opacity
, поэтому присутствовали методы opacity
и withOpacity()
. Введением opacity раньше хотели сделать так, чтобы Color
имел альфа-канал с плавающей запятой, но теперь альфа — это просто число с плавающей запятой, поэтому использование opacity стало излишним. В будущем методы opacity
и withOpacity()
будут удалены:
// До
final x = color.opacity;
// После
final x = color.a;
``````dart
final x = color.withOpacity(0.0);
Кроме того, если вы используете наследование от Color
, лучше временно заменить его на implements
, то есть вам больше не потребуется реализовывать логику через super
. Почему временно? Потому что команда Flutter планирует в будущем закрыть Color
через sealed
, поэтому внешних реализаций Color
уже не будет.
class Foo implements Color {
int _red;
@override
double get r => _red * 255.0;
}
Кроме того, при использовании Color
и выполнении любых вычислений с цветами, следует сначала проверять пространство цветов (ColorSpace
) этого цвета, прежде чем выполнять вычисления. Для выполнения преобразования пространства цветов рекомендуется использовать новый метод Color.withValues
.
// До
double redRatio(Color x, Color y) => x.red / y.red;
// После
double redRatio(Color x, Color y) {
final xPrime = x.withValues(colorSpace: ColorSpace.extendedSRGB);
final yPrime = y.withValues(colorSpace: ColorSpace.extendedSRGB);
return xPrime.r / yPrime.r;
}
Выполнение вычислений с цветами без учета совместимости пространств цветов может привести к небольшим ошибкам. Например, в примере выше, если используется другое пространство цветов вместо совместимого, разница в значении redRatio
составит 0.09.
toDouble
, они оказывают значительное влияние на UI Flutter. Независимо от адаптации цветовых API, изменений в способах вычислений или поддержки новых цветовых пространств, эти изменения действительно затрагивают широкий спектр областей. Такие изменения могут вызывать проблемы с границами рендера, поэтому слияние было отложено до бета-версии. Возможно, скоро мы сможем видеть эти изменения в официальной версии.https://github.com/flutter/flutter/issues/55092
https://github.com/dart-lang/sdk/issues/56363
https://github.com/flutter/flutter/issues/127852
https://github.com/flutter/flutter/issues/127855
https://docs.flutter.dev/release/breaking-changes/wide-gamut-framework
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )