194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin/* 294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Copyright (C) 2014 The Android Open Source Project 394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Licensed under the Apache License, Version 2.0 (the "License"); 594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * you may not use this file except in compliance with the License. 694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * You may obtain a copy of the License at 794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * http://www.apache.org/licenses/LICENSE-2.0 994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 1094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Unless required by applicable law or agreed to in writing, software 1194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * distributed under the License is distributed on an "AS IS" BASIS, 1294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * See the License for the specific language governing permissions and 1494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * limitations under the License. 1594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 1694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 1772f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinpackage android.hardware.camera2.params; 1894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 1994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkinimport static com.android.internal.util.Preconditions.*; 2094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 2194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkinimport android.graphics.PointF; 2272f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.hardware.camera2.CameraCharacteristics; 2372f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.hardware.camera2.CameraDevice; 2472f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.hardware.camera2.CameraMetadata; 2572f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.hardware.camera2.CaptureRequest; 263c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.utils.HashCodeHelpers; 2794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 2894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkinimport java.util.Arrays; 2994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 3094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin/** 3194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Immutable class for describing a {@code 2 x M x 3} tonemap curve of floats. 3294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 3394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>This defines red, green, and blue curves that the {@link CameraDevice} will 3494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * use as the tonemapping/contrast/gamma curve when {@link CaptureRequest#TONEMAP_MODE} is 3594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * set to {@link CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE}.</p> 3694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 3794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>The total number of points {@code (Pin, Pout)} for each color channel can be no more than 3894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS}.</p> 3994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 4094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>The coordinate system for each point is within the inclusive range 4194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p> 4294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 4394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_BLUE 4494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_GREEN 4594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_RED 4694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CameraMetadata#TONEMAP_MODE_CONTRAST_CURVE 4794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS 4894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 4994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkinpublic final class TonemapCurve { 5094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 5194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Lower bound tonemap value corresponding to pure black for a single color channel. 5294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 5394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final float LEVEL_BLACK = 0.0f; 5494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 5594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 5694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Upper bound tonemap value corresponding to a pure white for a single color channel. 5794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 5894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final float LEVEL_WHITE = 1.0f; 5994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 6094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 6194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Number of elements in a {@code (Pin, Pout)} point; 6294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 6394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final int POINT_SIZE = 2; 6494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 6594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 6694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Index of the red color channel curve. 6794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 6894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final int CHANNEL_RED = 0; 6994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 7094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Index of the green color channel curve. 7194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 7294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final int CHANNEL_GREEN = 1; 7394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 7494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Index of the blue color channel curve. 7594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 7694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public static final int CHANNEL_BLUE = 2; 7794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 7894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 7994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Create a new immutable TonemapCurve instance. 8094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 8183a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * <p>Values are stored as a contiguous array of {@code (Pin, Pout)} points.</p> 8294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 8394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>All parameters may have independent length but should have at most 84b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * {@link CameraCharacteristics#TONEMAP_MAX_CURVE_POINTS} * {@value #POINT_SIZE} elements and 85b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * at least 2 * {@value #POINT_SIZE} elements.</p> 8694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 8794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>All sub-elements must be in the inclusive range of 8894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p> 8994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 9094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>This constructor copies the array contents and does not retain ownership of the array.</p> 9194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 9283a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * @param red An array of elements whose length is divisible by {@value #POINT_SIZE} 9383a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * @param green An array of elements whose length is divisible by {@value #POINT_SIZE} 9483a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * @param blue An array of elements whose length is divisible by {@value #POINT_SIZE} 9594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 9694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws IllegalArgumentException 9783a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * if any of input array length is invalid, 9883a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * or if any of the elements in the array are not in the range of 9983a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}] 10094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws NullPointerException 10183a9e4d86407d627f3f6fbf8757d2a389097ab6fYin-Chia Yeh * if any of the parameters are {@code null} 10294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 10394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public TonemapCurve(float[] red, float[] green, float[] blue) { 10494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin // TODO: maxCurvePoints check? 10594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 10694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkNotNull(red, "red must not be null"); 10794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkNotNull(green, "green must not be null"); 10894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkNotNull(blue, "blue must not be null"); 10994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 11094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentArrayLengthDivisibleBy(red, POINT_SIZE, "red"); 11194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentArrayLengthDivisibleBy(green, POINT_SIZE, "green"); 11294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentArrayLengthDivisibleBy(blue, POINT_SIZE, "blue"); 11394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 114b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh checkArgumentArrayLengthNoLessThan(red, MIN_CURVE_LENGTH, "red"); 115b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh checkArgumentArrayLengthNoLessThan(green, MIN_CURVE_LENGTH, "green"); 116b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh checkArgumentArrayLengthNoLessThan(blue, MIN_CURVE_LENGTH, "blue"); 117b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh 11894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArrayElementsInRange(red, LEVEL_BLACK, LEVEL_WHITE, "red"); 11994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArrayElementsInRange(green, LEVEL_BLACK, LEVEL_WHITE, "green"); 12094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArrayElementsInRange(blue, LEVEL_BLACK, LEVEL_WHITE, "blue"); 12194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 12294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin mRed = Arrays.copyOf(red, red.length); 12394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin mGreen = Arrays.copyOf(green, green.length); 12494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin mBlue = Arrays.copyOf(blue, blue.length); 12594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 12694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 12794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private static void checkArgumentArrayLengthDivisibleBy(float[] array, 12894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin int divisible, String arrayName) { 12994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (array.length % divisible != 0) { 13094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin throw new IllegalArgumentException(arrayName + " size must be divisible by " 13194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin + divisible); 13294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 13394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 13494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 13594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private static int checkArgumentColorChannel(int colorChannel) { 13694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin switch (colorChannel) { 13794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_RED: 13894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_GREEN: 13994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_BLUE: 14094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin break; 14194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin default: 14294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin throw new IllegalArgumentException("colorChannel out of range"); 14394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 14494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 14594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return colorChannel; 14694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 14794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 148b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh private static void checkArgumentArrayLengthNoLessThan(float[] array, int minLength, 149b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh String arrayName) { 150b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh if (array.length < minLength) { 151b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh throw new IllegalArgumentException(arrayName + " size must be at least " 152b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh + minLength); 153b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh } 154b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh } 155b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh 15694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 15794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Get the number of points stored in this tonemap curve for the specified color channel. 15894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 15994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @param colorChannel one of {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, {@link #CHANNEL_BLUE} 16094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @return number of points stored in this tonemap for that color's curve (>= 0) 16194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 16294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws IllegalArgumentException if {@code colorChannel} was out of range 16394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 16494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public int getPointCount(int colorChannel) { 16594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentColorChannel(colorChannel); 16694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 16794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return getCurve(colorChannel).length / POINT_SIZE; 16894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 16994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 17094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 17194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Get the point for a color channel at a specified index. 17294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 17394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>The index must be at least 0 but no greater than {@link #getPointCount(int)} for 17494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * that {@code colorChannel}.</p> 17594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 17694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>All returned coordinates in the point are between the range of 17794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p> 17894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 17994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @param colorChannel {@link #CHANNEL_RED}, {@link #CHANNEL_GREEN}, or {@link #CHANNEL_BLUE} 18094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @param index at least 0 but no greater than {@code getPointCount(colorChannel)} 18194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @return the {@code (Pin, Pout)} pair mapping the tone for that index 18294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 18394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws IllegalArgumentException if {@code colorChannel} or {@code index} was out of range 18494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 18594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see #LEVEL_BLACK 18694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see #LEVEL_WHITE 18794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 18894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public PointF getPoint(int colorChannel, int index) { 18994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentColorChannel(colorChannel); 19094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (index < 0 || index >= getPointCount(colorChannel)) { 19194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin throw new IllegalArgumentException("index out of range"); 19294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 19394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 19494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin final float[] curve = getCurve(colorChannel); 19594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 19694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin final float pIn = curve[index * POINT_SIZE + OFFSET_POINT_IN]; 19794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin final float pOut = curve[index * POINT_SIZE + OFFSET_POINT_OUT]; 19894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 19994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return new PointF(pIn, pOut); 20094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 20194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 20294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 20394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Copy the color curve for a single color channel from this tonemap curve into the destination. 20494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 20594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p> 20694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <!--The output is encoded the same as in the constructor --> 20794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Values are stored as packed {@code (Pin, Pout}) points, and there are a total of 20894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * {@link #getPointCount} points for that respective channel.</p> 20994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 21094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>All returned coordinates are between the range of 21194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * [{@value #LEVEL_BLACK}, {@value #LEVEL_WHITE}].</p> 21294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 21394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @param destination 21494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * an array big enough to hold at least {@link #getPointCount} {@code *} 21594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * {@link #POINT_SIZE} elements after the {@code offset} 21694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @param offset 21794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * a non-negative offset into the array 21894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws NullPointerException 21994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * If {@code destination} was {@code null} 22094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws IllegalArgumentException 22194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * If offset was negative 22294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @throws ArrayIndexOutOfBoundsException 22394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * If there's not enough room to write the elements at the specified destination and 22494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * offset. 22594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 22694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_BLUE 22794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_RED 22894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see CaptureRequest#TONEMAP_CURVE_GREEN 22994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see #LEVEL_BLACK 23094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @see #LEVEL_WHITE 23194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 23294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public void copyColorCurve(int colorChannel, float[] destination, 23394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin int offset) { 23494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkArgumentNonnegative(offset, "offset must not be negative"); 23594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin checkNotNull(destination, "destination must not be null"); 23694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 23794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (destination.length + offset < getPointCount(colorChannel) * POINT_SIZE) { 23894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin throw new ArrayIndexOutOfBoundsException("destination too small to fit elements"); 23994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 24094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 24194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin float[] curve = getCurve(colorChannel); 24294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin System.arraycopy(curve, /*srcPos*/0, destination, offset, curve.length); 24394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 24494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 24594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 24694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * Check if this TonemapCurve is equal to another TonemapCurve. 24794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 24894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * <p>Two matrices are equal if and only if all of their elements are 24994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * {@link Object#equals equal}.</p> 25094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * 25194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * @return {@code true} if the objects were equal, {@code false} otherwise 25294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 25394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin @Override 25494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public boolean equals(Object obj) { 25594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (obj == null) { 25694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return false; 25794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 25894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (this == obj) { 25994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return true; 26094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 26194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (obj instanceof TonemapCurve) { 26294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin final TonemapCurve other = (TonemapCurve) obj; 26394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return Arrays.equals(mRed, other.mRed) && 26494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin Arrays.equals(mGreen, other.mGreen) && 26594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin Arrays.equals(mBlue, other.mBlue); 26694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 26794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return false; 26894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 26994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 27094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin /** 27194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin * {@inheritDoc} 27294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin */ 27394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin @Override 27494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin public int hashCode() { 27594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin if (mHashCalculated) { 27694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin // Avoid re-calculating hash. Data is immutable so this is both legal and faster. 27794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return mHashCode; 27894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 27994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 28094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue); 28194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin mHashCalculated = true; 28294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 28394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return mHashCode; 28494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 28594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 286b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh /** 287b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * Return the TonemapCurve as a string representation. 288b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * 289b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * <p> {@code "TonemapCurve{R:[(%f, %f), (%f, %f) ... (%f, %f)], G:[(%f, %f), (%f, %f) ... 290b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * (%f, %f)], B:[(%f, %f), (%f, %f) ... (%f, %f)]}"}, 291b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * where each {@code (%f, %f)} respectively represents one point of the corresponding 292b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * tonemap curve. </p> 293b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * 294b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh * @return string representation of {@link TonemapCurve} 295b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh */ 296b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh @Override 297b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh public String toString() { 298b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh StringBuilder sb = new StringBuilder("TonemapCurve{"); 299b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append("R:"); 300b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(curveToString(CHANNEL_RED)); 301b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(", G:"); 302b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(curveToString(CHANNEL_GREEN)); 303b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(", B:"); 304b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(curveToString(CHANNEL_BLUE)); 305b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append("}"); 306b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh return sb.toString(); 307b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh } 308b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh 309b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh private String curveToString(int colorChannel) { 310b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh checkArgumentColorChannel(colorChannel); 311b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh StringBuilder sb = new StringBuilder("["); 312b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh float[] curve = getCurve(colorChannel); 313b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh int pointCount = curve.length / POINT_SIZE; 314b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh for (int i = 0, j = 0; i < pointCount; i++, j += 2) { 315b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append("("); 316b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(curve[j]); 317b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(", "); 318b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append(curve[j+1]); 319b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append("), "); 320b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh } 321b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh // trim extra ", " at the end. Guaranteed to work because pointCount >= 2 322b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.setLength(sb.length() - 2); 323b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh sb.append("]"); 324b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh return sb.toString(); 325b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh } 326b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh 32794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private float[] getCurve(int colorChannel) { 32894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin switch (colorChannel) { 32994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_RED: 33094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return mRed; 33194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_GREEN: 33294814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return mGreen; 33394814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin case CHANNEL_BLUE: 33494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin return mBlue; 33594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin default: 33694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin throw new AssertionError("colorChannel out of range"); 33794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 33894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin } 33994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 34094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private final static int OFFSET_POINT_IN = 0; 34194814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private final static int OFFSET_POINT_OUT = 1; 342b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh private final static int TONEMAP_MIN_CURVE_POINTS = 2; 343b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh private final static int MIN_CURVE_LENGTH = TONEMAP_MIN_CURVE_POINTS * POINT_SIZE; 34494814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 34594814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private final float[] mRed; 34694814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private final float[] mGreen; 34794814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private final float[] mBlue; 34894814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin 34994814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private int mHashCode; 35094814218d2313a989a5a8969f633e3fc33e43071Igor Murashkin private boolean mHashCalculated = false; 351b086421b41f1fbe0dfcd14cb38eed0acbddd81d0Yin-Chia Yeh} 352