如何为两个不同颜色对象的重叠区域设置组合颜色?

Raj*_*ddy 27 android drawing

我用两种不同的颜色创建不同的自定义视图.根据我的应用功能,当拖动对象相互重叠时,用户将在屏幕上拖动这些对象.我想区分重叠区域,如何设置重叠区域的组合颜色.请看下面的图片.这里我使用canvas来创建那些自定义视图,两个圆圈是两个不同的视图.

在此输入图像描述

编辑: 如果我使用不透明度128我能够看到背景颜色,但我想要重叠对象颜色的组合颜色.

Gun*_*son 21

您正在寻找的颜色混合有时被称为直观颜色混合,或RYB颜色系统:

RYB:

在此输入图像描述 CC许可证

从A引用论文由Nathan戈西特和陈宝权的算法直观的彩色混合总结了直观的彩色系统是如何工作的:

"在这个模型中,红色,黄色和蓝色被用作纯原色.红色和黄色混合形成橙色,黄色和蓝色混合形成绿色,蓝色和红色混合形成紫色[...].这些是未经训练的观察者希望使用儿童的颜料获得颜色[...].此外,许多人不认为白色是所有颜色的混合物,而是因为缺少颜色(空白画布).更常见假设将多种颜色混合在一起会产生泥泞的深棕色."

RYB未在Android的混合模式中实现,并且无法通过混合alpha /不同混合模式来真正模拟.

大多数计算机图形应用程序使用RGBCMYK颜色空间:

CMYK:

在此输入图像描述CC许可证

CMY基于减色.减色混合意味着,从白色开始,当我们添加颜色时,结果会变暗.CMYK用于混合用于打印的图像中的颜色,例如Photoshop和Illustrator.

RGB:

在此输入图像描述 CC许可证

RGB基于添加颜色.使用加色方法用光创建计算机屏幕上的颜色.添加剂颜色混合从黑色开始,并且随着更多颜色的添加,结果变得更轻并且以白色结束.

网站更详细地讨论了CMYK和RGB.

在RGB和CMYK中,混合蓝色和黄色都会产生绿色,或者一般来说,直观的颜色混合.在Android上实现RYB颜色系统将非常复杂.上面引用的Nathan Gossett和Baoquan Chen的论文提出了一种解决方案,其最后用C语言实现了算法.此算法可以在Android上的自定义混合中实现.扩展的Drawable.setColorFilter()用途. SO问题中讨论的子类必须使用NDK在本机代码中完成.PorterDuffColorfilterColorFilterColorFilter

CMYK颜色混合解决方法

如果您有兴趣使用CMYK颜色混合作为解决方法,我已经包含了一个如何在下面完成它的基本示例.在该示例中,将混合青色圆和黄色圆以产生绿色交叉.

从在Adobe Illustrator中创建的这些.png图像文件开始:

在此输入图像描述

在此输入图像描述

十六进制颜色值0x00ffff(青色)和0xffff00(黄色).

将它们添加到名为cyancircle.png和yellowcircle.png的drawable文件夹中.

配置main.xml布局如下:

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" 
    android:background="#ffffff"
    android:padding="30dp">

<ImageView
    android:id="@+id/bluecircle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/cyancircle">
</ImageView>

<ImageView
    android:id="@+id/yellowcircle"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/yellowcircle" 
    android:layout_marginTop="30dp">
</ImageView>     
</RelativeLayout>
Run Code Online (Sandbox Code Playgroud)

创建您的活动:

import android.app.Activity;
import android.graphics.PorterDuff;
import android.os.Bundle;
import android.widget.ImageView;

public class PorterDuffTestActivity extends Activity {
/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ImageView yellowCircle = (ImageView)findViewById(R.id.yellowcircle);

        yellowCircle.getDrawable().setColorFilter(0x88ffff00, PorterDuff.Mode.MULTIPLY);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

在此输入图像描述

此方法的限制是顶部形状的alpha必须设置为50%("0x88ffff00"中的"88").对于黄色,这可以很好地工作但是对于其他颜色,α效果可能是不可接受的(颜色可能看起来是另一种颜色,例如,红色变成粉红色,白色背景上的低α值).哪种混合模式最终可以接受取决于您将要使用的颜色集,并将进行一些实验.另请注意,背景颜色可能会影响混合模式下的圆圈颜色.在此示例中,背景设置为白色.


Sud*_*lan 5

我为6个对象做了另一个例子.

在此输入图像描述

关键点:

  1. onDraw方法不会覆盖对象视图,后台也会设置为透明

    setBackgroundColor(Color.TRANSPARENT);

  2. 但是,onDraw方法将被重命名为onDrawEx将从Overlay View调用.

    public void onDrawEx(Canvas canvas){

  3. 叠加视图将传递自定义画布以进行绘制.在传递给对象视图之前,它将做必要的翻译.

        mOverlayView = new View(this){
        @Override
        protected void onDraw(Canvas canvas) {
            Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888);
            Canvas canvasBitmap = new Canvas(bitmap);
            ViewGroup viewGroup = (ViewGroup)getParent();
            for(int i = 0 ; i < viewGroup.getChildCount()-1;i++){
                ObjectView objectView = (ObjectView) viewGroup.getChildAt(i);
                canvasBitmap.save();
                canvasBitmap.translate(objectView.getTranslationX(), objectView.getTranslationY());
                objectView.onDrawEx(canvasBitmap);
                canvasBitmap.restore();
            }
            canvas.drawBitmap(bitmap, 0, 0, new Paint());
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)
  4. 使用mPaint.setXfermode(new PorterDuffXfermode(Mode.ADD)); 添加颜色.但是所有对象都应该使用像0xFF000030,0xFF0000C0,0xFF003000,0xFF00C000,0xFF300000,0xC00000这样的颜色,然后只对所有可能的重叠我们可以得到不同的颜色.这取决于你的最大物体数量.

        int k = 0 ;
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x000030<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x003000<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    for(int i = 0 ; i < 2;i++,k++){
        int color = 0xFF000000|(0x300000<<i*2);
        frameLayout.addView(new ObjectView(this,color,k*50,k*50,k), new FrameLayout.LayoutParams(50, 50));
    }
    
    Run Code Online (Sandbox Code Playgroud)

这里我修改为支持版本8

使用

mPaint.setXfermode(new PixelXorXfermode(0x00000000));
Run Code Online (Sandbox Code Playgroud)

对于

mPaint.setXfermode(new PorterDuffXfermode(Mode.ADD));
Run Code Online (Sandbox Code Playgroud)

我使用布局参数进行翻译.


Cat*_*ord 3

我能想到的最简单的解决方案是通过在代码或 xml 中将每个不透明度设置为 0.5 来简单地使用 alpha 通道。然后,当它们重叠时,颜色应该会相互褪色。但这确实意味着非重叠部分中的颜色会有点褪色,并且根据形状后面的背景,让它们完全透明可能看起来不太好。