001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging.formats.tiff.photometricinterpreters.floatingpoint;
018
019import java.awt.Color;
020
021/**
022 * Provides a palette entry for colors associated with a range of values. The
023 * return value will be interpolated between the minimum and maximum value for
024 * this entry.
025 * <p>
026 * In keeping with the conventions of many Geographic Information Systems (GIS)
027 * and art applications, this instance "covered" values in the range v0 &le; f
028 * &lt; v1. Thus, a value that exactly matches the upper bound of the range is
029 * not considered "covered".
030 */
031public class PaletteEntryForRange implements PaletteEntry {
032
033    private final float v0;
034    private final float v1;
035    private final float r0;
036    private final float r1;
037    private final float g0;
038    private final float g1;
039    private final float b0;
040    private final float b1;
041    private final float a0;
042    private final float a1;
043
044    /**
045     * Constructs a palette entry for the range of values v0 &le; f &lt; v1. The
046     * return color value will be interpolated between the two specified colors.
047     *
048     * @param v0 the lower bounds (inclusive) of the covered range of values
049     * @param v1 the upper bounds (non-inclusive) of the covered range of value
050     * @param color0 the color assigned to value v0
051     * @param color1 the color assigned to value v1
052     */
053    public PaletteEntryForRange(float v0, float v1, Color color0, Color color1) {
054        this.v0 = v0;
055        this.v1 = v1;
056        float deltaV = v1 - v0;
057        // check for range volation
058        if (deltaV <= 0 || Float.isNaN(deltaV)) {
059            throw new IllegalArgumentException("Specified values must be v0<v1");
060        }
061        if (color0 == null || color1 == null) {
062            throw new IllegalArgumentException("Null colors not allowed");
063        }
064        int argb0 = color0.getRGB();
065        a0 = (argb0 >> 24) & 0xff;
066        r0 = (argb0 >> 16) & 0xff;
067        g0 = (argb0 >> 8) & 0xff;
068        b0 = argb0 & 0xff;
069
070        int argb1 = color1.getRGB();
071        a1 = (argb1 >> 24) & 0xff;
072        r1 = (argb1 >> 16) & 0xff;
073        g1 = (argb1 >> 8) & 0xff;
074        b1 = argb1 & 0xff;
075    }
076
077    /**
078     * Constructs a palette entry for the range of values v0 &le; f &lt; v1. A
079     * single color will be returned for all values in range
080     *
081     * @param v0 the lower bounds (inclusive) of the covered range of values
082     * @param v1 the upper bounds (non-inclusive) of the covered range of value
083     * @param color the color assigned to value v0
084     */
085    public PaletteEntryForRange(float v0, float v1, Color color) {
086        this.v0 = v0;
087        this.v1 = v1;
088        float deltaV = v1 - v0;
089        // check for range volation
090        if (deltaV <= 0 || Float.isNaN(deltaV)) {
091            throw new IllegalArgumentException("Specified values must be v0<v1");
092        }
093        if (color == null) {
094            throw new IllegalArgumentException("Null colors not allowed");
095        }
096
097        int argb0 = color.getRGB();
098        a0 = (argb0 >> 24) & 0xff;
099        r0 = (argb0 >> 16) & 0xff;
100        g0 = (argb0 >> 8) & 0xff;
101        b0 = argb0 & 0xff;
102
103        int argb1 = color.getRGB();
104        a1 = (argb1 >> 24) & 0xff;
105        r1 = (argb1 >> 16) & 0xff;
106        g1 = (argb1 >> 8) & 0xff;
107        b1 = argb1 & 0xff;
108    }
109
110    @Override
111    public boolean isCovered(float f) {
112        return v0 <= f && f < v1;
113    }
114
115    @Override
116    public int getARGB(float f) {
117        if (v0 <= f && f <= v1) {
118            float t = (f - v0) / (v1 - v0);
119            int a = (int) (t * (a1 - a0) + a0 + 0.5);
120            int r = (int) (t * (r1 - r0) + r0 + 0.5);
121            int g = (int) (t * (g1 - g0) + g0 + 0.5);
122            int b = (int) (t * (b1 - b0) + b0 + 0.5);
123            return (((((a << 8) | r) << 8) | g) << 8) | b;
124        }
125        return 0;
126    }
127
128    @Override
129    public Color getColor(float f) {
130        if (v0 <= f && f <= v1) {
131            float t = (f - v0) / (v1 - v0);
132            int a = (int) (t * (a1 - a0) + a0 + 0.5);
133            int r = (int) (t * (r1 - r0) + r0 + 0.5);
134            int g = (int) (t * (g1 - g0) + g0 + 0.5);
135            int b = (int) (t * (b1 - b0) + b0 + 0.5);
136            return new Color(r, g, b, a);
137        }
138        return null;
139    }
140
141    @Override
142    public boolean coversSingleEntry() {
143        return false;
144    }
145
146    @Override
147    public float getLowerBound() {
148        return v0;
149    }
150
151    @Override
152    public float getUpperBound() {
153        return v1;
154    }
155
156    @Override
157    public String toString() {
158        return "PaletteEntry for range " + v0 + ", " + v1;
159    }
160}