В этом уроке:
- используем PorterDuffColorFilter
Вернемся к теме ColorFilter, рассмотренной нами в Уроке 153. Там мы использовали два фильтра ColorMatrixColorFilter и LightingColorFilter. Сейчас рассмотрим третий – PorterDuffColorFilter. Если вы не читали Урок 154, то обязательно прочитайте, там я уже начал рассказывать про PorterDuff-режимы. Сейчас будет продолжение этой темы.
Механизм PorterDuffColorFilter похож на PorterDuffXfermode. Только вместо двух картинок у нас будет картинка и цвет. При создании объекта PorterDuffColorFilter вы указываете цвет, и он будет играть роль SRC-картинки полностью залитой этим цветом.
Посмотрим на примере.
Создадим проект:
Project name: P1551_PorterDuffColorFilter
Build Target: Android 4.4
Application name: PorterDuffColorFilter
Package name: ru.startandroid.develop.p1551porterduffcolorfilter
Create Activity: MainActivity
MainActivity.java:
package ru.startandroid.develop.p1551porterduffcolorfilter;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawView(this));
}
class DrawView extends View {
Paint[] paints;
Paint paintBorder;
Bitmap bitmap;
int size = 200;
PorterDuff.Mode mode = PorterDuff.Mode.SRC;
int[] colorSrc = new int[] { Color.WHITE, Color.LTGRAY, Color.GRAY,
Color.DKGRAY, Color.BLACK };
public DrawView(Context context) {
super(context);
// необходимо для корректной работы
if (android.os.Build.VERSION.SDK_INT >= 11) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
// создание bitmap картинки необходимого размера
bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
bitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
// создание массива кистей paints
paints = new Paint[colorSrc.length];
for (int i = 0; i < colorSrc.length; i++) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// для каждой кисти свой PorterDuffColorFilter
// с цветом из массива colorSrc
paint.setColorFilter(new PorterDuffColorFilter(colorSrc[i],
mode));
paints[i] = paint;
}
// кисть для рамок
paintBorder = new Paint();
paintBorder.setStyle(Paint.Style.STROKE);
paintBorder.setStrokeWidth(3);
paintBorder.setColor(Color.BLACK);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.translate(0, 200);
int delta = (canvas.getWidth() - size * paints.length)
/ (paints.length + 1);
// рисование bitmap
for (int i = 0; i < paints.length; i++) {
canvas.translate(delta, 0);
// используем кисти из массива paints
canvas.drawBitmap(bitmap, 0, 0, paints[i]);
canvas.drawRect(0, 0, size, size, paintBorder);
canvas.translate(size, 0);
}
}
}
}
Переменная mode будет содержать текущий PorterDuff-режим. Эту переменную будем менять по ходу урока.
Массив colorSrc содержит 5 цветов: градация от белого до черного. Наш пример будет выводить сразу 5 результатов наложения картинки на цвет. Это придаст результату больше наглядности.
В конструкторе DrawView создаем картинку со стандартной Android-иконкой. Затем для каждого цвета из массива colorSrc создаем отдельную кисть со своим PorterDuffColorFilter.
В onDraw выводим bitmap используя созданный массив кистей.
Результат:

Напомню, что цвет указанный при создании PorterDuffColorFilter – это SRC-картинка, а bitmap – DST-картинка.
Т.к. мы указали режим PorterDuff.Mode.SRC, то мы видим только SRC-картинку т.е. цвет.
Поменяем значение mode на PorterDuff.Mode.DST.

Теперь мы во всех вариантах видим только DST-картинку, т.е. bitmap.
Эти простые PorterDuff-режимы мы уже рассматривали на прошлом уроке. Теперь посмотрим на более сложные.
MULTIPLY
Перемножение SRC и DST цветов. Умножение цвета на белый (1,1,1) не меняет цвет, умножение на черный (0,0,0) – делает его черным.

DARKEN
При расчете пикселов результата выбирается наиболее темный из двух исходных: SRC и DST.

LIGHTEN
При расчете пикселов результата выбирается наиболее светлый из двух исходных: SRC и DST.

SCREEN
Похож на MULTIPLY, только наоборот. При скрещении цвета с белым получается белый, при скрещении с черным – цвет не меняется.

OVERLAY
Этот режим, к сожалению, не могу прокомментировать. Похоже на изменение контрастности картинки.

Рекомендую поэксперементировать с цветами и использовать не белый/серый/черный, а оттенки какого-либо другого цвета. И посмотреть результат при разных режимах.
Например, красный цвет:
int[] colorSrc = new int[] { Color.rgb(50, 0, 0), Color.rgb(100, 0, 0),
Color.rgb(150, 0, 0), Color.rgb(200, 0, 0),
Color.rgb(250, 0, 0) };
c режимом MULTIPLY будет выглядеть вот так:

На следующем уроке:
- используем AvoidXfermode
Присоединяйтесь к нам в Telegram:
- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.
- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance
- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня

