安卓系统只保留一张位图作为改变色调、对比度、饱和度等的源头。

问题描述 投票:0回答:1

我正在我的android应用中开发一个功能,用户可以使用SeekBar修改位图的饱和度、色调、对比度等。我已经为每个处理写了不同的方法。这可以单独工作,但如果我改变位图的色调,在调用任何其他方法之前,例如饱和度,我想保留位图和应用的色调进度等。如果进度设置为默认,用户应该能够看到原始的位图。

例如,如果我把位图的色相值改为200,那么用户就可以看到原图。现在如果我想编辑饱和度,新的饱和度位图应该是应用色调。如果我把饱和度和色调进度重置为默认值,那么用户应该能够看到原始的位图颜色。

我试过很多方法来实现这种行为,例如在每次方法调用前复制像素,但没有任何帮助。目前,我只是在用户点击每个位图处理类型时将修改后的位图像素复制到原始位图中,但如果我重置所有的值,位图就不会变成原始颜色。请看我的代码。

我希望这能帮助理解这个问题。

private Bitmap wallpaper, modifiedWallpaper;
private ImageView imageView;
private ImageButton contrast;
private ImageButton hue;
private ImageButton saturation;
private float contrastProgress;
private float hueProgress;
private float satProgress;
private boolean isBlur, isBright, isContrast;
private boolean isHue, isSaturation, isRGB;
private TextView currentMode;
private SeekBar seekBar;
private Paint paint;
private Canvas canvas;
private CardView editor;


@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.inflate(R.layout.fragment_customize_wallpaper, container, false);
    imageView = view.findViewById(R.id.wallpaper);
    rgbContainer = view.findViewById(R.id.rgb);
    close = view.findViewById(R.id.close);
    currentMode = view.findViewById(R.id.current_mode);
    seekBar = view.findViewById(R.id.seekBar);
    seekBar.setOnSeekBarChangeListener(seekBarChangeListener);


    contrast = view.findViewById(R.id.contrast);
    hue = view.findViewById(R.id.hue);
    saturation = view.findViewById(R.id.saturation);

    contrast.setOnClickListener(this);
    hue.setOnClickListener(this);
    saturation.setOnClickListener(this);
    satProgress = 256f;

    loadWallpaper(final String wallpaperUrl);     
    return view;
}


private void loadWallpaper(final String wallpaperUrl) {
    Picasso.get().load(Constants.DOMAIN + wallpaperUrl).into(new Target() {
        @Override
        public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
            wallpaper = bitmap; //original loaded
            modifiedWallpaper = wallpaper.copy(Bitmap.Config.ARGB_8888, true);
            imageView.setImageBitmap(wallpaper);
        }

        @Override
        public void onBitmapFailed(Exception e, Drawable errorDrawable) {

        }

        @Override
        public void onPrepareLoad(Drawable placeHolderDrawable) {

        }
    });
}


@Override
public void onClick(View view) {
    switch (view.getId()) {
       case R.id.contrast : {
            wallpaper = modifiedWallpaper.copy(Bitmap.Config.ARGB_8888, true);
            isBlur = false;
            isBright = false;
            isContrast = true;
            isHue = false;
            isSaturation = false;
            isRGB = false;
            seekBar.setVisibility(View.VISIBLE);
            rgbContainer.setVisibility(View.GONE);
            changeIconTint();
            seekBar.setOnSeekBarChangeListener(null);
            seekBar.setMax(90);
            seekBar.setProgress((int) contrastProgress);
            seekBar.setOnSeekBarChangeListener(seekBarChangeListener);
            currentMode.setText("Contrast");
            break;
        }
        case R.id.hue : {
            wallpaper = modifiedWallpaper.copy(Bitmap.Config.ARGB_8888, true);
            isBlur = false;
            isBright = false;
            isContrast = false;
            isHue = true;
            isSaturation = false;
            isRGB = false;
            seekBar.setVisibility(View.VISIBLE);
            rgbContainer.setVisibility(View.GONE);
            changeIconTint();
            seekBar.setOnSeekBarChangeListener(null);
            seekBar.setMax(180);
            seekBar.setProgress((int) hueProgress);
            seekBar.setOnSeekBarChangeListener(seekBarChangeListener);
            currentMode.setText("Hue");
            break;
        }
        case R.id.saturation : {
            wallpaper = modifiedWallpaper.copy(Bitmap.Config.ARGB_8888, true);
            isBlur = false;
            isBright = false;
            isContrast = false;
            isHue = false;
            isSaturation = true;
            isRGB = false;
            seekBar.setVisibility(View.VISIBLE);
            rgbContainer.setVisibility(View.GONE);
            changeIconTint();
            seekBar.setOnSeekBarChangeListener(null);
            seekBar.setMax(512);
            seekBar.setProgress((int) satProgress);
            seekBar.setOnSeekBarChangeListener(seekBarChangeListener);
            currentMode.setText("Saturation");
            break;
        }
    }
}

private void changeContrast(float contrastProgress) {
    float cb = this.contrastProgress == 0 ? 0 : -(this.contrastProgress / 1.8f) * 5;
    ColorMatrix cm = new ColorMatrix(new float[]
            {
                    contrastProgress, 0, 0, 0, cb,
                    0, contrastProgress, 0, 0, cb,
                    0, 0, contrastProgress, 0, cb,
                    0, 0, 0, contrastProgress, 0
            });

    paint = new Paint();
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    modifiedWallpaper = wallpaper.copy(Bitmap.Config.ARGB_8888, true);
    canvas = new Canvas(modifiedWallpaper);
    canvas.drawBitmap(modifiedWallpaper, 0, 0, paint);
    imageView.setImageBitmap(modifiedWallpaper);
}

private void changeHue() {
    ColorMatrix cm = new ColorMatrix();
    float hueProgress = cleanValue() / 90f * (float) Math.PI;
    if (hueProgress == 0){
        return;
    }

    float cosVal = (float) Math.cos(hueProgress);
    float sinVal = (float) Math.sin(hueProgress);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]
            {//logic };
    cm.postConcat(new ColorMatrix(mat));

    paint = new Paint();
    paint.setColorFilter(new ColorMatrixColorFilter(cm));
    modifiedWallpaper = wallpaper.copy(Bitmap.Config.ARGB_8888, true);
    canvas = new Canvas(modifiedWallpaper);
    canvas.drawBitmap(modifiedWallpaper, 0, 0, paint);
    imageView.setImageBitmap(modifiedWallpaper);
}

private void changeSaturation() {
    ColorMatrix colorMatrix = new ColorMatrix();
    colorMatrix.setSaturation(satProgress / 256);
    paint = new Paint();
    paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
    modifiedWallpaper = wallpaper.copy(Bitmap.Config.ARGB_8888, true);
    canvas = new Canvas(modifiedWallpaper);
    canvas.drawBitmap(modifiedWallpaper, 0, 0, paint);
    imageView.setImageBitmap(modifiedWallpaper);
}

private SeekBar.OnSeekBarChangeListener seekBarChangeListener = new SeekBar.OnSeekBarChangeListener() 
{
    @Override
    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
        if (isContrast) {
            contrastProgress = seekBar.getProgress();
            Log.d("Contrast", "" + (int) contrastProgress);
            changeContrast((float) (seekBar.getProgress() + 10) / 10);
            return;
        }
        if (isHue) {
            hueProgress = seekBar.getProgress();
            Log.d("Hue", "" + (int) hueProgress);
            changeHue();
            return;
        }
        if (isSaturation) {
            satProgress = seekBar.getProgress();
            Log.d("Saturation", "" + (int) satProgress);
            changeSaturation();
        }
    }

    @Override
    public void onStartTrackingTouch(SeekBar seekBar) {

    }

    @Override
    public void onStopTrackingTouch(SeekBar seekBar) {

    }
};
java android android-studio image-processing android-bitmap
1个回答
1
投票

你在应用滤镜时没有保存状态。你创建了一个 新的 Paint 附带 新的 ColorMatrix 和a 新的 Bitmap. 这就是为什么一个过滤器会覆盖前一个过滤器的原因。

有几种方法可以解决这个问题。我认为第一步是将 "过滤 "和 "绘图 "功能分开。例如:在你的代码中,"过滤 "和 "绘制 "功能是分开的。changeSaturation() 在你的代码中,不仅改变了饱和度,而且还在屏幕上画了图。我是这样做的。

    @Override
    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
        if (isContrast) contrast = (float) (seekBar.getProgress() + 10) / 10
        if (isHue) hue = seekBar.getProgress();
        if (isSaturation) saturation = seekBar.getProgress();

        ColorMatrix matrix = calculateColorMatrix(contrast, hue, saturation);
        drawBitmap(matrix);
    }


    private void drawBitmap(ColorMatrix colorMatrix) {
         Paint paint = new Paint();
         paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
         modifiedWallpaper = wallpaper.copy(Bitmap.Config.ARGB_8888, true);
         canvas = new Canvas(modifiedWallpaper);
         canvas.drawBitmap(modifiedWallpaper, 0, 0, paint);
         imageView.setImageBitmap(modifiedWallpaper);
    }

    private ColorMatrix calculateColorMatrix(float contrast, hue, saturation) {
        ColorMatrix colorMatrix = new ColorMatrix();

        // saturation
        colorMatrix.setSaturation(satProgress / 256);

        // hue   
        float cosVal = (float) Math.cos(hueProgress);
        float sinVal = (float) Math.sin(hueProgress);
        float lumR = 0.213f;
        // logic...
        colorMatrix.postConcat(new ColorMatrix(mat));

        //contrast
        // logic...
        colorMatrix.postConcat(new ColorMatrix(new float[]
            {
                    contrastProgress, 0, 0, 0, cb,
                    0, contrastProgress, 0, 0, cb,
                    0, 0, contrastProgress, 0, cb,
                    0, 0, 0, contrastProgress, 0
            }));

        return colorMatrix;
    }

这只是其中一种方法。可能是最简单的一种。如果你不想每次滑块移动时都创建所有的过滤器,你可以保持三个不同的 matrix 每个过滤器都有一个,每次只修改其中一个。

    ColorMatrix hue = new ColorMatrix();
    ColorMatrix sat = new ColorMatrix();
    ColorMatrix con = new ColorMatrix();

    @Override
    public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
        if (isContrast) {
         con = //logic to create contrast matrix
        }
        if (isHue) {
         hue //logic to create hue matrix
        }
        if (isSaturation) {
          //...
          sat.setSaturation(...)
        }


        ColorMatrix matrix = hue.postConcat(sat).postConcat(con);
        drawBitmap(matrix);
    }

我还没有亲自测试过这段代码,你可能要做一些修改,但我希望这能让你走上正确的方向!

© www.soinside.com 2019 - 2024. All rights reserved.