152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk/*
252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * Copyright (C) 2014 The Android Open Source Project
352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk *
452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * you may not use this file except in compliance with the License.
652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * You may obtain a copy of the License at
752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk *
852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk *
1052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * Unless required by applicable law or agreed to in writing, software
1152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
1252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * See the License for the specific language governing permissions and
1452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * limitations under the License.
1552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk */
1652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
1752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunkpackage android.hardware.camera2.params;
1852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
1952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunkimport java.util.Arrays;
2052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
2152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunkimport static com.android.internal.util.Preconditions.checkNotNull;
2252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
2352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk/**
2452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * Immutable class to store a 4-element vector of integers corresponding to a 2x2 pattern
2552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk * of color channel offsets used for the black level offsets of each color channel.
2652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk */
2752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunkpublic final class BlackLevelPattern {
2852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
2952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
3052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * The number of offsets in this vector.
3152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
3252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public static final int COUNT = 4;
3352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
3452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
3552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * Create a new {@link BlackLevelPattern} from a given offset array.
3652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
3752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * <p>The given offset array must contain offsets for each color channel in
3852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * a 2x2 pattern corresponding to the color filter arrangement.  Offsets are
3952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * given in row-column scan order.</p>
4052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
4152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @param offsets an array containing a 2x2 pattern of offsets.
4252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
4352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws IllegalArgumentException if the given array has an incorrect length.
4452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws NullPointerException if the given array is null.
4552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @hide
4652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
4752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public BlackLevelPattern(int[] offsets) {
4852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (offsets == null) {
4952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            throw new NullPointerException("Null offsets array passed to constructor");
5052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
5152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (offsets.length < COUNT) {
5252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            throw new IllegalArgumentException("Invalid offsets array length");
5352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
5452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        mCfaOffsets = Arrays.copyOf(offsets, COUNT);
5552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    }
5652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
5752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
5852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * Return the color channel offset for a given index into the array of raw pixel values.
5952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
6052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @param column the column index in the the raw pixel array.
6152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @param row the row index in the raw pixel array.
6252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @return a color channel offset.
6352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
6452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws IllegalArgumentException if a column or row given is negative.
6552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
6652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public int getOffsetForIndex(int column, int row) {
6752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (row < 0 || column < 0) {
6852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            throw new IllegalArgumentException("column, row arguments must be positive");
6952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
7052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        return mCfaOffsets[((row & 1) << 1) | (column & 1)];
7152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    }
7252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
7352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
7452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * Copy the ColorChannel offsets into the destination vector.
7552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
7652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * <p>Offsets are given in row-column scan order for a given 2x2 color pattern.</p>
7752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
7852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @param destination an array big enough to hold at least {@value #COUNT} elements after the
7952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *          {@code offset}
8052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @param offset a non-negative offset into the array
8152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
8252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws IllegalArgumentException if the offset is invalid.
8352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws ArrayIndexOutOfBoundsException if the destination vector is too small.
8452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @throws NullPointerException if the destination is null.
8552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
8652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public void copyTo(int[] destination, int offset) {
8752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        checkNotNull(destination, "destination must not be null");
8852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (offset < 0) {
8952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            throw new IllegalArgumentException("Null offset passed to copyTo");
9052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
9152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (destination.length - offset < COUNT) {
9252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
9352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
9452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        for (int i = 0; i < COUNT; ++i) {
9552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            destination[offset + i] = mCfaOffsets[i];
9652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
9752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    }
9852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
9952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
10052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * Check if this {@link BlackLevelPattern} is equal to another {@link BlackLevelPattern}.
10152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
10252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * <p>Two vectors are only equal if and only if each of the respective elements is equal.</p>
10352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     *
10452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * @return {@code true} if the objects were equal, {@code false} otherwise
10552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
10652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    @Override
10752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public boolean equals(Object obj) {
10852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        if (obj == null) {
10952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            return false;
11052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        } else if (this == obj) {
11152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            return true;
11252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        } else if (obj instanceof BlackLevelPattern) {
11352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            final BlackLevelPattern other = (BlackLevelPattern) obj;
11452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk            return Arrays.equals(other.mCfaOffsets, mCfaOffsets);
11552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        }
11652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        return false;
11752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    }
11852842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
11952842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    /**
12052842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     * {@inheritDoc}
12152842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk     */
12252842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    @Override
12352842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    public int hashCode() {
12452842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk        return Arrays.hashCode(mCfaOffsets);
12552842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    }
12652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk
127310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen    /**
128310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * Return this {@link BlackLevelPattern} as a string representation.
129310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     *
130310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * <p> {@code "BlackLevelPattern([%d, %d], [%d, %d])"}, where each {@code %d} represents one
131310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * black level offset of a color channel. The values are in the same order as channels listed
132310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * for the CFA layout key (see
133310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * {@link android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT}).
134310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * </p>
135310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     *
136310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * @return string representation of {@link BlackLevelPattern}
137310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     *
138310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     * @see android.hardware.camera2.CameraCharacteristics#SENSOR_INFO_COLOR_FILTER_ARRANGEMENT
139310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen     */
140310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen    @Override
141310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen    public String toString() {
142310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen        return String.format("BlackLevelPattern([%d, %d], [%d, %d])", mCfaOffsets[0],
143310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen                mCfaOffsets[1], mCfaOffsets[2], mCfaOffsets[3]);
144310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen    }
145310f381eac558bce069b52fbda9a8aeb83608858Chien-Yu Chen
14652842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk    private final int[] mCfaOffsets;
14752842e7a6f0e922185db04ae8b91c776a234acf1Ruben Brunk}
148