You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android实现快速Color Splash效果的方法或库推荐请求

嘿,我之前刚好踩过逐像素处理大图的坑,那种卡顿感真的难受!给你几个高效实现Android Color Splash效果的方案,亲测好用:

高效实现Android Color Splash效果的方案

一、首选:使用RenderScript(官方高性能方案)

RenderScript是Android官方提供的高性能计算框架,专门针对像素级、矩阵类的密集型运算优化,能利用GPU或多核CPU加速,处理大图的速度比Java逐像素快5-10倍以上,而且不需要引入第三方库,兼容性也不错(API 11+,低版本可借助支持库)。

步骤1:创建RenderScript脚本文件

在src/main/rs目录下创建ColorSplash.rs(如果没有rs目录就新建一个):

#pragma version(1)
#pragma rs java_package_name(com.your.package.name) // 替换成你的包名

rs_allocation inputImage;
rs_allocation outputImage;
float3 targetColor;
float tolerance = 0.2f; // 颜色容差,值越大匹配的颜色范围越广

void root(const uchar4 *v_in, uchar4 *v_out) {
    // 把输入像素转为0-1的浮点颜色值
    float3 inColor = rsUnpackColor8888(*v_in);
    // 计算与目标颜色的欧氏距离
    float diff = distance(inColor, targetColor);
    
    if (diff > tolerance) {
        // 去饱和化:转为灰度
        float gray = 0.299f * inColor.r + 0.587f * inColor.g + 0.114f * inColor.b;
        *v_out = rsPackColorTo8888(gray, gray, gray, inColor.a);
    } else {
        // 保留原颜色
        *v_out = *v_in;
    }
}

步骤2:Java端调用代码

import android.graphics.Bitmap;
import android.graphics.Color;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptC_ColorSplash;

public Bitmap applyColorSplash(RenderScript rs, Bitmap originalBitmap, int targetColor) {
    // 创建输出Bitmap
    Bitmap outputBitmap = Bitmap.createBitmap(
        originalBitmap.getWidth(), 
        originalBitmap.getHeight(), 
        originalBitmap.getConfig()
    );

    // 分配RenderScript需要的内存块
    Allocation inputAlloc = Allocation.createFromBitmap(rs, originalBitmap);
    Allocation outputAlloc = Allocation.createFromBitmap(rs, outputBitmap);

    // 初始化脚本并设置参数
    ScriptC_ColorSplash script = new ScriptC_ColorSplash(rs);
    script.set_inputImage(inputAlloc);
    script.set_outputImage(outputAlloc);
    
    // 将目标颜色转为0-1的浮点数组
    float r = Color.red(targetColor) / 255.0f;
    float g = Color.green(targetColor) / 255.0f;
    float b = Color.blue(targetColor) / 255.0f;
    script.set_targetColor(new float[]{r, g, b});
    script.set_tolerance(0.3f); // 可根据需求调整容差

    // 执行像素处理
    script.forEach_root(inputAlloc, outputAlloc);
    // 将处理后的结果复制到输出Bitmap
    outputAlloc.copyTo(outputBitmap);

    // 释放资源,避免内存泄漏
    inputAlloc.destroy();
    outputAlloc.destroy();
    script.destroy();

    return outputBitmap;
}

二、简化开发:用Glide自定义Transformation

如果你的场景本来就用Glide加载图片,那直接自定义一个Transformation是最省心的选择——Glide会自动处理线程调度、缓存和Bitmap资源管理,不用自己操心。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import com.bumptech.glide.load.resource.bitmap.BitmapResource;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
import com.bumptech.glide.load.Transformation;
import com.bumptech.glide.load.engine.Resource;

public class ColorSplashTransformation implements Transformation<Bitmap> {
    private final int targetColor;
    private final float tolerance;

    public ColorSplashTransformation(int targetColor, float tolerance) {
        this.targetColor = targetColor;
        this.tolerance = tolerance;
    }

    @Override
    public Resource<Bitmap> transform(Context context, Resource<Bitmap> resource, int outWidth, int outHeight) {
        Bitmap source = resource.get();
        // 先获取Glide的Bitmap池,复用Bitmap减少内存开销
        Bitmap result = TransformationUtils.getBitmapDrawable(context.getResources(), source).getBitmap();
        
        Canvas canvas = new Canvas(result);
        Paint grayPaint = new Paint();
        
        // 第一步:给整张图去饱和化(转灰度)
        ColorMatrix grayMatrix = new ColorMatrix();
        grayMatrix.setSaturation(0);
        grayPaint.setColorFilter(new ColorMatrixColorFilter(grayMatrix));
        canvas.drawBitmap(source, 0, 0, grayPaint);

        // 第二步:用PorterDuff模式叠加原颜色的目标区域
        Paint colorPaint = new Paint();
        colorPaint.setColorFilter(new PorterDuffColorFilter(targetColor, PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(source, 0, 0, colorPaint);

        return BitmapResource.obtain(result, com.bumptech.glide.Glide.get(context).getBitmapPool());
    }

    @Override
    public String getId() {
        // 唯一标识,用于Glide的缓存键
        return "ColorSplash:" + targetColor + ":" + tolerance;
    }
}

使用时直接在Glide加载链中添加:

Glide.with(context)
    .load(imageUrl)
    .transform(new ColorSplashTransformation(Color.RED, 0.3f))
    .into(imageView);

三、应急优化:改进你的逐像素代码

如果暂时不想引入新框架,也可以优化你的原有代码,提升不少速度:

  • 一次性获取所有像素数组,避免频繁IO
  • 用多线程并行处理
  • 用整数运算代替浮点数,避免开根号等耗时操作
import android.graphics.Bitmap;
import android.graphics.Color;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public Bitmap applyColorSplashOptimized(Bitmap original, int targetColor, int tolerance) {
    int width = original.getWidth();
    int height = original.getHeight();
    Bitmap result = Bitmap.createBitmap(width, height, original.getConfig());

    int[] pixels = new int[width * height];
    original.getPixels(pixels, 0, width, 0, 0, width, height);

    // 提前计算目标颜色的RGB值和容差平方(避免循环中重复计算)
    int targetR = Color.red(targetColor);
    int targetG = Color.green(targetColor);
    int targetB = Color.blue(targetColor);
    int toleranceSq = tolerance * tolerance; // 用平方代替开根号,提升速度

    // 用ForkJoinPool并行处理像素数组
    ForkJoinPool.commonPool().invoke(new RecursiveAction() {
        @Override
        protected void compute() {
            for (int i = 0; i < pixels.length; i++) {
                int pixel = pixels[i];
                int r = Color.red(pixel);
                int g = Color.green(pixel);
                int b = Color.blue(pixel);

                // 计算颜色距离的平方
                int dr = r - targetR;
                int dg = g - targetG;
                int db = b - targetB;
                int distanceSq = dr*dr + dg*dg + db*db;

                if (distanceSq > toleranceSq) {
                    // 转为灰度
                    int gray = (int)(0.299*r + 0.587*g + 0.114*b);
                    pixels[i] = Color.argb(Color.alpha(pixel), gray, gray, gray);
                }
            }
        }
    });

    result.setPixels(pixels, 0, width, 0, 0, width, height);
    return result;
}

内容的提问来源于stack exchange,提问作者filipst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:54:46