OK, color me confused. Why are you expecting to do this with PorterDuff?

PorterDuff works on images (or colors) with alpha to combine them. The alpha 
controls how they combine.

I don't see any way to get information from the color channels to the alpha 
channel via PorterDuff. The output alpha channel is always a function of the 
source and destination alpha channels -- and not of the color channels.

Even if there were modes that derived alpha from color -- what you're 
looking to do is very different than the sort of operations involved in 
PorterDuff. Except for clamping the result between full-on and full-off 
(however you choose to represent those values), PorterDuff operations are 
linear.

Have you considered painting using AvoidXfermode? I.e. construct your paint 
with an Xfermode of new AvoidXfermode(<your transparent color>, 0, 
AvoidXfermode.Mode.TARGET).

Here's a twisted little app that demonstrates, It constructs two changing 
bitmaps -- a background gradient and a foreground. It alternates between two 
modes -- Opaque and Transparent. In Transparent mode, the Color.MAGENTA 
circles are replaced using AvoidXfermode with transparent regions, showing 
the background. It also replaces a square region with half-transparency of 
the same color via the same general technique.

Please view responsibly.

package com.example.transparent;

import java.util.Random;

import android.app.Activity;
import android.graphics.AvoidXfermode;
import android.graphics.AvoidXfermode.Mode;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.graphics.Xfermode;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.widget.ImageView;
import android.widget.TextView;

public class Transparent extends Activity {
        private final Random m_random = new Random();
        int m_bg_color_1 = Color.RED;
        int m_bg_color_1_delta = 0;
        int m_bg_color_2 = Color.BLUE;
        int m_bg_color_2_delta = 0;
        
        int m_state = 0;
        final Bitmap m_foreground = Bitmap.createBitmap(300, 300, 
Config.ARGB_8888);
        final Bitmap m_background = Bitmap.createBitmap(300, 300, 
Config.ARGB_8888);
        
        private int clamp(int c) {
                return Math.max(0, Math.min(255, c));
        }
        
        private int add(int c, int delta) {
                if (delta > 128) {
                        return clamp(c - (256 - delta));
                } else {
                        return clamp(c + delta);
                }
        }
        
        private int nextColor(int c, int delta) {
                return Color.rgb(
                                add(Color.red(c), Color.red(delta)),
                                add(Color.green(c), Color.green(delta)),
                                add(Color.blue(c), Color.blue(delta))
                                );
        }
        
        private final int MAX_VELOCITY = 5;
        
        private int newDeltaComponent(int c) {
                if (c == 0) return m_random.nextInt(MAX_VELOCITY-1) + 1;
                if (c == 255) return 255 - m_random.nextInt(MAX_VELOCITY);
                return c;
        }
        
        private int newDelta(int c) {
                return Color.rgb(newDeltaComponent(
                                Color.red(c)),
                                newDeltaComponent(Color.green(c)),
                                newDeltaComponent(Color.blue(c)));
        }
        
        private boolean atLimit(int c) {
                return Color.red(c) == 0 || Color.red(c) == 255 || 
Color.green(c) == 0 || Color.green(c) == 255 || Color.blue(c) == 0 || 
Color.blue(c) == 255;
        }
        
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final ImageView iv = (ImageView)findViewById(R.id.image);
        final Handler h = new Handler();
        Runnable animate = new Runnable() {
                        @Override
                        public void run() {
                                Bitmap background = createBackground();
                                iv.setBackgroundDrawable(new 
BitmapDrawable(background));
                                boolean transparent = ((m_state / 50) & 1) 
== 1;
                                Bitmap bm = createForeground(transparent);
                                iv.setImageBitmap(bm);
                                m_state++;
                                m_bg_color_1 = nextColor(m_bg_color_1, 
m_bg_color_1_delta);
                                m_bg_color_2 = nextColor(m_bg_color_2, 
m_bg_color_2_delta);
                                if (atLimit(m_bg_color_1)) {
                                        m_bg_color_1_delta = 
newDelta(m_bg_color_1);
                                }
                                if (atLimit(m_bg_color_2)) {
                                        m_bg_color_2_delta = 
newDelta(m_bg_color_2);
                                }
                                h.postDelayed(this, 100);                   
            
                        }
                };
                animate.run();
    }
    
    private int p(int p) {
        return (m_state + p) % 10 - 5;
    }
    
    private int avg(int c1, int c2) {
        return Color.argb(
                        (Color.alpha(c1) + Color.alpha(c2)) / 2,
                        (Color.red(c1) + Color.red(c2)) / 2, 
                        (Color.green(c1) + Color.green(c2)) / 2,
                        (Color.blue(c1) + Color.blue(c2)) / 2);
    }

        private Bitmap createForeground(boolean transparent) {
        Canvas c = new Canvas(m_foreground);
        Paint clear = new Paint();
        clear.setColor(Color.TRANSPARENT);
        clear.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
        c.drawRect(new Rect(0, 0, 300, 300), clear);
        Paint outer = new Paint();
        outer.setColor(avg(m_bg_color_1, m_bg_color_2));
        c.drawRoundRect(new RectF(10 + p(8), 10 + p(2), 290 + p(7), 290 + 
p(4)), 10 + p(0), 10 + p(5), outer);
        Paint magenta = new Paint();
        magenta.setColor(Color.MAGENTA);
        Paint blue = new Paint();
        blue.setColor(Color.BLUE);
        c.drawCircle(150 + p(0), 150 + p(5), 105, blue);
        c.drawCircle(150 + p(2), 150 + p(7), 90, magenta);
        c.drawCircle(150 + p(3), 150 + p(1), 75, blue);
        c.drawCircle(150 + p(6), 150 + p(4), 60, magenta);
        c.drawCircle(150 + p(8), 150 + p(5), 45, blue);
        c.drawCircle(150 + p(7), 150 + p(2), 30, magenta);
        c.drawCircle(150 + p(5), 150 + p(3), 15, blue);
        // OK, now we have a green rectangle, with hypercaffeinated nested 
blue and magenta circles inside that.
        TextView msg = (TextView)findViewById(R.id.mode);
        if (transparent) {
                // Let's replace the Magenta with Transparent.
                Paint t = new Paint();
                t.setColor(Color.TRANSPARENT);
                Xfermode mode = new AvoidXfermode(Color.MAGENTA, 0, 
Mode.TARGET);
                t.setXfermode(mode);
                c.drawRect(new Rect(20, 20, 280, 280), t);
                Paint t2 = new Paint();
                // And set a portion of the outer rectangle to 
half-transparency.
                Xfermode mode2 = new AvoidXfermode(outer.getColor(), 0, 
Mode.TARGET);
                t2.setXfermode(mode2);
                t2.setColor(outer.getColor());
                t2.setAlpha(128);
                c.drawRect(new Rect(40, 40, 260, 260), t2);
                msg.setText(R.string.transparent);
        } else {
                msg.setText(R.string.opaque);
        }
                return m_foreground;
        }

        /**
         * @return a nice background to make transparency obvious.
         */
        private Bitmap createBackground() {
                float x0 = (float)(m_state % 300);
                float y0 = (float)((m_state + 150) % 300);
                Shader grad = new LinearGradient(x0, y0, 300f - x0, 300f - 
y0, m_bg_color_1, m_bg_color_2, TileMode.MIRROR);
        Canvas bc = new Canvas(m_background);
        Paint bcp = new Paint();
        bcp.setShader(grad);
        bc.drawRect(new Rect(0, 0, 300, 300), bcp);
                return m_background;
        }
}

-- res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
android:id="@+id/mode"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/opaque"
    />
<ImageView android:id="@+id/image" android:layout_width="fill_parent" 
android:layout_height="fill_parent"></ImageView>
</LinearLayout>

-- res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">Transparent</string>
<string name="opaque">Opaque!</string>
<string name="transparent">Transparent!</string>
</resources>

-- 
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en

Reply via email to