java - 如何为 png 图像设置ColorFilter

标签 java android android-studio

我已经在使用 setColorFilter() 为这些线条添加颜色。这条线的原始颜色是黄色。我使用红色或绿色取决于某些陈述。

这是我到目前为止所拥有的: 有人帮我做到了这一点: How to set filter property in ImageView Android studio

enter image description here

但现在我需要在线下添加颜色......就像这样:

enter image description here

sparkline.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
sparkline.setImageResource(R.drawable.btc_spike);

<androidx.constraintlayout.utils.widget.ImageFilterView
                android:layout_width="80dp"
                android:layout_height="50dp"
                android:id="@+id/sparkline"
                android:layout_marginRight="2dp"
                app:saturation="80"
                app:brightness="0.85"
                app:crossfade="0.0"
                app:warmth="10"
                android:src="@drawable/btc_spike" />

我也找到了这个页面,但不确定它是否要我在这个页面上添加另一个图像或其他东西......

https://developer.android.com/reference/android/graphics/PorterDuff.Mode#MULTIPLY

最佳答案

要使用 png 图像在线条下添加颜色,您可以执行如下操作:

  1. 以位图形式检索 png 图像(源位图)。
  2. 将源位图复制到临时位图(输出位图)中。
  3. 迭代输出位图的每个 x,y 像素并找到线像素(非透明像素)。其余透明像素将其区分为线条区域上方和线条区域下方的透明像素。
  4. 最后将红色/绿色设置为线条像素,将红色/绿色灯光颜色设置为线条下方的透明像素。

这是一个执行上述步骤的辅助函数:

public static Bitmap getShadowLineBitmap(@NonNull Bitmap srcBitmap, @ColorInt int lineColor, @ColorInt int shadowUnderLineColor){

        //copy the srcBitmap to the outBitmap
        Bitmap outBitmap = srcBitmap.copy(srcBitmap.getConfig(), true);
        try
        {
            //iterate each x,y pixel
            for (int x = 0; x < outBitmap.getWidth(); x++) {
                boolean foundLinePx = false;
                for (int y = 0; y < outBitmap.getHeight(); y++) {

                    //get the current RGBA x,y pixel
                    int rgba = outBitmap.getPixel(x, y);

                    //if its a Transparent pixel it means that is a pixel above or below the line
                    //so draw the pixels above the line to Transparent and draw the pixels below the line to a red/green light color
                    if (rgba == Color.TRANSPARENT) {
                        if(foundLinePx)
                            outBitmap.setPixel(x, y, shadowUnderLineColor);
                        else
                            outBitmap.setPixel(x, y, rgba);
                    }
                    //if its a Non-Transparent pixel it means that is a line pixel so draw each line pixel to red/green
                    else {
                        outBitmap.setPixel(x, y, lineColor);
                        foundLinePx = true;
                    }
                }
            }
        }catch (Exception e){

        }
        return outBitmap;
    }

可以像下面这样使用:

//get the src Bitmap from Resources (Bitmap can be retrieved also from Glide/Picasso)
Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.sparkline); 

//Draw the Bitmap with Green Line Color and Green Shadow Light Color
imageView.setImageBitmap(getShadowLineBitmap(srcBitmap, Color.argb(255, 25, 189, 119), Color.argb(255, 231, 250, 243)));

//Draw the Bitmap with Red Line Color and Red Shadow Light Color
imageView.setImageBitmap(getShadowLineBitmap(srcBitmap, Color.argb(255, 228, 112, 117), Color.argb(255, 252, 227, 228)));

结果:

green red

在 RecyclerView 中使用 Glide 加载位图

我已经使用 RecyclerView 测试了来自您的域的一些图形图像链接(例如: https://s3.coinmarketcap.com/generated/sparklines/web/7d/usd/1.png ),即使我向上/向下滚动单元格,它也能按预期工作。

void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position)添加以下代码行以使用 Glide 加载位图(Glide 版本:com.github.bumptech.glide:glide:4.12.0):

Glide.with(itemView.getContext().getApplicationContext())
        .asBitmap()
        .placeholder(R.drawable.placeholer)
        .error(R.drawable.error)
        .diskCacheStrategy(DiskCacheStrategy.NONE)
        .override(164, 48) //we know the web image size (164x48)
        .load(url)
        .into(new CustomTarget<Bitmap>(164, 48)
        {
            @Override
            public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
               
                        //set resource to ImageBitmap
                        imageView.setImageBitmap(resource);

                        //set Green Color filter to line and Green Shadow line colour in AsyncTask
                        if(isGreen) {
                            imageView.setColorFilter(Color.argb(255, 25, 189, 119), PorterDuff.Mode.MULTIPLY);
                            new DrawBitmapShadowAsyncTask(imageView,
                                    Color.argb(255, 25, 189, 119),
                                    Color.argb(255, 231, 250, 243))
                                    .execute(resource);
                        }
                        //set Red Color filter to line and Red Shadow line colour in AsyncTask
                        else{
                            imageView.setColorFilter(Color.argb(255, 228, 112, 117), PorterDuff.Mode.MULTIPLY);
                            new DrawBitmapShadowAsyncTask(imageView,
                                    Color.argb(255, 228, 112, 117),
                                    Color.argb(255, 252, 227, 228))
                                    .execute(resource);
                        }
            }

            @Override
            public void onLoadStarted(@Nullable Drawable placeholder) {
                if(placeholder!=null){
                    imageView.setImageDrawable(placeholder);
                }
                else {
                    imageView.setImageBitmap(BitmapFactory.decodeResource(itemView.getResources(), R.drawable.placeholer));
                }
            }

            @Override
            public void onLoadFailed(@Nullable Drawable errorDrawable) {
                if(errorDrawable!=null){
                    imageView.setImageDrawable(errorDrawable);
                }
                else {
                    imageView.setImageBitmap(BitmapFactory.decodeResource(itemView.getResources(), R.drawable.error));
                }
            }

            @Override
            public void onLoadCleared(@Nullable Drawable placeholder) {

            }
        });

从上面:

  1. void onLoadStarted(@Nullable Drawable placeholder)设置加载开始时可绘制的 ImageView 占位符。
  2. void onLoadFailed(@Nullable Drawable errorDrawable)设置加载失败时 ImageView 错误可绘制。
  3. void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition)当资源加载完成并且位图可供使用时调用。在此回调中,我们使用 AsyncTask 中之前的辅助函数在图形线下方使用浅色进行绘制。

下面是DrawBitmapShadowAsyncTask RecyclerView Adapter 中使用的 AsyncTask 私有(private)静态类 Glide onResourceReady在背景线程中的线条下方绘制阴影颜色:

    /**
     * Draws Shadow Color under the Graph line asynchronously
     */
    private static class DrawBitmapShadowAsyncTask extends AsyncTask<Bitmap, Void, Bitmap> {

        private WeakReference<ImageView> imageView = null;
        private @ColorInt int lineColor;
        private @ColorInt int shadowUnderLineColor;

        private DrawBitmapShadowAsyncTask(ImageView imageView, @ColorInt int lineColor, @ColorInt int shadowUnderLineColor){
            this.imageView = new WeakReference<>(imageView);
            this.lineColor = lineColor;
            this.shadowUnderLineColor = shadowUnderLineColor;
        }

        /**
         * Colorize the srcBitmap below the graph line in a Background Thread
         * @param bitmaps bitmaps[0] (srcBitmap)
         * @return the output bitmap
         */
        @Override
        protected Bitmap doInBackground(Bitmap... bitmaps) {
            return getShadowLineBitmap(bitmaps[0], lineColor, shadowUnderLineColor);
        }

        /**
         * Set the output Bitmap to imageView in Main Thread
         * @param bitmap the output bitmap
         */
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if(imageView!=null && imageView.get()!=null){
                imageView.get().clearColorFilter();
                imageView.get().setImageBitmap(bitmap);
            }
        }

        /**
         * Helper method to draw shadow color under the line
         * @param srcBitmap The source Bitmap
         * @param lineColor The color line
         * @param shadowUnderLineColor The shadow color under the line
         * @return Bitmap The output Bitmap
         */
        private Bitmap getShadowLineBitmap(@NonNull Bitmap srcBitmap, @ColorInt int lineColor, @ColorInt int shadowUnderLineColor){

            //copy the srcBitmap to the outBitmap
            Bitmap outBitmap = srcBitmap.copy(srcBitmap.getConfig(), true);
            try
            {
                //iterate each x,y pixel
                for (int x = 0; x < outBitmap.getWidth(); x++) {
                    boolean foundLinePx = false;
                    for (int y = 0; y < outBitmap.getHeight(); y++) {

                        //get the current RGBA x,y pixel
                        int rgba = outBitmap.getPixel(x, y);

                        //if its a Transparent pixel it means that is a pixel above or below the line
                        //so draw the pixels above the line to Transparent and draw the pixels below the line to a red/green light color
                        if (rgba == Color.TRANSPARENT) {
                            if(foundLinePx)
                                outBitmap.setPixel(x, y, shadowUnderLineColor);
                            else
                                outBitmap.setPixel(x, y, rgba);
                        }
                        //if its a Non-Transparent pixel it means that is a line pixel so draw each line pixel to red/green
                        else {
                            outBitmap.setPixel(x, y, lineColor);
                            foundLinePx = true;
                        }
                    }
                }
            }catch (Exception e){

            }
            return outBitmap;
        }
    }

Recycler查看结果:

recyclerview_red recyclerview_green

关于java - 如何为 png 图像设置ColorFilter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68881601/

相关文章:

java - IntelliJ Idea Ultimate 在创建新的 Spring 项目时下载旧版本的 Spring 文件

java - 通过远程接口(interface)将 EJB 注入(inject) servlet

android - 错误 : Program type already present: android. support.v4.os.ResultReceiver$MyResultReceiver

java - startActivityForResult 返回错误的 Activity

java - Intellij Plugin开发之如何获取Android-Studio模块名称

java - "Cannot find symbol variable BuildConfig"有多个源文件夹

java - HSDC数据库连接

java - 从 .jar 文件复制文件夹

android - Cordova 3.4 - 检测键盘事件

android - 关闭 Android Studios 糟糕的风格建议?