Skip to content

Instantly share code, notes, and snippets.

@niusounds
Last active August 29, 2015 13:57
Show Gist options
  • Save niusounds/9615694 to your computer and use it in GitHub Desktop.
Save niusounds/9615694 to your computer and use it in GitHub Desktop.
https://gist.github.com/niusounds/7905659 の後にまた作った。複数レイヤーを重ねて表示するView。Layerごとに色相・明るさ・コントラスト・透明度の指定が可能。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class LayeredImageView extends View {
private final List<Layer> layers = new ArrayList<Layer>();
public LayeredImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public LayeredImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LayeredImageView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawLayers(canvas, true);
}
public void drawLayers(Canvas canvas, boolean toScreen) {
for (Layer l : layers) {
drawLayer(canvas, l, toScreen);
}
}
protected void drawLayer(Canvas canvas, Layer layer, boolean toScreen) {
canvas.drawBitmap(layer.bitmap(), layer.matrix, layer.paint);
}
public boolean addLayer(Layer layer) {
return layers.add(layer);
}
public Layer setLayer(int index, Layer layer) {
return layers.set(index, layer);
}
public boolean removeLayer(Layer layer) {
return layers.remove(layer);
}
public List<Layer> getLayers() {
return Collections.unmodifiableList(layers);
}
public static class Layer {
private final Matrix matrix = new Matrix();
public final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
private Bitmap original;
public boolean locked = false;
public RectF bounds = new RectF();
private RectF transformed = new RectF();
private float hue = 0.0f;
private float brightness = 0.0f;
private float contrast = 1.0f;
private boolean flipped;
private float scaleX = 1.0f;
private float scaleY = 1.0f;
private float translateX = 0;
private float translateY = 0;
private float rotate = 0;
public Layer(Bitmap bmp) {
bitmap(bmp);
}
public void bitmap(Bitmap bmp) {
this.original = bmp;
bounds.set(0, 0, bmp.getWidth(), bmp.getHeight());
resetAdjustParameter();
}
public Bitmap bitmap() {
return original;
}
public RectF getTransformedBounds() {
matrix.mapRect(transformed, bounds);
return transformed;
}
private void updateColorFilter() {
ColorMatrix m = new ColorMatrix(); // 計算途中に使う一時的な行列
ColorMatrix composite = new ColorMatrix(); //
// TODO 色相(仮)
float r = (float) Math.max(Math.min(1.5 * Math.cos(hue) + 0.5, 1), 0);
float g = (float) Math.max(Math.min(1.5 * Math.cos(hue + 2.0 * Math.PI / 3.0) + 0.5, 1), 0);
float b = (float) Math.max(Math.min(1.5 * Math.cos(hue + 2.0 * Math.PI / 3.0 * 2.0) + 0.5, 1), 0);
float sum = r + g + b;
r /= sum;
g /= sum;
b /= sum;
m.set(new float[] {
r, g, b, 0, 0,
b, r, g, 0, 0,
g, b, r, 0, 0,
0, 0, 0, 1, 0
});
composite.postConcat(m);
// 明るさ(res = orig + val)
m.set(new float[] {
1, 0, 0, 0, brightness * 255,
0, 1, 0, 0, brightness * 255,
0, 0, 1, 0, brightness * 255,
0, 0, 0, 1, 0
});
composite.postConcat(m);
// コントラスト(res = (orig - 0.5) * val + 0.5)
m.set(new float[] {
1, 0, 0, 0, -128,
0, 1, 0, 0, -128,
0, 0, 1, 0, -128,
0, 0, 0, 1, 0
});
composite.postConcat(m);
m.setScale(contrast, contrast, contrast, 1.0f);
composite.postConcat(m);
m.set(new float[] {
1, 0, 0, 0, 128,
0, 1, 0, 0, 128,
0, 0, 1, 0, 128,
0, 0, 0, 1, 0
});
composite.postConcat(m);
paint.setColorFilter(new ColorMatrixColorFilter(composite));
}
public Layer hue(float hue) {
this.hue = hue;
updateColorFilter();
return this;
}
public Layer brightness(float brightness) {
this.brightness = brightness;
updateColorFilter();
return this;
}
public Layer contrast(float contrast) {
this.contrast = contrast;
updateColorFilter();
return this;
}
public Layer opacity(int value) {
paint.setAlpha(value);
return this;
}
public Layer opacity(float value) {
paint.setAlpha((int) (value * 255));
return this;
}
/**
* 画像調整値を初期値に戻す
*/
public void resetAdjustParameter() {
hue = 0.0f;
brightness = 0.0f;
contrast = 1.0f;
updateColorFilter();
paint.setAlpha(255);
}
public float hue() {
return hue;
}
public float brightness() {
return brightness;
}
public float contrast() {
return contrast;
}
public float opacity() {
return (float) paint.getAlpha() / 255.0f;
}
public float[] copyMatrixValues() {
float[] values = new float[9];
matrix.getValues(values);
return values;
}
public void setMatrixValues(float[] values) {
matrix.setValues(values);
}
public void flip() {
flipped = !flipped;
RectF rect = getTransformedBounds();
matrix.postScale(-1, 1, rect.centerX(), rect.centerY());
}
public boolean isFlipped() {
return flipped;
}
public void scale(float x, float y) {
matrix.postScale(x, y);
scaleX *= x;
scaleY *= y;
}
public void scale(float x, float y, float px, float py) {
matrix.postScale(x, y, px, py);
scaleX *= x;
scaleY *= y;
}
public float scaleX() {
return scaleX;
}
public float scaleY() {
return scaleY;
}
public void translate(float x, float y) {
matrix.postTranslate(x, y);
translateX += x;
translateY += y;
}
public float translateX() {
return translateX;
}
public float translateY() {
return translateY;
}
public void rotate(float degrees) {
matrix.postRotate(degrees);
rotate += degrees;
}
public void rotate(float degrees, float px, float py) {
matrix.postRotate(degrees, px, py);
rotate += degrees;
}
public float rotate() {
return rotate;
}
public Matrix matrix() {
return matrix;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment