Android Open Source - pixel-art Colour Picker View






From Project

Back to project page pixel-art.

License

The source code is released under:

Apache License

If you think the Android project pixel-art listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.jaween.pixelart.ui.colourpicker;
/*from   w  w  w  . j  a  v  a 2s .  c om*/
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.jaween.pixelart.util.Color;

import java.util.ArrayList;

/**
 * Created by ween on 11/21/14.
 */
public class ColourPickerView extends View {

    private Paint bitmapPaint = new Paint();
    private Paint circleBorderPaint = new Paint();
    private Paint selectedPointPaint = new Paint();

    private PointF selectedPoint = new PointF();
    private float selectedPointWidth;

    private Rect bounds = new Rect();
    private float radius;
    private float dp;

    private static float[] hsl = new float[3];
    private float hue = 0f;
    private float saturation = 1f;
    private float lightness = 0.5f;

    private Bitmap colourWheel;
    private boolean colourPickerGenerated = false;

    private OnColourSelectListener onColourSelectListener = null;

    public ColourPickerView(Context context) {
        super(context);
        init(context);
    }

    public ColourPickerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public ColourPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        dp = context.getResources().getDisplayMetrics().density;

        bitmapPaint.setColor(android.graphics.Color.MAGENTA);
        bitmapPaint.setStyle(Paint.Style.STROKE);

        circleBorderPaint.setColor(android.graphics.Color.BLACK);
        circleBorderPaint.setStrokeWidth(dp);
        circleBorderPaint.setStyle(Paint.Style.STROKE);
        circleBorderPaint.setAntiAlias(true);

        selectedPointWidth = 4*dp;
        selectedPointPaint.setColor(android.graphics.Color.WHITE);
        selectedPointPaint.setStrokeWidth(selectedPointWidth);
        selectedPointPaint.setStyle(Paint.Style.STROKE);
        selectedPointPaint.setShadowLayer(selectedPointWidth, 0, selectedPointWidth / 2, android.graphics.Color.DKGRAY);
        selectedPointPaint.setAntiAlias(true);

    }

    public float getSaturation() {
        return saturation;
    }

    public void setSaturation(float saturation) {
        this.saturation = saturation;
        invalidateSelectedColour(false);
    }

    public float getHue() {
        return hue;
    }

    public void setHue(float hue) {
        this.hue = hue;
        invalidateSelectedColour(false);
    }

    public float getLightness() {
        return lightness;
    }

    public void setLightness(float lightness) {
        this.lightness = lightness;
        invalidateSelectedColour(false);
    }

    public void setHSL(float hue, float saturation, float lightness, boolean fromPalette) {
        this.hue = hue;
        this.saturation = saturation;
        this.lightness = lightness;

        invalidateSelectedColour(fromPalette);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        bounds.left = getPaddingLeft();
        bounds.top = getPaddingTop();
        bounds.right = w - getPaddingRight() - bounds.left;
        bounds.bottom = h - getPaddingBottom() - bounds.top;

        int smallerDimension = Math.min(bounds.width(), bounds.height());
        radius = smallerDimension / 2f;

        selectedPoint.set(bounds.centerX(), bounds.centerY());

        // Fills out the colour picker
        if (smallerDimension > 0) {
            colourWheel = Bitmap.createBitmap(smallerDimension, smallerDimension, Bitmap.Config.ARGB_8888);
            ArrayList<Object> data = new ArrayList<Object>();
            data.add(colourWheel);
            data.add(radius);
            data.add(saturation);
            data.add(this);
            ColourPickerGenerator colourPickerGenerator = new ColourPickerGenerator();
            colourPickerGenerator.execute(data);
        }
    }

    // Outputs the colour (in HSL) that these coordinates represent on a colour rectangle
    private float[] coordsToRectangularHSL(float x, float y, float z, float width, float height, float[] hsl) {
        float h = 360f * x / width;
        float s = z;
        float l = 1 - y / height;
        hsl[0] = h;
        hsl[1] = s;
        hsl[2] = l;

        return hsl;
    }

    // Outputs the colour (in HSL) that these coordinates represent on a colour wheel
    private static float[] coordsToCirclularHSL(float x, float y, float z, float centerX, float centerY, float radius, float[] hsl) {
        float angle = (float) Math.atan2(y - centerX, x - centerX);
        float dist = (float) Math.hypot(x - centerY, y - centerY);

        float hPrime = (float) (angle * 180f / Math.PI + 180f);
        float s = z;
        float l = Math.min(dist / radius, 1f);

        if (dist > radius) {
            return null;
        }

        hsl[0] = hPrime;
        hsl[1] = s;
        hsl[2] = l;
        return hsl;
    }

    private void clampWithinCircle(PointF point) {
        float angle = (float) Math.atan2(point.y - bounds.centerY(), point.x - bounds.centerX());
        float dist = (float) Math.hypot(point.x - bounds.centerX(), point.y - bounds.centerY());

        if (dist > radius) {
            point.x = bounds.centerX() + (float) (radius*Math.cos(angle));
            point.y = bounds.centerY() + (float) (radius*Math.sin(angle));
        }
    }

    // Updates the selector reticule
    private void invalidateSelectedColour(boolean fromPalette) {
        int colour = Color.HSLToColor(hue, saturation, lightness);

        float angleRadians = (float) (hue * Math.PI / 180f);
        selectedPoint.x = bounds.centerX() - (float) (radius * lightness * Math.cos(angleRadians));
        selectedPoint.y = bounds.centerY() - (float) (radius * lightness * Math.sin(angleRadians));

        if (!fromPalette) {
            if (onColourSelectListener != null) {
                onColourSelectListener.onColourSelect(colour);
            }
        }

        invalidate();
    }

    private void colourPickerGenerated() {
        colourPickerGenerated = true;
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                selectColour(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_MOVE:
                selectColour(event.getX(), event.getY());
                break;
            case MotionEvent.ACTION_UP:
                if (onColourSelectListener != null) {
                    onColourSelectListener.onColourSelectEnd();
                }
            default:
                return false;
        }
        return true;
    }

    // Sets the selected colour to the coordinates passed in
    private void selectColour(float x, float y) {
        selectedPoint.set(x, y);

        // Coordinates outside the circle are brought back inside
        clampWithinCircle(selectedPoint);

        // Converts the coordinates into the corresponding HSL value (that is colour under the user's finger)
        float[] hsl = coordsToCirclularHSL(selectedPoint.x, selectedPoint.y, saturation, bounds.centerX(), bounds.centerY(), radius, this.hsl);
        if (hsl != null) {
            hue = hsl[0];
            saturation = hsl[1];
            lightness = hsl[2];

            // Updates the UI selector
            invalidateSelectedColour(false);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // Colour wheel
        if (colourPickerGenerated) {
            canvas.drawBitmap(colourWheel, bounds.centerX() - radius, bounds.centerY() - radius, bitmapPaint);
        }

        // Anti-aliased border
        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius, circleBorderPaint);

        // Selected colour reticule
        // TODO: On the first draw selectedPoint has the wrong value
        canvas.drawCircle(selectedPoint.x, selectedPoint.y, 8*dp, selectedPointPaint);
    }

    public void setOnColourSelectListener(OnColourSelectListener onColourSelectListener) {
        this.onColourSelectListener = onColourSelectListener;
    }

    public interface OnColourSelectListener {
        public void onColourSelect(int colour);
        public void onColourSelectEnd();
    }

    private static class ColourPickerGenerator extends AsyncTask<ArrayList<Object>, Void, Bitmap> {

        private Bitmap bitmap;
        private Float radius;
        private Float saturation;
        private ColourPickerView colourPickerView;
        private float[] hslTemp = new float[3];

        @Override
        protected Bitmap doInBackground(ArrayList<Object>... arrayLists) {
            ArrayList<Object> data = arrayLists[0];
            bitmap = (Bitmap) data.get(0);
            radius = (Float) data.get(1);
            saturation = (Float) data.get(2);
            colourPickerView = (ColourPickerView) data.get(3);
            makeColourPicker(bitmap);
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            colourPickerView.colourPickerGenerated();
            super.onPostExecute(bitmap);
        }

        private void makeColourPicker(Bitmap bitmap) {
            for (int x = 0; x < radius * 2; x++) {
                for (int y = 0; y < radius * 2; y++) {
                    //float[] hsl = coordsToRectangularHSL(x, y, saturation, radius * 2, radius * 2);
                    float[] hsl = coordsToCirclularHSL(x, y, saturation, radius, radius, radius, hslTemp);

                    int colour;
                    if (hsl == null) {
                        colour = android.graphics.Color.TRANSPARENT;
                    } else {
                        colour = Color.HSLToColor(hsl[0], hsl[1], hsl[2]);
                    }
                    bitmap.setPixel(x, y, colour);
                }
            }
        }


    }
}




Java Source Code List

com.jaween.pixelart.ContainerActivity.java
com.jaween.pixelart.ContainerFragment.java
com.jaween.pixelart.PanelManagerFragment.java
com.jaween.pixelart.io.AnimationFile.java
com.jaween.pixelart.io.FileAdapter.java
com.jaween.pixelart.io.ImportExport.java
com.jaween.pixelart.io.LoadFileDialog.java
com.jaween.pixelart.tools.Command.java
com.jaween.pixelart.tools.Dropper.java
com.jaween.pixelart.tools.Eraser.java
com.jaween.pixelart.tools.FloodFill.java
com.jaween.pixelart.tools.FreeSelect.java
com.jaween.pixelart.tools.MagicWand.java
com.jaween.pixelart.tools.Oval.java
com.jaween.pixelart.tools.Pen.java
com.jaween.pixelart.tools.RectSelect.java
com.jaween.pixelart.tools.Rect.java
com.jaween.pixelart.tools.Selection.java
com.jaween.pixelart.tools.ToolReport.java
com.jaween.pixelart.tools.Tool.java
com.jaween.pixelart.tools.attributes.EraserToolAttributes.java
com.jaween.pixelart.tools.attributes.MagicWandToolAttributes.java
com.jaween.pixelart.tools.attributes.OvalToolAttributes.java
com.jaween.pixelart.tools.attributes.PenToolAttributes.java
com.jaween.pixelart.tools.attributes.RectToolAttributes.java
com.jaween.pixelart.tools.attributes.ToolAttributes.java
com.jaween.pixelart.tools.options.EraserOptionsView.java
com.jaween.pixelart.tools.options.MagicWandOptionsView.java
com.jaween.pixelart.tools.options.OvalOptionsView.java
com.jaween.pixelart.tools.options.PenOptionsView.java
com.jaween.pixelart.tools.options.RectOptionsView.java
com.jaween.pixelart.tools.options.ToolOptionsView.java
com.jaween.pixelart.ui.ColourButton.java
com.jaween.pixelart.ui.ColourSelector.java
com.jaween.pixelart.ui.DrawingFragment.java
com.jaween.pixelart.ui.DrawingSurface.java
com.jaween.pixelart.ui.PaletteFragment.java
com.jaween.pixelart.ui.PanelFragment.java
com.jaween.pixelart.ui.PixelGrid.java
com.jaween.pixelart.ui.Thumbnail.java
com.jaween.pixelart.ui.ToolButton.java
com.jaween.pixelart.ui.ToolboxFragment.java
com.jaween.pixelart.ui.TransparencyCheckerboard.java
com.jaween.pixelart.ui.animation.AnimationFragment.java
com.jaween.pixelart.ui.animation.FrameAdapter.java
com.jaween.pixelart.ui.animation.Frame.java
com.jaween.pixelart.ui.colourpicker.ColourPickerDialog.java
com.jaween.pixelart.ui.colourpicker.ColourPickerFragment.java
com.jaween.pixelart.ui.colourpicker.ColourPickerView.java
com.jaween.pixelart.ui.layer.LayerAdapter.java
com.jaween.pixelart.ui.layer.LayerFragment.java
com.jaween.pixelart.ui.layer.Layer.java
com.jaween.pixelart.ui.undo.DrawOpManager.java
com.jaween.pixelart.ui.undo.DrawOpUndoData.java
com.jaween.pixelart.ui.undo.FrameUndoData.java
com.jaween.pixelart.ui.undo.LayerUndoData.java
com.jaween.pixelart.ui.undo.UndoItem.java
com.jaween.pixelart.ui.undo.UndoManager.java
com.jaween.pixelart.util.AbsVerticalSeekBar.java
com.jaween.pixelart.util.AnimatedGifEncoder.java
com.jaween.pixelart.util.AutoSaver.java
com.jaween.pixelart.util.BitmapEncoder.java
com.jaween.pixelart.util.Color.java
com.jaween.pixelart.util.ConfigChangeFragment.java
com.jaween.pixelart.util.Debug.java
com.jaween.pixelart.util.MarchingAnts.java
com.jaween.pixelart.util.PreferenceManager.java
com.jaween.pixelart.util.ScaleListener.java
com.jaween.pixelart.util.SlideAnimator.java
com.jaween.pixelart.util.SlidingLinearLayout.java
com.jaween.pixelart.util.VerticalProgressBar.java
com.tokaracamara.android.verticalslidevar.VerticalSeekBar.java