com.day.image.ColorCurve Maven / Gradle / Ivy
Show all versions of aem-sdk-api Show documentation
/*************************************************************************
*
* ADOBE CONFIDENTIAL
* __________________
*
* Copyright 2012 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains
* the property of Adobe Systems Incorporated and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Adobe Systems Incorporated and its
* suppliers and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Adobe Systems Incorporated.
**************************************************************************/
package com.day.image;
import java.awt.Color;
/**
* The ColorCurve
class is a container to provide color and tonality
* information. The main use of instances of this class is done in the
* {@link MultitoneOp} class, which uses instances of this class to convey
* information of colors and tonality of those colors to mix together.
*
* Instances of this class contain a Color
value and a tonality
* curve, which is a 256 element array of intensity values in the range [0..1],
* where 0 is no application of this color and 1 is full color intensity. The
* elements of the array map to image luminance, where element 0 is taken for
* pixels with most luminance and element 256 is taken for pixels with no
* luminance.
*
* @version $Revision$, $Date$
* @author fmeschbe
* @since echidna
* @audience wad
*/
public class ColorCurve {
/** The number of levels supported by instances of this class */
public static final int MAX_LEVEL = 256;
/**
* The default color curve if none is explicitly defined. This maps input
* luminance levels to the same output level.
*/
private static final float[] IDENTITY_CURVE;
/** The color of this instance */
private final Color color;
// build the identity mapping table
static {
IDENTITY_CURVE = new float[MAX_LEVEL];
for (int i=0; i < MAX_LEVEL; i++) {
IDENTITY_CURVE[i] = (float) i / 256;
}
}
/**
* The color curve for this instance or null
if this
* instances
*/
private final float[] curve;
/**
* Creates a copy of the ColorCurve
instance. This copy
* constructor copies the values of the other instance. That is external
* modification of thos values has no influence on the newly created
* instance.
*
* @param colorCurve
*/
public ColorCurve(ColorCurve colorCurve) {
this.color = colorCurve.color;
this.curve = colorCurve.curve == null
? null
: (float[]) colorCurve.curve.clone();
}
/**
* Creates a ColorCurve
with the given color and the default
* mapping. The default mapping maps luminosity levels to the same intensity
* levels.
*
* @param color The color to set in this ColorCurve
.
*/
public ColorCurve(Color color) {
this.color = color;
this.curve = IDENTITY_CURVE;
}
/**
* Creates a ColorCurve
with the given color and an evenly
* spaced interval table based on list of intensity points.
*
* Each entry of the curve parameter is in the range [0..1] and the length
* of the array is in the interval [2..256]. If the array has less than
* two entries it is ignored and the identity mapping is taken, if either
* an entry value is out of range or the curve array is longer than 256
* entries, the result is undefined.
*
* @param color The color described by this descriptor
* @param curve The intensity perecentages for equally distributed
* intervals or null
to use the identity map.
*/
public ColorCurve(Color color, float[] curve) {
this.color = color;
if (curve == null || curve.length < 2) {
this.curve = IDENTITY_CURVE;
} else {
this.curve = evenlySpacedCurve(curve);
}
}
/**
* Creates a ColorCurve
with the given color and an interval
* table based on list of intensity points where the interval distances
* is also specified.
*
* Each entry of the curve parameter is in the range [0..1] and the length
* of the array is in the interval [2..256]. If the array has less than
* two entries it is ignored and the identity mapping is taken, if either
* an entry value is out of range or the curve array is longer than 256
* entries, the result is undefined.
*
* The intervals array must contain the one elements less than the curve
* array, that is the predicate
* curve.length - 1 == intervals.length
must be
* true
. If the intervals array is smaller or bigger than that,
* it is ignored and the points are evenyl spaced !
*
* The sum of entries of the intervals array defines the relative size of
* each interval. For example if the sum of the entries is 11, the first
* entry is 1, then the first intervall will take 23 steps, which is
* 256 * 1/11 because each step is 1/11th of the full range of 256.
*
* @param color The color described by this descriptor
* @param curve The intensity perecentages for the intervals or
* null
to use the identity map (in which case the
* intervals argument is ignored).
* @param intervals Normalized intervalls of curve values or
* null
to evenly space the itensity levels
* .
*/
public ColorCurve(Color color, float[] curve, float intervals[]) {
this.color = color;
if (curve == null || curve.length < 2) {
this.curve = IDENTITY_CURVE;
} else {
this.curve = intervalCurve(curve, intervals);
}
}
/**
* Returns the color associated with this instance.
* @return the color associated with this instance.
*/
public Color getColor() {
return color;
}
/**
* Returns the intensity level for the given level.
*
* @param step The luminosity level for which to return this instances
* intensity level.
*
* @return The intensity level of this instance for the given luminosity.
*
* @throws IndexOutOfBoundsException if step is less than 0 or higher than
* {@link #MAX_LEVEL}.
*/
public float getLevel(int step) {
return curve[step];
}
/**
* Creates a curve vector which evenly spaces the curve gradient intervals.
*
* @param curve The curve gradient points to be distributed.
*
* @return The curve vector with evenly spaced gradient intervalls.
*/
private float[] evenlySpacedCurve(float[] curve) {
// create an intervals array, which evenly spaces the curve data
float[] intervals = new float[curve.length-1];
for (int i=0; i < intervals.length; i++) {
intervals[i] = 1;
}
// now use the interval parametrized method
return intervalCurve(curve, intervals);
}
/**
* Creates a curve vector, whose curve gradients are distributed according
* to the intervalls array. The array contains normalized values of relative
* intervall size. For example, if the sum of all entries in the intervals
* array is 11 and the first entry is 1, the first intervall takes 23
* steps which is 256 * 1 / 11.
*
* If the intervals list is null
or does not contain one
* element less than then curve list, the curve points are evenly distributed
* as if the method {@link #evenlySpacedCurve(float[] curve)} would be
* called.
*
* @param curve The curve gradient points to be distributed
* @param intervals The normalized distribution list
*
* @return The curve vector with gradient intervalls as specified.
*/
private float[] intervalCurve(float[] curve, float intervals[]) {
// check whether the intervalls array is correct, else use evenly spaced
if (intervals == null || intervals.length != curve.length-1) {
return evenlySpacedCurve(curve);
}
// find the normalization factor, which is the sum of all interval entries.
float factor = 0;
for (int i=0; i < intervals.length; i++) {
factor += intervals[i];
}
float[] res = new float[MAX_LEVEL];
int resI = 0;
float level1 = curve[0];
for (int i=1; i < curve.length; i++) {
float level0 = level1;
float interval = intervals[i-1] * MAX_LEVEL / factor;
int end = (int) (resI + interval + .5f);
if (end > MAX_LEVEL || i == curve.length-1) {
end = MAX_LEVEL;
}
level1 = curve[i];
float step = (level1 - level0) / (end - resI);
for ( ; resI < end; resI++) {
res[resI] = level0;
level0 += step;
}
}
return res;
}
}