Home | History | Annotate | Download | only in params
      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 static com.android.internal.util.Preconditions.*;
     20 
     21 import android.hardware.camera2.CameraMetadata;
     22 import android.hardware.camera2.utils.HashCodeHelpers;
     23 import android.util.Rational;
     24 
     25 import java.util.Arrays;
     26 
     27 /**
     28  * Immutable class for describing a 3x3 matrix of {@link Rational} values in row-major order.
     29  *
     30  * <p>This matrix maps a transform from one color space to another. For the particular color space
     31  * source and target, see the appropriate camera metadata documentation for the key that provides
     32  * this value.</p>
     33  *
     34  * @see CameraMetadata
     35  */
     36 public final class ColorSpaceTransform {
     37 
     38     /** The number of rows in this matrix. */
     39     private static final int ROWS = 3;
     40 
     41     /** The number of columns in this matrix. */
     42     private static final int COLUMNS = 3;
     43 
     44     /** The number of total Rational elements in this matrix. */
     45     private static final int COUNT = ROWS * COLUMNS;
     46 
     47     /** Number of int elements in a rational. */
     48     private static final int RATIONAL_SIZE = 2;
     49 
     50     /** Numerator offset inside a rational (pair). */
     51     private static final int OFFSET_NUMERATOR = 0;
     52 
     53     /** Denominator offset inside a rational (pair). */
     54     private static final int OFFSET_DENOMINATOR = 1;
     55 
     56     /** Number of int elements in this matrix. */
     57     private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;
     58 
     59     /**
     60      * Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
     61      *
     62      * <p>The elements must be stored in a row-major order.</p>
     63      *
     64      * @param elements An array of {@code 9} elements
     65      *
     66      * @throws IllegalArgumentException
     67      *            if the count of {@code elements} is not {@code 9}
     68      * @throws NullPointerException
     69      *            if {@code elements} or any sub-element is {@code null}
     70      */
     71     public ColorSpaceTransform(Rational[] elements) {
     72 
     73         checkNotNull(elements, "elements must not be null");
     74         if (elements.length != COUNT) {
     75             throw new IllegalArgumentException("elements must be " + COUNT + " length");
     76         }
     77 
     78         mElements = new int[COUNT_INT];
     79 
     80         for (int i = 0; i < elements.length; ++i) {
     81             checkNotNull(elements, "element[" + i + "] must not be null");
     82             mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
     83             mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
     84         }
     85     }
     86 
     87     /**
     88      * Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
     89      *
     90      * <p>The elements must be stored in a row-major order. Each rational is stored
     91      * contiguously as a {@code (numerator, denominator)} pair.</p>
     92      *
     93      * <p>In particular:<pre>{@code
     94      * int[] elements = new int[
     95      *     N11, D11, N12, D12, N13, D13,
     96      *     N21, D21, N22, D22, N23, D23,
     97      *     N31, D31, N32, D32, N33, D33
     98      * ];
     99      *
    100      * new ColorSpaceTransform(elements)}</pre>
    101      *
    102      * where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
    103      * column {@code j}.</p>
    104      *
    105      * @param elements An array of {@code 18} elements
    106      *
    107      * @throws IllegalArgumentException
    108      *            if the count of {@code elements} is not {@code 18}
    109      * @throws NullPointerException
    110      *            if {@code elements} is {@code null}
    111      */
    112     public ColorSpaceTransform(int[] elements) {
    113         checkNotNull(elements, "elements must not be null");
    114         if (elements.length != COUNT_INT) {
    115             throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
    116         }
    117 
    118         for (int i = 0; i < elements.length; ++i) {
    119             checkNotNull(elements, "element " + i + " must not be null");
    120         }
    121 
    122         mElements = Arrays.copyOf(elements, elements.length);
    123     }
    124 
    125     /**
    126      * Get an element of this matrix by its row and column.
    127      *
    128      * <p>The rows must be within the range [0, 3),
    129      * and the column must be within the range [0, 3).</p>
    130      *
    131      * @return element (non-{@code null})
    132      *
    133      * @throws IllegalArgumentException if column or row was out of range
    134      */
    135     public Rational getElement(int column, int row) {
    136         if (column < 0 || column >= COLUMNS) {
    137             throw new IllegalArgumentException("column out of range");
    138         } else if (row < 0 || row >= ROWS) {
    139             throw new IllegalArgumentException("row out of range");
    140         }
    141 
    142         int numerator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_NUMERATOR];
    143         int denominator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_DENOMINATOR];
    144 
    145         return new Rational(numerator, denominator);
    146     }
    147 
    148     /**
    149      * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
    150      *
    151      * @param destination
    152      *          an array big enough to hold at least {@code 9} elements after the
    153      *          {@code offset}
    154      * @param offset
    155      *          a non-negative offset into the array
    156      * @throws NullPointerException
    157      *          If {@code destination} was {@code null}
    158      * @throws ArrayIndexOutOfBoundsException
    159      *          If there's not enough room to write the elements at the specified destination and
    160      *          offset.
    161      */
    162     public void copyElements(Rational[] destination, int offset) {
    163         checkArgumentNonnegative(offset, "offset must not be negative");
    164         checkNotNull(destination, "destination must not be null");
    165         if (destination.length - offset < COUNT) {
    166             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
    167         }
    168 
    169         for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
    170             int numerator = mElements[j + OFFSET_NUMERATOR];
    171             int denominator = mElements[j + OFFSET_DENOMINATOR];
    172 
    173             destination[i + offset] = new Rational(numerator, denominator);
    174         }
    175     }
    176 
    177     /**
    178      * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
    179      *
    180      * <p>Each element is stored as a contiguous rational packed as a
    181      * {@code (numerator, denominator)} pair of ints, identical to the
    182      * {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
    183      *
    184      * @param destination
    185      *          an array big enough to hold at least {@code 18} elements after the
    186      *          {@code offset}
    187      * @param offset
    188      *          a non-negative offset into the array
    189      * @throws NullPointerException
    190      *          If {@code destination} was {@code null}
    191      * @throws ArrayIndexOutOfBoundsException
    192      *          If there's not enough room to write the elements at the specified destination and
    193      *          offset.
    194      *
    195      * @see ColorSpaceTransform#ColorSpaceTransform(int[])
    196      */
    197     public void copyElements(int[] destination, int offset) {
    198         checkArgumentNonnegative(offset, "offset must not be negative");
    199         checkNotNull(destination, "destination must not be null");
    200         if (destination.length - offset < COUNT_INT) {
    201             throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
    202         }
    203 
    204         // Manual copy faster than System#arraycopy for very small loops
    205         for (int i = 0; i < COUNT_INT; ++i) {
    206             destination[i + offset] = mElements[i];
    207         }
    208     }
    209 
    210     /**
    211      * Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
    212      *
    213      * <p>Two color space transforms are equal if and only if all of their elements are
    214      * {@link Object#equals equal}.</p>
    215      *
    216      * @return {@code true} if the objects were equal, {@code false} otherwise
    217      */
    218     @Override
    219     public boolean equals(final Object obj) {
    220         if (obj == null) {
    221             return false;
    222         }
    223         if (this == obj) {
    224             return true;
    225         }
    226         if (obj instanceof ColorSpaceTransform) {
    227             final ColorSpaceTransform other = (ColorSpaceTransform) obj;
    228             for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
    229                 int numerator = mElements[j + OFFSET_NUMERATOR];
    230                 int denominator = mElements[j + OFFSET_DENOMINATOR];
    231                 int numeratorOther = other.mElements[j + OFFSET_NUMERATOR];
    232                 int denominatorOther = other.mElements[j + OFFSET_DENOMINATOR];
    233                 Rational r = new Rational(numerator, denominator);
    234                 Rational rOther = new Rational(numeratorOther, denominatorOther);
    235                 if (!r.equals(rOther)) {
    236                     return false;
    237                 }
    238             }
    239             return true;
    240         }
    241         return false;
    242     }
    243 
    244     /**
    245      * {@inheritDoc}
    246      */
    247     @Override
    248     public int hashCode() {
    249         return HashCodeHelpers.hashCode(mElements);
    250     }
    251 
    252     /**
    253      * Return the color space transform as a string representation.
    254      *
    255      *  <p> Example:
    256      * {@code "ColorSpaceTransform([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an
    257      * identity transform. Elements are printed in row major order. </p>
    258      *
    259      * @return string representation of color space transform
    260      */
    261     @Override
    262     public String toString() {
    263         return String.format("ColorSpaceTransform%s", toShortString());
    264     }
    265 
    266     /**
    267      * Return the color space transform as a compact string representation.
    268      *
    269      *  <p> Example:
    270      * {@code "([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an identity transform.
    271      * Elements are printed in row major order. </p>
    272      *
    273      * @return compact string representation of color space transform
    274      */
    275     private String toShortString() {
    276         StringBuilder sb = new StringBuilder("(");
    277         for (int row = 0, i = 0; row < ROWS; row++) {
    278             sb.append("[");
    279             for (int col = 0; col < COLUMNS; col++, i += RATIONAL_SIZE) {
    280                 int numerator = mElements[i + OFFSET_NUMERATOR];
    281                 int denominator = mElements[i + OFFSET_DENOMINATOR];
    282                 sb.append(numerator);
    283                 sb.append("/");
    284                 sb.append(denominator);
    285                 if (col < COLUMNS - 1) {
    286                     sb.append(", ");
    287                 }
    288             }
    289             sb.append("]");
    290             if (row < ROWS - 1) {
    291                 sb.append(", ");
    292             }
    293         }
    294         sb.append(")");
    295         return sb.toString();
    296     }
    297 
    298     private final int[] mElements;
    299 }
    300