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 return value will be interpolated between the minimum and maximum value for this
023 * entry.
024 * <p>
025 * In keeping with the conventions of many Geographic Information Systems (GIS) and art applications, this instance "covered" values in the range v0 &le; f &lt;
026 * v1. Thus, a value that exactly matches the upper bound of the range is not considered "covered".
027 */
028public class PaletteEntryForRange implements PaletteEntry {
029
030    private final float v0;
031    private final float v1;
032    private final float r0;
033    private final float r1;
034    private final float g0;
035    private final float g1;
036    private final float b0;
037    private final float b1;
038    private final float a0;
039    private final float a1;
040
041    /**
042     * Constructs a palette entry for the range of values v0 &le; f &lt; v1. A single color will be returned for all values in range
043     *
044     * @param v0    the lower bounds (inclusive) of the covered range of values
045     * @param v1    the upper bounds (non-inclusive) of the covered range of value
046     * @param color the color assigned to value v0
047     */
048    public PaletteEntryForRange(final float v0, final float v1, final Color color) {
049        this.v0 = v0;
050        this.v1 = v1;
051        final float deltaV = v1 - v0;
052        // check for range volation
053        if (deltaV <= 0 || Float.isNaN(deltaV)) {
054            throw new IllegalArgumentException("Specified values must be v0<v1");
055        }
056        if (color == null) {
057            throw new IllegalArgumentException("Null colors not allowed");
058        }
059
060        final int argb0 = color.getRGB();
061        a0 = argb0 >> 24 & 0xff;
062        r0 = argb0 >> 16 & 0xff;
063        g0 = argb0 >> 8 & 0xff;
064        b0 = argb0 & 0xff;
065
066        final int argb1 = color.getRGB();
067        a1 = argb1 >> 24 & 0xff;
068        r1 = argb1 >> 16 & 0xff;
069        g1 = argb1 >> 8 & 0xff;
070        b1 = argb1 & 0xff;
071    }
072
073    /**
074     * Constructs a palette entry for the range of values v0 &le; f &lt; v1. The return color value will be interpolated between the two specified colors.
075     *
076     * @param v0     the lower bounds (inclusive) of the covered range of values
077     * @param v1     the upper bounds (non-inclusive) of the covered range of value
078     * @param color0 the color assigned to value v0
079     * @param color1 the color assigned to value v1
080     */
081    public PaletteEntryForRange(final float v0, final float v1, final Color color0, final Color color1) {
082        this.v0 = v0;
083        this.v1 = v1;
084        final float deltaV = v1 - v0;
085        // check for range volation
086        if (deltaV <= 0 || Float.isNaN(deltaV)) {
087            throw new IllegalArgumentException("Specified values must be v0<v1");
088        }
089        if (color0 == null || color1 == null) {
090            throw new IllegalArgumentException("Null colors not allowed");
091        }
092        final int argb0 = color0.getRGB();
093        a0 = argb0 >> 24 & 0xff;
094        r0 = argb0 >> 16 & 0xff;
095        g0 = argb0 >> 8 & 0xff;
096        b0 = argb0 & 0xff;
097
098        final int argb1 = color1.getRGB();
099        a1 = argb1 >> 24 & 0xff;
100        r1 = argb1 >> 16 & 0xff;
101        g1 = argb1 >> 8 & 0xff;
102        b1 = argb1 & 0xff;
103    }
104
105    @Override
106    public boolean coversSingleEntry() {
107        return false;
108    }
109
110    @Override
111    public int getArgb(final float f) {
112        if (v0 <= f && f <= v1) {
113            final float t = (f - v0) / (v1 - v0);
114            final int a = (int) (t * (a1 - a0) + a0 + 0.5);
115            final int r = (int) (t * (r1 - r0) + r0 + 0.5);
116            final int g = (int) (t * (g1 - g0) + g0 + 0.5);
117            final int b = (int) (t * (b1 - b0) + b0 + 0.5);
118            return ((a << 8 | r) << 8 | g) << 8 | b;
119        }
120        return 0;
121    }
122
123    @Override
124    public Color getColor(final float f) {
125        if (v0 <= f && f <= v1) {
126            final float t = (f - v0) / (v1 - v0);
127            final int a = (int) (t * (a1 - a0) + a0 + 0.5);
128            final int r = (int) (t * (r1 - r0) + r0 + 0.5);
129            final int g = (int) (t * (g1 - g0) + g0 + 0.5);
130            final int b = (int) (t * (b1 - b0) + b0 + 0.5);
131            return new Color(r, g, b, a);
132        }
133        return null;
134    }
135
136    @Override
137    public float getLowerBound() {
138        return v0;
139    }
140
141    @Override
142    public float getUpperBound() {
143        return v1;
144    }
145
146    @Override
147    public boolean isCovered(final float f) {
148        return v0 <= f && f < v1;
149    }
150
151    @Override
152    public String toString() {
153        return "PaletteEntry for range " + v0 + ", " + v1;
154    }
155}