Перевод картинки в серый средствами CSS

Серое в CSS (92.76КиБ)

Экспериментировал в рамках прототипа для рабочего проекта с преобразованием изображения в серую гамму. Вообще, конечно, есть тег CANVAS, там это запросто, но интересно посмотреть появилось ли что-то в CSS со времён фильтров «Эксплорера». В IE с незапамятных времён (ещё с пятой версии) есть фильтр «gray», который даёт нужный эффект. Сейчас фильтры обзавелись префиксами и их рекомендуемый синтаксис иной, но суть та же:

.gray {
        filter: gray; /* IE 5+ */
        -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"; /* new IE */
}

Я всё ждал когда же W3C «переизобретёт» микрософтские фильтры. Свершилось. Недавно появилась спецификация Filter Effects, которая, конечно, гораздо шире того, что когда-то предложили в «Микрософте», но основной смысл тот же, и даже некоторые фильтры похожи.

«Хром» включил в готовящуяся 18-ю версию эксперементальную поддержку этих фильтров:

.gray {
        -webkit-filter: grayscale(1); /* Chrome 18+ */
}

В «Опере» и «Файрфоксе» поддержки этих фильтров пока нет, но есть поддержка других — фильтров SVG. Можно, например, засунуть растровое изображение внутрь SVG и применить к нему нужный фильтр:

<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>

<!-- тут какой-то HTML код и вдруг понадобилась серая картика -->
<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="100%" height="100%" filter="gray" /></svg>

Хорошие новости — SVG можно мешать с HTML. С версии 3.5 в «Файерфоксе» есть способ лучше — можно применять фильры SVG прямо к тегам HTML (и делать всякие другие чудесные штуки), правда все описания в документации почему-то относятся к XHTML или внешним ресурсам, но я обнаружил, что уже с четвёртой версии этот же трюк работает и с обычным HTML:

<style>
    .gray {
        filter: url(#gray);  /* Firefox 4+ */
    }
</style>

<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>

<body><img src="/imgs/2008.11.27.jpg" class="gray" /></body>

Добавлено позднее: в ходе дальнейших экспериментов оказалось, что в более ранних «Хромах» (нижнюю границу я пока не выяснил, но в моём 17-м работает), можно через CSS задавать фильтры для SVG, вот таким образом:

<style>
    .gray {
        -webkit-filter: url(#gray); /* Chrome ?? */
        -webkit-filter: grayscale(1); /* Chrome 18+ 
    }
</style>

<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>

<!-- тут HTML и внезапно понадобилась серая картинка -->

<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="400" height="431" class="gray" /></svg>

При этом «Хром» требует, чтобы ширина и высота картинки были заданы в абсолютных единицах (остальные браузеры прекрасно понимают проценты).

Если собрать всё вместе, получается нижеприведённый код. Я поставил рядом два изображения: слева обычный элемент HTML img, справа — растр в SVG, по ссылке можно протестировать что поддерживает ваш браузер.

Посмотреть код.

<html>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<style>
    .gray {
        cursor: pointer;

        filter: url(#gray);  /* Firefox 4+ */
        filter: gray; /* IE 5+ */
        -webkit-filter: url(#gray); /* Chrome ?? */
        -webkit-filter: grayscale(1); /* Chrome 18+ */
        -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"; /* new IE */
    }

    .gray:hover {
        filter: none;
        -webkit-filter: none;
        -ms-filter: none;
    }

</style>

<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>

<body>
<img src="/imgs/2008.11.27.jpg" class="gray" />
<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="400" height="431" class="gray" /></svg>
</body>

</html>

Мне негде потестировать IE и тем более десятую версию, но я где-то читал, что из «десятки» убрали фильтры, поэтому я, на всякий случай, поставил режим совместимости с девятой версией в коде.

27 комментариев

libjpeg-turbo

Сегодня от нашего системного администратора узнал о библиотеке libjpeg-turbo. Это оптимизированная под SIMD-инструкции (MMX, SSE и NEON) библиотека libjpeg.

Авторами утверждается, что библиотека превосходит оригинальную по скорости в несколько раз.

Самое интересное, что библиотека бинарно соместима с оригиналом, то есть простой заменой одной на другую в системе можно добиться прироста производительности всех утилит, которые её используют.

Я погонял тесты у себя на ноутбуке с «МакОС», результаты получились следующие:

bolk@Bolk ~  $ otool -L `which jpegtran` | fgrep libjpeg
    /usr/local/Cellar/jpeg/8d/lib/libjpeg.8.dylib (compatibility version 13.0.0, current version 13.0.0)

bolk@Bolk ~  $ time for _ in {1..100}; do jpegtran -optimize -crop 4000x3000+2+2 ex.jpg > /dev/null; done

real	1m28.244s
user	1m20.063s
sys	0m7.705

bolk@Bolk ~ $ otool -L /opt/libjpeg-turbo/bin/jpegtran | fgrep libjpeg
/opt/libjpeg-turbo/bin/jpegtran:
    /opt/libjpeg-turbo/lib/libjpeg.62.dylib (compatibility version 63.0.0, current version 63.0.0)

bolk@Bolk ~  $ time for _ in {1..100}; do /opt/libjpeg-turbo/bin/jpegtran -optimize -crop 4000x3000+2+2 ex.jpg > /dev/null; done

real	0m59.433s
user	0m50.509s
sys	0m7.728s

В моём случае прирост порядка 30%. Для теста я взял случайную картинку из фотоальбомов с разрешением 5184×3456 и при помощи утилиты jpegtran вырезал оттуда кусок изображения. Каждый тест повторялся сто раз.

10 комментариев