对同一个可绘制对象应用多个色彩过滤器

7
我希望对一个可绘制对象应用多个色彩过滤器,是否可能?或者创建一个包含我想要应用的过滤器组合的过滤器。
例如,我想要:
Drawable d = ...;
d.setColorFilter(0x3F000000, Mode.OVERLAY).setColorFilter(0xFF2D2D2D, Mode.SCREEN)
2个回答

8
这是我最终使用的方法:在Canvas上操作Drawable位图,并应用尽可能多的图层,使用Paint,它不仅适用于颜色过滤器,还适用于任何类型的图像混合。
...
Drawable myBackground = createBackground(getResources().getColor(R.color.Green)); 
setBackgroundDrawable(myBackground);
...

private Drawable createBackground(int color) {

    Canvas canvas = new Canvas();
    Bitmap buttonImage = BitmapFactory.decodeResource(getResources(), R.drawable.btn_image);
    Bitmap buttonShadows = BitmapFactory.decodeResource(getResources(), R.drawable.btn_shadows);
    Bitmap buttonHighLights = BitmapFactory.decodeResource(getResources(), R.drawable.btn_highlights);
    Bitmap result = Bitmap.createBitmap(buttonImage.getWidth(), buttonImage.getHeight(), Bitmap.Config.ARGB_8888);

    canvas.setBitmap(result);
    Paint paint = new Paint();
    paint.setFilterBitmap(false);

    // Color
    paint.setColorFilter(new PorterDuffColorFilter(color, Mode.MULTIPLY));
    canvas.drawBitmap(buttonImage, 0, 0, paint);
    paint.setColorFilter(null);
    // Shadows
    paint.setXfermode(new PorterDuffXfermode(Mode.MULTIPLY));
    canvas.drawBitmap(buttonShadows, 0, 0, paint);
    // HighLights
    paint.setXfermode(new PorterDuffXfermode(Mode.SCREEN));
    canvas.drawBitmap(buttonHighLights, 0, 0, paint);

    paint.setXfermode(null);
    return new BitmapDrawable(getResources(), result);
}

注意:setBackgroundDrawable(Drawable d) 已经被弃用,而 setBackground(Drawable d) 只能在 API 16 或更高版本中使用。因此,如果您的最小目标 API 版本是 14,最大目标 API 版本是 17(像我一样的情况),则没有“干净”的方法将绘制设置为背景。我仍然使用了被弃用的调用。


1
在大量搜索后,我没有找到一个完全满足我的需求的答案。然而,我偶然发现了2018年的this video "Practical Image Processing in Android",它指引我找到了正确的方向:使用ImageFilterView类。你可以在这里找到documentation
看到他们如何在同一张图片上应用多个过滤器非常有教育意义,并且并不难。它包括使用ColorMatrix并通过调用ColorMatrix.postConcat方法连接多个其他ColorMatrix。最终结果包含了您应用的所有过滤器。
以下是一个示例代码,用于更改图像的亮度和饱和度。
package com.rewieer.imagefilters;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.SeekBar;

public class MainActivity extends AppCompatActivity {
  private ImageView image;
  private SeekBar brightnessSeekBar;
  private SeekBar saturationSeekBar;
  private BitmapDrawable defaultDrawable;

  private int brightness = 0;
  private int saturation = 0;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    image = findViewById(R.id.mainImage);
    defaultDrawable = (BitmapDrawable) image.getDrawable();

    brightnessSeekBar = findViewById(R.id.brightnessSeekBar);
    saturationSeekBar = findViewById(R.id.saturationSeekBar);

    brightnessSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        brightness = progress;
        redraw();
      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {

      }

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {

      }
    });

    saturationSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
      @Override
      public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        saturation = progress;
        redraw();
      }

      @Override
      public void onStartTrackingTouch(SeekBar seekBar) {

      }

      @Override
      public void onStopTrackingTouch(SeekBar seekBar) {

      }
    });
  }

  public void redraw() {
    ColorMatrix matrix = new ColorMatrix();
    matrix.postConcat(new ColorMatrix(new float[]{
        1f, 0, 0, 0, brightness,
        0, 1f, 0, 0, brightness,
        0, 0, 1f, 0, brightness,
        0, 0, 0, 1f, 0
    }));

    float MS = 1.0F - saturation;
    float Rt = 0.2999F * MS;
    float Gt = 0.587F * MS;
    float Bt = 0.114F * MS;

    matrix.postConcat(new ColorMatrix(new float[]{
        Rt + saturation, Gt, Bt, 0, 0,
        Rt, Gt + saturation, Bt, 0, 0,
        Rt, Gt, Bt + saturation, 0, 0,
        0, 0, 0, 1f, 0
    }));

    image.setColorFilter(new ColorMatrixColorFilter(matrix));
  }
}

这里最重要的方法是redraw。 通过查看ImageFilterView源代码,我们也可以通过简单地复制粘贴它们的算法来轻松地为图像应用温暖和对比度。

很遗憾,ImageFilterView不支持视图绑定。 - Veniamin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接