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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 
22 import java.util.Arrays;
23 import java.util.Objects;
24 
25 /**
26  * Immutable class to store a 4-element vector of integers corresponding to a 2x2 pattern
27  * of color channel offsets used for the black level offsets of each color channel.
28  *
29  * For a camera device with
30  * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME
31  * MONOCHROME} capability, all 4 elements of the pattern will have the same value.
32  */
33 public final class BlackLevelPattern {
34 
35     /**
36      * The number of offsets in this vector.
37      */
38     public static final int COUNT = 4;
39 
40     /**
41      * Create a new {@link BlackLevelPattern} from a given offset array.
42      *
43      * <p>The given offset array must contain offsets for each color channel in
44      * a 2x2 pattern corresponding to the color filter arrangement.  Offsets are
45      * given in row-column scan order.</p>
46      *
47      * <p>This constructor is public to allow for easier application testing by
48      * creating custom object instances. It's not necessary to construct these
49      * objects during normal use of the camera API.</p>
50      *
51      * @param offsets an array containing a 2x2 pattern of offsets.
52      *
53      * @throws IllegalArgumentException if the given array has an incorrect length.
54      * @throws NullPointerException if the given array is null.
55      */
BlackLevelPattern(@onNull int[] offsets)56     public BlackLevelPattern(@NonNull int[] offsets) {
57         if (offsets == null) {
58             throw new NullPointerException("Null offsets array passed to constructor");
59         }
60         if (offsets.length < COUNT) {
61             throw new IllegalArgumentException("Invalid offsets array length");
62         }
63         mCfaOffsets = Arrays.copyOf(offsets, COUNT);
64     }
65 
66     /**
67      * Return the color channel offset for a given index into the array of raw pixel values.
68      *
69      * @param column the column index in the the raw pixel array.
70      * @param row the row index in the raw pixel array.
71      * @return a color channel offset.
72      *
73      * @throws IllegalArgumentException if a column or row given is negative.
74      */
getOffsetForIndex(int column, int row)75     public int getOffsetForIndex(int column, int row) {
76         if (row < 0 || column < 0) {
77             throw new IllegalArgumentException("column, row arguments must be positive");
78         }
79         return mCfaOffsets[((row & 1) << 1) | (column & 1)];
80     }
81 
82     /**
83      * Copy the ColorChannel offsets into the destination vector.
84      *
85      * <p>Offsets are given in row-column scan order for a given 2x2 color pattern.</p>
86      *
87      * @param destination an array big enough to hold at least {@value #COUNT} elements after the
88      *          {@code offset}
89      * @param offset a non-negative offset into the array
90      *
91      * @throws IllegalArgumentException if the offset is invalid.
92      * @throws ArrayIndexOutOfBoundsException if the destination vector is too small.
93      * @throws NullPointerException if the destination is null.
94      */
copyTo(int[] destination, int offset)95     public void copyTo(int[] destination, int offset) {
96         Objects.requireNonNull(destination, "destination must not be null");
97         if (offset < 0) {
98             throw new IllegalArgumentException("Null offset passed to copyTo");
99         }
100         if (destination.length - offset < COUNT) {
101             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
102         }
103         for (int i = 0; i < COUNT; ++i) {
104             destination[offset + i] = mCfaOffsets[i];
105         }
106     }
107 
108     /**
109      * Check if this {@link BlackLevelPattern} is equal to another {@link BlackLevelPattern}.
110      *
111      * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
112      *
113      * @return {@code true} if the objects were equal, {@code false} otherwise
114      */
115     @Override
equals(@ullable Object obj)116     public boolean equals(@Nullable Object obj) {
117         if (obj == null) {
118             return false;
119         } else if (this == obj) {
120             return true;
121         } else if (obj instanceof BlackLevelPattern) {
122             final BlackLevelPattern other = (BlackLevelPattern) obj;
123             return Arrays.equals(other.mCfaOffsets, mCfaOffsets);
124         }
125         return false;
126     }
127 
128     /**
129      * {@inheritDoc}
130      */
131     @Override
hashCode()132     public int hashCode() {
133         return Arrays.hashCode(mCfaOffsets);
134     }
135 
136     /**
137      * Return this {@link BlackLevelPattern} as a string representation.
138      *
139      * <p> {@code "BlackLevelPattern([%d, %d], [%d, %d])"}, where each {@code %d} represents one
140      * black level offset of a color channel. The values are in the same order as channels listed
141      * for the CFA layout key (see
142      * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}).
143      * </p>
144      *
145      * <p>A {@link
146      * android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME
147      * MONOCHROME} camera only has one channel. As a result, the returned string will contain 4
148      * identical values.
149      * </p>
150      *
151      * @return string representation of {@link BlackLevelPattern}
152      *
153      * @see android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
154      */
155     @Override
toString()156     public String toString() {
157         return String.format("BlackLevelPattern([%d, %d], [%d, %d])", mCfaOffsets[0],
158                 mCfaOffsets[1], mCfaOffsets[2], mCfaOffsets[3]);
159     }
160 
161     private final int[] mCfaOffsets;
162 }
163