How to set combined color for overlapped area of two different color objects?

RajaReddy PolamReddy picture RajaReddy PolamReddy · Jul 3, 2012 · Viewed 8.2k times · Source

I am creating different custom views with two different colors. According to my app features user will drag those objects on the screen, when dragging objects will overlap each other. I want to differentiated the overlapped area, how to set the combined color for overlapped Area. Look at the below image. Here I am using canvas for creating those custom views two circles are two different views.

enter image description here

EDIT: If I use opacity 128 I am able to see the background color, but I want the combination color of overlapped objects colors.

Answer

Gunnar Karlsson picture Gunnar Karlsson · Jul 6, 2012

The Color mixing you are looking for is sometimes called Intuitive Color Mixing, or the RYB Color System:

RYB:

enter image description here CC license

A quote from this paper by Nathan Gossett and Baoquan Chen on algorithms for intuitive color mixing summarizes how the intuitive color system works:

"In this model, Red, Yellow and Blue are used as pure primary colors. Red and Yellow mix to form Orange, Yellow and Blue mix to form Green, and Blue and Red mix to form Purple [...]. These are the colors an untrained viewer would expect to obtain using children's paint [...]. In addition, many people do not think of White as the mixture of all colors, but instead as the absence of color (a blank canvas). A more common assumption would be that mixing many colors together would result in a muddy dark brown color."

RYB is not implemented in Android's blend modes and can't really be simulated by mixing alpha/different blend modes.

Most computer graphics applications make use of the RGB or CMYK color spaces:

CMYK:

enter image description hereCC license

CMY is based on subtractive color. Subtractive color mixing means that, starting with white, as we add color, the result gets darker. CMYK is used for mixing colors in images intended for printing in e.g. Photoshop and Illustrator.

RGB:

enter image description here CC license

RGB is based on Additive Color. The colors on a computer screen are created with light using the additive color method. Additive color mixing begins with black and as more color is added, the result gets lighter and ends in white.

This site discusses CMYK and RGB in more detail.

In neither RGB nor CMYK does mixing blue and yellow produce green, or generally speaking, intuitive color mixes. To implement a RYB color system on Android would be quite involved. The paper by Nathan Gossett and Baoquan Chen quoted above proposes a solution with an algorithm implemented in C at the very end of the paper. This algorithm could be implemented in a custom blend on Android. Drawable.setColorFilter() uses PorterDuffColorfilter which extends ColorFilter. Subclassing ColorFilter as discussed in this SO question would have to be done in native code using the NDK.

CMYK Color Mixing Workaround

In case you are interested in using a CMYK color mixing as a workaround, I've included a basic example of how it can be done below. In this example, A cyan-color circle and a yellow-color circle will be blended to produce a green intersection.

Starting with these .png image files created in Adobe Illustrator:

enter image description here

enter image description here

with hex color value 0x00ffff (cyan) and 0xffff00 (yellow).

Add them to your drawable folder with names cyancircle.png and yellowcircle.png.

Configure your main.xml layout as follows:

<?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>

Create your Activity:

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);
    }
}

Output:

enter image description here

The limitation to this method is that the top shape's alpha has to be set to 50% (the "88" in "0x88ffff00"). For yellow this works reasonable well but for other colors the alpha effect may not be acceptable (the color may appear to be another color, e.g. red becomes pink with low alpha values on white background). Which blend mode is ultimately acceptable for you depends on the set of colors you are going to use and will take some experimentation. Also note the background color may affect the circles' colors in blend mode. In this example the background is set to white.