1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.hardware.camera2.params; 18 19 import java.util.Arrays; 20 21 import static com.android.internal.util.Preconditions.checkNotNull; 22 23 /** 24 * Immutable class to store a 4-element vector of integers corresponding to a 2x2 pattern 25 * of color channel offsets used for the black level offsets of each color channel. 26 */ 27 public final class BlackLevelPattern { 28 29 /** 30 * The number of offsets in this vector. 31 */ 32 public static final int COUNT = 4; 33 34 /** 35 * Create a new {@link BlackLevelPattern} from a given offset array. 36 * 37 * <p>The given offset array must contain offsets for each color channel in 38 * a 2x2 pattern corresponding to the color filter arrangement. Offsets are 39 * given in row-column scan order.</p> 40 * 41 * @param offsets an array containing a 2x2 pattern of offsets. 42 * 43 * @throws IllegalArgumentException if the given array has an incorrect length. 44 * @throws NullPointerException if the given array is null. 45 * @hide 46 */ BlackLevelPattern(int[] offsets)47 public BlackLevelPattern(int[] offsets) { 48 if (offsets == null) { 49 throw new NullPointerException("Null offsets array passed to constructor"); 50 } 51 if (offsets.length < COUNT) { 52 throw new IllegalArgumentException("Invalid offsets array length"); 53 } 54 mCfaOffsets = Arrays.copyOf(offsets, COUNT); 55 } 56 57 /** 58 * Return the color channel offset for a given index into the array of raw pixel values. 59 * 60 * @param column the column index in the the raw pixel array. 61 * @param row the row index in the raw pixel array. 62 * @return a color channel offset. 63 * 64 * @throws IllegalArgumentException if a column or row given is negative. 65 */ getOffsetForIndex(int column, int row)66 public int getOffsetForIndex(int column, int row) { 67 if (row < 0 || column < 0) { 68 throw new IllegalArgumentException("column, row arguments must be positive"); 69 } 70 return mCfaOffsets[((row & 1) << 1) | (column & 1)]; 71 } 72 73 /** 74 * Copy the ColorChannel offsets into the destination vector. 75 * 76 * <p>Offsets are given in row-column scan order for a given 2x2 color pattern.</p> 77 * 78 * @param destination an array big enough to hold at least {@value #COUNT} elements after the 79 * {@code offset} 80 * @param offset a non-negative offset into the array 81 * 82 * @throws IllegalArgumentException if the offset is invalid. 83 * @throws ArrayIndexOutOfBoundsException if the destination vector is too small. 84 * @throws NullPointerException if the destination is null. 85 */ copyTo(int[] destination, int offset)86 public void copyTo(int[] destination, int offset) { 87 checkNotNull(destination, "destination must not be null"); 88 if (offset < 0) { 89 throw new IllegalArgumentException("Null offset passed to copyTo"); 90 } 91 if (destination.length - offset < COUNT) { 92 throw new ArrayIndexOutOfBoundsException("destination too small to fit elements"); 93 } 94 for (int i = 0; i < COUNT; ++i) { 95 destination[offset + i] = mCfaOffsets[i]; 96 } 97 } 98 99 /** 100 * Check if this {@link BlackLevelPattern} is equal to another {@link BlackLevelPattern}. 101 * 102 * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p> 103 * 104 * @return {@code true} if the objects were equal, {@code false} otherwise 105 */ 106 @Override equals(Object obj)107 public boolean equals(Object obj) { 108 if (obj == null) { 109 return false; 110 } else if (this == obj) { 111 return true; 112 } else if (obj instanceof BlackLevelPattern) { 113 final BlackLevelPattern other = (BlackLevelPattern) obj; 114 return Arrays.equals(other.mCfaOffsets, mCfaOffsets); 115 } 116 return false; 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override hashCode()123 public int hashCode() { 124 return Arrays.hashCode(mCfaOffsets); 125 } 126 127 /** 128 * Return this {@link BlackLevelPattern} as a string representation. 129 * 130 * <p> {@code "BlackLevelPattern([%d, %d], [%d, %d])"}, where each {@code %d} represents one 131 * black level offset of a color channel. The values are in the same order as channels listed 132 * for the CFA layout key (see 133 * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}). 134 * </p> 135 * 136 * @return string representation of {@link BlackLevelPattern} 137 * 138 * @see android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT 139 */ 140 @Override toString()141 public String toString() { 142 return String.format("BlackLevelPattern([%d, %d], [%d, %d])", mCfaOffsets[0], 143 mCfaOffsets[1], mCfaOffsets[2], mCfaOffsets[3]); 144 } 145 146 private final int[] mCfaOffsets; 147 } 148