Реализация контрастного фильтра css / svg с использованием sharp (libvips) - PullRequest
0 голосов
/ 24 марта 2019

Я использую libvips для преобразования изображений на сервере с предварительным просмотром css / svg на интерфейсе для экономии ресурсов.

Я борюсь с реализацией функции фильтра контраста css / svg.

Спецификация показывает контраст в виде линейного преобразования в виде:

out = slope * in + intercept

, где intercept должно быть:

intercept = - (0.5 * slope) + 0.5

Таким образом, я могу использовать contrast(1.25) для предварительного просмотра модификаций изображений css.

Однако, реализация этой линейной функции в libvips через JS Library Sharp:

sharp.linear(contrast, - (0.5 * contrast) + 0.5)

Если посмотреть глубже на контрастность изображения, ожидаемый результат состоит в том, что максимумы ставятся еще выше, а минимумы - еще ниже. Это похоже на противоречие со спецификацией, потому что спецификация применяет линейное преобразование, поэтому она всегда должна быть кратной и складываемой, повышая максимумы, но немного увеличивая минимумы.

Используя linear in sharp (и, следовательно, в libvips) для изменения контраста, вывод фактически выглядит как фильтр яркости, который в фильтре css / svg находится в форме линейного преобразования без добавления

out = slope * in

Мне кажется, что я неправильно понимаю, что делает перехват в линейной функции SVG. Кроме того, сравнение SVG и CSS показывает различия. Использование contrast(2) в css должно имитировать slope = 2 и intercept = -(0.5 * 2) + 0.5 = -0.5 в svg, что не так в этой скрипке:

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg>
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>

Хорошо видно, что второе изображение с svg-фильтром выглядит иначе, чем третье с использованием css-фильтра.

Мое понимание фильтров совершенно неверно? Я ожидаю, что должен быть какой-то порог, чтобы инвертировать умножение в деление для минимумов.

Как я могу реализовать контраст CSS в разных средах как линейную функцию с одинаковым результатом?

1 Ответ

1 голос
/ 26 марта 2019

Ваша интуиция не верна :) Для входных значений меньше 0,5 - формула уменьшает яркость - почему?Давайте возьмем значение контрастности 2 и входное значение 0,4

Выход = 2 * 0,4 - (0,5 * 2) + 0,5

Выход = 0,8 - 1 + 0,5

Output = 0.3

Как вы можете видеть, когда вход ниже 0,5, выход всегда будет меньше, чем вход, потому что сумма компонента наклона и первого (отрицательного) компонента пересечениябудет равен контрасту, умноженному на разницу между входом и 0,5

. Эта формула приводит к унифицированным значениям (с полами и с потолком 0/1).

enter image description here

Также CSS-фильтры по умолчанию используют цветовое пространство sRGB.Фильтры SVG используют linearRGB.Вам необходимо установить цветовое пространство фильтра SVG на sRGB, добавив атрибут: color-interpolation-filters = "sRGB" к вашему элементу svg.Когда вы делаете это - ваши изображения выглядят одинаково.

.svg {
  filter: url(#contrast);
}

.css {
  filter: contrast(2);
}
<img src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="svg" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">
<img class="css" src="https://dev-cdn.swbpg.com/o/g/1515254671.jpeg" width="300">

<svg color-interpolation-filters="sRGB">
  <filter id="contrast">
    <feComponentTransfer>
      <feFuncR type="linear" slope="2" intercept="-0.5"/>
      <feFuncG type="linear" slope="2" intercept="-0.5"/>
      <feFuncB type="linear" slope="2" intercept="-0.5"/>
    </feComponentTransfer>
  </filter>
</svg>
...