com.livinglogic.ul4.Color.java Source code

Java tutorial

Introduction

Here is the source code for com.livinglogic.ul4.Color.java

Source

/*
** Copyright 2009-2014 by LivingLogic AG, Bayreuth/Germany
** All Rights Reserved
** See LICENSE for the license
*/

package com.livinglogic.ul4;

import java.util.List;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.NoSuchElementException;
import java.util.Vector;

import org.apache.commons.lang.math.NumberUtils;

import static com.livinglogic.utils.SetUtils.makeSet;

public class Color implements Collection, UL4Repr, UL4Attributes, UL4Len, UL4Type {
    private char r;
    private char g;
    private char b;
    private char a;

    public Color(int r, int g, int b, int a) {
        if (r < 0)
            r = 0;
        else if (r > 255)
            r = 255;
        this.r = (char) r;

        if (g < 0)
            g = 0;
        else if (g > 255)
            g = 255;
        this.g = (char) g;

        if (b < 0)
            b = 0;
        else if (b > 255)
            b = 255;
        this.b = (char) b;

        if (a < 0)
            a = 0;
        else if (a > 255)
            a = 255;
        this.a = (char) a;
    }

    public Color(int r, int g, int b) {
        this(r, g, b, 255);
    }

    public static Color fromrgb(double r, double g, double b, double a) {
        return new Color((int) (255 * r), (int) (255 * g), (int) (255 * b), (int) (255 * a));
    }

    public static Color fromrgb(double r, double g, double b) {
        return fromrgb(r, g, b, 1.0);
    }

    public static Color fromhsv(double h, double s, double v, double a) {
        h %= 1.0;

        if (s < 0.0)
            s = 0.0;
        else if (s > 1.0)
            s = 1.0;

        if (v < 0.0)
            v = 0.0;
        else if (v > 1.0)
            v = 1.0;

        if (a < 0.0)
            a = 0.0;
        else if (a > 1.0)
            a = 1.0;

        int rr = 0;
        int rg = 0;
        int rb = 0;
        int ra = (int) (255. * a);

        if (s == 0.0)
            rr = rg = rb = (int) (255. * v);
        else {
            int i = (int) (h * 6.0);
            double f = (h * 6.0) - i;
            double p = v * (1.0 - s);
            double q = v * (1.0 - s * f);
            double t = v * (1.0 - s * (1.0 - f));

            switch (i) {
            case 0:
            case 6:
                rr = (int) (255. * v);
                rg = (int) (255. * t);
                rb = (int) (255. * p);
                break;
            case 1:
                rr = (int) (255. * q);
                rg = (int) (255. * v);
                rb = (int) (255. * p);
                break;
            case 2:
                rr = (int) (255. * p);
                rg = (int) (255. * v);
                rb = (int) (255. * t);
                break;
            case 3:
                rr = (int) (255. * p);
                rg = (int) (255. * q);
                rb = (int) (255. * v);
                break;
            case 4:
                rr = (int) (255. * t);
                rg = (int) (255. * p);
                rb = (int) (255. * v);
                break;
            case 5:
                rr = (int) (255. * v);
                rg = (int) (255. * p);
                rb = (int) (255. * q);
                break;
            }
        }
        return new Color(rr, rg, rb, ra);
    }

    public static Color fromhsv(double h, double s, double v) {
        return fromhsv(h, s, v, 1.0);
    }

    private static double _v(double m1, double m2, double hue) {
        hue %= 1.0;

        if (hue < 1. / 6.)
            return m1 + (m2 - m1) * hue * 6.0;
        else if (hue < 0.5)
            return m2;
        else if (hue < 2. / 3.)
            return m1 + (m2 - m1) * (2. / 3. - hue) * 6.0;
        else
            return m1;
    }

    public static Color fromhls(double h, double l, double s, double a) {
        h %= 1.0;

        if (l < 0.0)
            l = 0.0;
        else if (l > 1.0)
            l = 1.0;

        if (s < 0.0)
            s = 0.0;
        else if (s > 1.0)
            s = 1.0;

        if (a < 0.0)
            a = 0.0;
        else if (a > 1.0)
            a = 1.0;

        if (s == 0.0)
            return new Color((int) (255. * l), (int) (255. * l), (int) (255. * l), (int) (255. * a));

        double m2 = l <= 0.5 ? l * (1.0 + s) : l + s - (l * s);
        double m1 = 2.0 * l - m2;

        double r = _v(m1, m2, h + 1. / 3.);
        double g = _v(m1, m2, h);
        double b = _v(m1, m2, h - 1. / 3.);
        return new Color((int) (255. * r), (int) (255. * g), (int) (255. * b), (int) (255. * a));
    }

    public static Color fromhls(double h, double l, double s) {
        return fromhls(h, l, s, 1.0);
    }

    public int getR() {
        return r;
    }

    public int getG() {
        return g;
    }

    public int getB() {
        return b;
    }

    public int getA() {
        return a;
    }

    public String toString() {
        if (a == 255) {
            if (((r >> 4) == (r & 0xf)) && ((g >> 4) == (g & 0xf)) && ((b >> 4) == (b & 0xf)))
                return "#" + Integer.toHexString(r >> 4) + Integer.toHexString(g >> 4)
                        + Integer.toHexString(b >> 4);
            else {
                String sr = Integer.toHexString(r);
                if (sr.length() < 2)
                    sr = "0" + sr;

                String sg = Integer.toHexString(g);
                if (sg.length() < 2)
                    sg = "0" + sg;

                String sb = Integer.toHexString(b);
                if (sb.length() < 2)
                    sb = "0" + sb;

                return "#" + sr + sg + sb;
            }
        } else {
            return "rgba(" + Integer.toString(r) + "," + Integer.toString(g) + "," + Integer.toString(b) + ","
                    + a / 255. + ")";
        }
    }

    public void reprUL4(UL4Repr.Formatter formatter) {
        formatter.append("#");
        if (((r >> 4) == (r & 0xf)) && ((g >> 4) == (g & 0xf)) && ((b >> 4) == (b & 0xf))
                && ((a >> 4) == (a & 0xf))) {
            formatter.append(Integer.toHexString(r >> 4));
            formatter.append(Integer.toHexString(g >> 4));
            formatter.append(Integer.toHexString(b >> 4));
            if (a != 255)
                formatter.append(Integer.toHexString(a >> 4));
        } else {
            String sr = Integer.toHexString(r);
            if (sr.length() < 2)
                formatter.append("0");
            formatter.append(sr);

            String sg = Integer.toHexString(g);
            if (sg.length() < 2)
                formatter.append("0");
            formatter.append(sg);

            String sb = Integer.toHexString(b);
            if (sb.length() < 2)
                formatter.append("0");
            formatter.append(sb);

            if (a != 255) {
                String sa = Integer.toHexString(a);
                if (sa.length() < 2)
                    formatter.append("0");
                formatter.append(sa);
            }
        }
    }

    public String dump() {
        StringBuilder buffer = new StringBuilder(8);

        String sr = Integer.toHexString(r);
        if (sr.length() < 2)
            buffer.append("0");
        buffer.append(sr);

        String sg = Integer.toHexString(g);
        if (sg.length() < 2)
            buffer.append("0");
        buffer.append(sg);

        String sb = Integer.toHexString(b);
        if (sb.length() < 2)
            buffer.append("0");
        buffer.append(sb);

        String sa = Integer.toHexString(a);
        if (sa.length() < 2)
            buffer.append("0");
        buffer.append(sa);

        return buffer.toString();
    }

    public static Color fromdump(String value) {
        int r = Integer.valueOf(value.substring(0, 2), 16);
        int g = Integer.valueOf(value.substring(2, 4), 16);
        int b = Integer.valueOf(value.substring(4, 6), 16);
        int a = Integer.valueOf(value.substring(6, 8), 16);
        return new Color(r, g, b, a);
    }

    public static Color fromrepr(String value) {
        if (value == null)
            return null;
        int len = value.length();
        int r;
        int g;
        int b;
        int a;
        if (len == 4 || len == 5) {
            r = Integer.valueOf(value.substring(1, 2), 16) * 0x11;
            g = Integer.valueOf(value.substring(2, 3), 16) * 0x11;
            b = Integer.valueOf(value.substring(3, 4), 16) * 0x11;
            a = (len == 4) ? 0xff : (Integer.valueOf(value.substring(4, 5), 16) * 0x11);
        } else if (len == 7 || len == 9) {
            r = Integer.valueOf(value.substring(1, 3), 16);
            g = Integer.valueOf(value.substring(3, 5), 16);
            b = Integer.valueOf(value.substring(5, 7), 16);
            a = (len == 7) ? 0xff : Integer.valueOf(value.substring(7, 9), 16);
        } else
            throw new RuntimeException("Invalid color repr '" + value + "'");
        return new Color(r, g, b, a);
    }

    public Color blend(Color color) {
        double sa = a / 255.;
        double rsa = 1. - sa;
        int nr = (int) (r * sa + rsa * color.r);
        int ng = (int) (g * sa + rsa * color.g);
        int nb = (int) (b * sa + rsa * color.b);
        int na = (int) (255 - rsa * (255 - color.a));
        return new Color(nr, ng, nb, na);
    }

    public Vector<Double> hls() {
        int maxc = NumberUtils.max((int) r, (int) g, (int) b);
        int minc = NumberUtils.min((int) r, (int) g, (int) b);

        double dmaxc = maxc / 255.;
        double dminc = minc / 255.;

        double l = (dminc + dmaxc) / 2.0;

        if (minc == maxc) {
            Vector retVal = new Vector(3);
            retVal.add(new Double(0.0));
            retVal.add(new Double(l));
            retVal.add(new Double(0.0));
            return retVal;
        }
        double s = l <= 0.5 ? (dmaxc - dminc) / (dmaxc + dminc) : (dmaxc - dminc) / (2.0 - dmaxc - dminc);

        double rc = (dmaxc - r / 255.) / (dmaxc - dminc);
        double gc = (dmaxc - g / 255.) / (dmaxc - dminc);
        double bc = (dmaxc - b / 255.) / (dmaxc - dminc);

        double h;
        if (r == maxc)
            h = bc - gc;
        else if (g == maxc)
            h = 2.0 + rc - bc;
        else
            h = 4.0 + gc - rc;
        h = (h / 6.0) % 1.0;

        Vector retVal = new Vector(3);
        retVal.add(new Double(h));
        retVal.add(new Double(l));
        retVal.add(new Double(s));
        return retVal;
    }

    public Vector<Double> hlsa() {
        Vector retVal = hls();
        retVal.add(new Double(a / 255.));
        return retVal;
    }

    public Vector<Double> hsv() {
        int maxc = NumberUtils.max((int) r, (int) g, (int) b);
        int minc = NumberUtils.min((int) r, (int) g, (int) b);

        double dmaxc = maxc / 255.;
        double dminc = minc / 255.;

        double v = dmaxc;
        if (minc == maxc) {
            Vector retVal = new Vector(3);
            retVal.add(0.0d);
            retVal.add(0.0d);
            retVal.add(v);
            return retVal;
        }
        double s = (dmaxc - dminc) / dmaxc;

        double rc = (dmaxc - r / 255.) / (dmaxc - dminc);
        double gc = (dmaxc - g / 255.) / (dmaxc - dminc);
        double bc = (dmaxc - b / 255.) / (dmaxc - dminc);

        double h;
        if (r == maxc)
            h = bc - gc;
        else if (g == maxc)
            h = 2.0 + rc - bc;
        else
            h = 4.0 + gc - rc;
        h = (h / 6.0) % 1.0;

        Vector retVal = new Vector(3);
        retVal.add(h);
        retVal.add(s);
        retVal.add(v);
        return retVal;
    }

    public Vector<Double> hsva() {
        Vector retVal = hsv();
        retVal.add(new Double(a / 255.));
        return retVal;
    }

    public double lum() {
        int maxc = NumberUtils.max((int) r, (int) g, (int) b);
        int minc = NumberUtils.min((int) r, (int) g, (int) b);

        double dmaxc = maxc / 255.;
        double dminc = minc / 255.;

        return (dminc + dmaxc) / 2.0;
    }

    public Color withlum(double lum) {
        int maxc = NumberUtils.max((int) r, (int) g, (int) b);
        int minc = NumberUtils.min((int) r, (int) g, (int) b);

        double dmaxc = maxc / 255.;
        double dminc = minc / 255.;

        double l = (dminc + dmaxc) / 2.0;

        if (minc == maxc)
            return fromhls(0., lum, 0., a);

        double s = l <= 0.5 ? (dmaxc - dminc) / (dmaxc + dminc) : (dmaxc - dminc) / (2.0 - dmaxc - dminc);

        double rc = (dmaxc - r / 255.) / (dmaxc - dminc);
        double gc = (dmaxc - g / 255.) / (dmaxc - dminc);
        double bc = (dmaxc - b / 255.) / (dmaxc - dminc);

        double h;
        if (r == maxc)
            h = bc - gc;
        else if (g == maxc)
            h = 2.0 + rc - bc;
        else
            h = 4.0 + gc - rc;
        h = (h / 6.0) % 1.0;

        return fromhls(h, lum, s, a);
    }

    public Color witha(int a) {
        return new Color(r, g, b, a);
    }

    public Color abslum(double f) {
        Vector<Double> v = hlsa();
        return fromhls(v.get(0), v.get(1) + f, v.get(2), v.get(3));
    }

    public Color rellum(double f) {
        Vector<Double> v = hlsa();
        double newlum = v.get(1);
        if (f > 0)
            newlum += (1 - newlum) * f;
        else if (f < 0)
            newlum += newlum * f;
        return fromhls(v.get(0), newlum, v.get(2), v.get(3));
    }

    // Collection interface
    public boolean add(Object o) {
        throw new UnsupportedOperationException();
    }

    public boolean addAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    public void clear() {
        throw new UnsupportedOperationException();
    }

    public boolean contains(Object o) {
        if (o == null || !(o instanceof Integer))
            return false;
        int ov = ((Integer) o);

        return ((r == ov) || (g == ov) || (b == ov) || (a == ov));
    }

    public boolean containsAll(Collection c) {
        for (Object o : c) {
            if (!contains(o))
                return false;
        }
        return true;
    }

    public boolean equals(Object o) {
        if (o == null || !(o instanceof Color))
            return false;
        Color co = (Color) o;
        return ((r == co.r) && (g == co.g) && (b == co.b) && (a == co.a));
    }

    public boolean isEmpty() {
        return false;
    }

    public int hashCode() {
        return r ^ g ^ b ^ a;
    }

    public class ColorIterator implements Iterator {
        int index;

        public ColorIterator() {
            index = 0;
        }

        public boolean hasNext() {
            return index < 4;
        }

        public Object next() {
            switch (index++) {
            case 0:
                return r;
            case 1:
                return g;
            case 2:
                return b;
            case 3:
                return a;
            default:
                throw new NoSuchElementException("No more components available!");
            }
        }

        public void remove() {
            throw new UnsupportedOperationException("Colors don't support component removal!");
        }
    };

    public Iterator iterator() {
        return new ColorIterator();
    }

    public boolean remove(Object o) {
        throw new UnsupportedOperationException();
    }

    public boolean removeAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    public boolean retainAll(Collection c) {
        throw new UnsupportedOperationException();
    }

    public Object[] toArray() {
        Object[] retVal = new Object[4];
        retVal[0] = new Integer(r);
        retVal[1] = new Integer(g);
        retVal[2] = new Integer(b);
        retVal[3] = new Integer(a);
        return retVal;
    }

    public Object[] toArray(Object[] a) {
        throw new UnsupportedOperationException();
    }

    public int size() {
        return 4;
    }

    public int lenUL4() {
        return 4;
    }

    public String typeUL4() {
        return "color";
    }

    int getItemIntegerUL4(int index) {
        switch (index) {
        case 0:
        case -4:
            return r;
        case 1:
        case -3:
            return g;
        case 2:
        case -2:
            return b;
        case 3:
        case -1:
            return a;
        default:
            throw new ArrayIndexOutOfBoundsException(index);
        }
    }

    private static class BoundMethodR extends BoundMethod<Color> {
        public BoundMethodR(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.r";
        }

        public Object evaluate(BoundArguments args) {
            return (int) object.r;
        }
    }

    private static class BoundMethodG extends BoundMethod<Color> {
        public BoundMethodG(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.g";
        }

        public Object evaluate(BoundArguments args) {
            return (int) object.g;
        }
    }

    private static class BoundMethodB extends BoundMethod<Color> {
        public BoundMethodB(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.b";
        }

        public Object evaluate(BoundArguments args) {
            return (int) object.b;
        }
    }

    private static class BoundMethodA extends BoundMethod<Color> {
        public BoundMethodA(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.a";
        }

        public Object evaluate(BoundArguments args) {
            return (int) object.a;
        }
    }

    private static class BoundMethodLum extends BoundMethod<Color> {
        public BoundMethodLum(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.lum";
        }

        public Object evaluate(BoundArguments args) {
            return object.lum();
        }
    }

    private static class BoundMethodHLS extends BoundMethod<Color> {
        public BoundMethodHLS(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.hls";
        }

        public Object evaluate(BoundArguments args) {
            return object.hls();
        }
    }

    private static class BoundMethodHLSA extends BoundMethod<Color> {
        public BoundMethodHLSA(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.hlsa";
        }

        public Object evaluate(BoundArguments args) {
            return object.hlsa();
        }
    }

    private static class BoundMethodHSV extends BoundMethod<Color> {
        public BoundMethodHSV(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.hsv";
        }

        public Object evaluate(BoundArguments args) {
            return object.hsv();
        }
    }

    private static class BoundMethodHSVA extends BoundMethod<Color> {
        public BoundMethodHSVA(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.hsva";
        }

        public Object evaluate(BoundArguments args) {
            return object.hsva();
        }
    }

    private static class BoundMethodWithA extends BoundMethod<Color> {
        public BoundMethodWithA(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.witha";
        }

        private static final Signature signature = new Signature("a", Signature.required);

        public Signature getSignature() {
            return signature;
        }

        public Object evaluate(BoundArguments args) {
            return object.witha(Utils.toInt(args.get(0)));
        }
    }

    private static class BoundMethodWithLum extends BoundMethod<Color> {
        public BoundMethodWithLum(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.withlum";
        }

        private static final Signature signature = new Signature("lum", Signature.required);

        public Signature getSignature() {
            return signature;
        }

        public Object evaluate(BoundArguments args) {
            return object.withlum(Utils.toDouble(args.get(0)));
        }
    }

    private static class BoundMethodAbsLum extends BoundMethod<Color> {
        public BoundMethodAbsLum(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.abslum";
        }

        private static final Signature signature = new Signature("f", Signature.required);

        public Signature getSignature() {
            return signature;
        }

        public Object evaluate(BoundArguments args) {
            return object.abslum(Utils.toDouble(args.get(0)));
        }
    }

    private static class BoundMethodRelLum extends BoundMethod<Color> {
        public BoundMethodRelLum(Color object) {
            super(object);
        }

        public String nameUL4() {
            return "color.rellum";
        }

        private static final Signature signature = new Signature("f", Signature.required);

        public Signature getSignature() {
            return signature;
        }

        public Object evaluate(BoundArguments args) {
            return object.rellum(Utils.toDouble(args.get(0)));
        }
    }

    protected static Set<String> attributes = makeSet("r", "g", "b", "a", "lum", "hls", "hlsa", "hsv", "hsva",
            "witha", "withlum", "abslum", "rellum");

    public Set<String> getAttributeNamesUL4() {
        return attributes;
    }

    public Object getItemStringUL4(String key) {
        if ("r".equals(key))
            return new BoundMethodR(this);
        else if ("g".equals(key))
            return new BoundMethodG(this);
        else if ("b".equals(key))
            return new BoundMethodB(this);
        else if ("a".equals(key))
            return new BoundMethodA(this);
        else if ("lum".equals(key))
            return new BoundMethodLum(this);
        else if ("hls".equals(key))
            return new BoundMethodHLS(this);
        else if ("hlsa".equals(key))
            return new BoundMethodHLSA(this);
        else if ("hsv".equals(key))
            return new BoundMethodHSV(this);
        else if ("hsva".equals(key))
            return new BoundMethodHSVA(this);
        else if ("witha".equals(key))
            return new BoundMethodWithA(this);
        else if ("withlum".equals(key))
            return new BoundMethodWithLum(this);
        else if ("abslum".equals(key))
            return new BoundMethodAbsLum(this);
        else if ("rellum".equals(key))
            return new BoundMethodRelLum(this);
        else
            return new UndefinedKey(key);
    }
}