1860af325f2030a03c526e8551a85230d17df7b15nicolasroard/*
2860af325f2030a03c526e8551a85230d17df7b15nicolasroard * Copyright (C) 2013 The Android Open Source Project
3860af325f2030a03c526e8551a85230d17df7b15nicolasroard *
4860af325f2030a03c526e8551a85230d17df7b15nicolasroard * Licensed under the Apache License, Version 2.0 (the "License");
5860af325f2030a03c526e8551a85230d17df7b15nicolasroard * you may not use this file except in compliance with the License.
6860af325f2030a03c526e8551a85230d17df7b15nicolasroard * You may obtain a copy of the License at
7860af325f2030a03c526e8551a85230d17df7b15nicolasroard *
8860af325f2030a03c526e8551a85230d17df7b15nicolasroard *      http://www.apache.org/licenses/LICENSE-2.0
9860af325f2030a03c526e8551a85230d17df7b15nicolasroard *
10860af325f2030a03c526e8551a85230d17df7b15nicolasroard * Unless required by applicable law or agreed to in writing, software
11860af325f2030a03c526e8551a85230d17df7b15nicolasroard * distributed under the License is distributed on an "AS IS" BASIS,
12860af325f2030a03c526e8551a85230d17df7b15nicolasroard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13860af325f2030a03c526e8551a85230d17df7b15nicolasroard * See the License for the specific language governing permissions and
14860af325f2030a03c526e8551a85230d17df7b15nicolasroard * limitations under the License.
15860af325f2030a03c526e8551a85230d17df7b15nicolasroard */
16860af325f2030a03c526e8551a85230d17df7b15nicolasroard
17860af325f2030a03c526e8551a85230d17df7b15nicolasroardpackage com.android.gallery3d.filtershow.info;
18860af325f2030a03c526e8551a85230d17df7b15nicolasroard
19860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.content.Context;
20860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.Bitmap;
21860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.Canvas;
22860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.Color;
23860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.Paint;
24860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.Path;
25860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.PorterDuff;
26860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.graphics.PorterDuffXfermode;
27860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.os.AsyncTask;
28860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.util.AttributeSet;
29860af325f2030a03c526e8551a85230d17df7b15nicolasroardimport android.view.View;
30860af325f2030a03c526e8551a85230d17df7b15nicolasroard
31860af325f2030a03c526e8551a85230d17df7b15nicolasroardpublic class HistogramView extends View {
32860af325f2030a03c526e8551a85230d17df7b15nicolasroard
33860af325f2030a03c526e8551a85230d17df7b15nicolasroard    private Bitmap mBitmap;
34b203968cc53015d9c51b790a56cca638be77818dnicolasroard    private Paint mPaint = new Paint();
35b203968cc53015d9c51b790a56cca638be77818dnicolasroard    private int[] redHistogram = new int[256];
36b203968cc53015d9c51b790a56cca638be77818dnicolasroard    private int[] greenHistogram = new int[256];
37b203968cc53015d9c51b790a56cca638be77818dnicolasroard    private int[] blueHistogram = new int[256];
38b203968cc53015d9c51b790a56cca638be77818dnicolasroard    private Path mHistoPath = new Path();
39860af325f2030a03c526e8551a85230d17df7b15nicolasroard
40860af325f2030a03c526e8551a85230d17df7b15nicolasroard    class ComputeHistogramTask extends AsyncTask<Bitmap, Void, int[]> {
41860af325f2030a03c526e8551a85230d17df7b15nicolasroard        @Override
42860af325f2030a03c526e8551a85230d17df7b15nicolasroard        protected int[] doInBackground(Bitmap... params) {
43860af325f2030a03c526e8551a85230d17df7b15nicolasroard            int[] histo = new int[256 * 3];
44860af325f2030a03c526e8551a85230d17df7b15nicolasroard            Bitmap bitmap = params[0];
45860af325f2030a03c526e8551a85230d17df7b15nicolasroard            int w = bitmap.getWidth();
46860af325f2030a03c526e8551a85230d17df7b15nicolasroard            int h = bitmap.getHeight();
47860af325f2030a03c526e8551a85230d17df7b15nicolasroard            int[] pixels = new int[w * h];
48860af325f2030a03c526e8551a85230d17df7b15nicolasroard            bitmap.getPixels(pixels, 0, w, 0, 0, w, h);
49860af325f2030a03c526e8551a85230d17df7b15nicolasroard            for (int i = 0; i < w; i++) {
50860af325f2030a03c526e8551a85230d17df7b15nicolasroard                for (int j = 0; j < h; j++) {
51860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    int index = j * w + i;
52860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    int r = Color.red(pixels[index]);
53860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    int g = Color.green(pixels[index]);
54860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    int b = Color.blue(pixels[index]);
55860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    histo[r]++;
56860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    histo[256 + g]++;
57860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    histo[512 + b]++;
58860af325f2030a03c526e8551a85230d17df7b15nicolasroard                }
59860af325f2030a03c526e8551a85230d17df7b15nicolasroard            }
60860af325f2030a03c526e8551a85230d17df7b15nicolasroard            return histo;
61860af325f2030a03c526e8551a85230d17df7b15nicolasroard        }
62860af325f2030a03c526e8551a85230d17df7b15nicolasroard
63860af325f2030a03c526e8551a85230d17df7b15nicolasroard        @Override
64860af325f2030a03c526e8551a85230d17df7b15nicolasroard        protected void onPostExecute(int[] result) {
65860af325f2030a03c526e8551a85230d17df7b15nicolasroard            System.arraycopy(result, 0, redHistogram, 0, 256);
66860af325f2030a03c526e8551a85230d17df7b15nicolasroard            System.arraycopy(result, 256, greenHistogram, 0, 256);
67860af325f2030a03c526e8551a85230d17df7b15nicolasroard            System.arraycopy(result, 512, blueHistogram, 0, 256);
68860af325f2030a03c526e8551a85230d17df7b15nicolasroard            invalidate();
69860af325f2030a03c526e8551a85230d17df7b15nicolasroard        }
70860af325f2030a03c526e8551a85230d17df7b15nicolasroard    }
71860af325f2030a03c526e8551a85230d17df7b15nicolasroard
72860af325f2030a03c526e8551a85230d17df7b15nicolasroard    public HistogramView(Context context, AttributeSet attrs) {
73860af325f2030a03c526e8551a85230d17df7b15nicolasroard        super(context, attrs);
74860af325f2030a03c526e8551a85230d17df7b15nicolasroard    }
75860af325f2030a03c526e8551a85230d17df7b15nicolasroard
76860af325f2030a03c526e8551a85230d17df7b15nicolasroard    public void setBitmap(Bitmap bitmap) {
77860af325f2030a03c526e8551a85230d17df7b15nicolasroard        mBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
78860af325f2030a03c526e8551a85230d17df7b15nicolasroard        new ComputeHistogramTask().execute(mBitmap);
79860af325f2030a03c526e8551a85230d17df7b15nicolasroard    }
80860af325f2030a03c526e8551a85230d17df7b15nicolasroard
81860af325f2030a03c526e8551a85230d17df7b15nicolasroard    private void drawHistogram(Canvas canvas, int[] histogram, int color, PorterDuff.Mode mode) {
82860af325f2030a03c526e8551a85230d17df7b15nicolasroard        int max = 0;
83860af325f2030a03c526e8551a85230d17df7b15nicolasroard        for (int i = 0; i < histogram.length; i++) {
84860af325f2030a03c526e8551a85230d17df7b15nicolasroard            if (histogram[i] > max) {
85860af325f2030a03c526e8551a85230d17df7b15nicolasroard                max = histogram[i];
86860af325f2030a03c526e8551a85230d17df7b15nicolasroard            }
87860af325f2030a03c526e8551a85230d17df7b15nicolasroard        }
88b203968cc53015d9c51b790a56cca638be77818dnicolasroard        float w = getWidth(); // - Spline.curveHandleSize();
89b203968cc53015d9c51b790a56cca638be77818dnicolasroard        float h = getHeight(); // - Spline.curveHandleSize() / 2.0f;
90b203968cc53015d9c51b790a56cca638be77818dnicolasroard        float dx = 0; // Spline.curveHandleSize() / 2.0f;
91860af325f2030a03c526e8551a85230d17df7b15nicolasroard        float wl = w / histogram.length;
927321f1d82c7b72b491bf7c20b03e3491cb91fcabnicolasroard        float wh = h / max;
93b203968cc53015d9c51b790a56cca638be77818dnicolasroard
94b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.reset();
95b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setAntiAlias(true);
96b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setARGB(100, 255, 255, 255);
97b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStrokeWidth((int) Math.ceil(wl));
98860af325f2030a03c526e8551a85230d17df7b15nicolasroard
99860af325f2030a03c526e8551a85230d17df7b15nicolasroard        // Draw grid
100b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStyle(Paint.Style.STROKE);
101b203968cc53015d9c51b790a56cca638be77818dnicolasroard        canvas.drawRect(dx, 0, dx + w, h, mPaint);
102b203968cc53015d9c51b790a56cca638be77818dnicolasroard        canvas.drawLine(dx + w / 3, 0, dx + w / 3, h, mPaint);
103b203968cc53015d9c51b790a56cca638be77818dnicolasroard        canvas.drawLine(dx + 2 * w / 3, 0, dx + 2 * w / 3, h, mPaint);
104860af325f2030a03c526e8551a85230d17df7b15nicolasroard
105b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStyle(Paint.Style.FILL);
106b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setColor(color);
107b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStrokeWidth(6);
108b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setXfermode(new PorterDuffXfermode(mode));
109b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mHistoPath.reset();
110b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mHistoPath.moveTo(dx, h);
111860af325f2030a03c526e8551a85230d17df7b15nicolasroard        boolean firstPointEncountered = false;
112860af325f2030a03c526e8551a85230d17df7b15nicolasroard        float prev = 0;
113860af325f2030a03c526e8551a85230d17df7b15nicolasroard        float last = 0;
114860af325f2030a03c526e8551a85230d17df7b15nicolasroard        for (int i = 0; i < histogram.length; i++) {
115860af325f2030a03c526e8551a85230d17df7b15nicolasroard            float x = i * wl + dx;
116860af325f2030a03c526e8551a85230d17df7b15nicolasroard            float l = histogram[i] * wh;
117860af325f2030a03c526e8551a85230d17df7b15nicolasroard            if (l != 0) {
118860af325f2030a03c526e8551a85230d17df7b15nicolasroard                float v = h - (l + prev) / 2.0f;
119860af325f2030a03c526e8551a85230d17df7b15nicolasroard                if (!firstPointEncountered) {
120b203968cc53015d9c51b790a56cca638be77818dnicolasroard                    mHistoPath.lineTo(x, h);
121860af325f2030a03c526e8551a85230d17df7b15nicolasroard                    firstPointEncountered = true;
122860af325f2030a03c526e8551a85230d17df7b15nicolasroard                }
123b203968cc53015d9c51b790a56cca638be77818dnicolasroard                mHistoPath.lineTo(x, v);
124860af325f2030a03c526e8551a85230d17df7b15nicolasroard                prev = l;
125860af325f2030a03c526e8551a85230d17df7b15nicolasroard                last = x;
126860af325f2030a03c526e8551a85230d17df7b15nicolasroard            }
127860af325f2030a03c526e8551a85230d17df7b15nicolasroard        }
128b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mHistoPath.lineTo(last, h);
129b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mHistoPath.lineTo(w, h);
130b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mHistoPath.close();
131b203968cc53015d9c51b790a56cca638be77818dnicolasroard        canvas.drawPath(mHistoPath, mPaint);
132b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStrokeWidth(2);
133b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setStyle(Paint.Style.STROKE);
134b203968cc53015d9c51b790a56cca638be77818dnicolasroard        mPaint.setARGB(255, 200, 200, 200);
135b203968cc53015d9c51b790a56cca638be77818dnicolasroard        canvas.drawPath(mHistoPath, mPaint);
136860af325f2030a03c526e8551a85230d17df7b15nicolasroard    }
137860af325f2030a03c526e8551a85230d17df7b15nicolasroard
138860af325f2030a03c526e8551a85230d17df7b15nicolasroard    public void onDraw(Canvas canvas) {
139860af325f2030a03c526e8551a85230d17df7b15nicolasroard        canvas.drawARGB(0, 0, 0, 0);
140860af325f2030a03c526e8551a85230d17df7b15nicolasroard        drawHistogram(canvas, redHistogram, Color.RED, PorterDuff.Mode.SCREEN);
141860af325f2030a03c526e8551a85230d17df7b15nicolasroard        drawHistogram(canvas, greenHistogram, Color.GREEN, PorterDuff.Mode.SCREEN);
142860af325f2030a03c526e8551a85230d17df7b15nicolasroard        drawHistogram(canvas, blueHistogram, Color.BLUE, PorterDuff.Mode.SCREEN);
143860af325f2030a03c526e8551a85230d17df7b15nicolasroard    }
144860af325f2030a03c526e8551a85230d17df7b15nicolasroard}
145