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