1b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin/*
2b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Copyright (C) 2014 The Android Open Source Project
3b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *
4b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Licensed under the Apache License, Version 2.0 (the "License");
5b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * you may not use this file except in compliance with the License.
6b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * You may obtain a copy of the License at
7b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *
8b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *      http://www.apache.org/licenses/LICENSE-2.0
9b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *
10b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Unless required by applicable law or agreed to in writing, software
11b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * distributed under the License is distributed on an "AS IS" BASIS,
12b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * See the License for the specific language governing permissions and
14b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * limitations under the License.
15b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */
16b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
1772f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinpackage android.hardware.camera2.params;
18b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
19b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkinimport static com.android.internal.util.Preconditions.*;
203c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkin
2172f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.hardware.camera2.CameraMetadata;
223c40a046cf0ea7b6af01ec93e5276eccb3234bfeIgor Murashkinimport android.hardware.camera2.utils.HashCodeHelpers;
2372f9f0a96e4476ef231d5001cb30521ad4ce5b1eIgor Murashkinimport android.util.Rational;
24b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
25b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkinimport java.util.Arrays;
26b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
27b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin/**
28b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * Immutable class for describing a 3x3 matrix of {@link Rational} values in row-major order.
29b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *
30b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * <p>This matrix maps a transform from one color space to another. For the particular color space
31b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * source and target, see the appropriate camera metadata documentation for the key that provides
32b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * this value.</p>
33b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin *
34b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin * @see CameraMetadata
35b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin */
36b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkinpublic final class ColorSpaceTransform {
37b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
38b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** The number of rows in this matrix. */
39b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int ROWS = 3;
40b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
41b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** The number of columns in this matrix. */
42b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int COLUMNS = 3;
43b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
44b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** The number of total Rational elements in this matrix. */
45b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int COUNT = ROWS * COLUMNS;
46b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
47b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** Number of int elements in a rational. */
48b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int RATIONAL_SIZE = 2;
49b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
50b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** Numerator offset inside a rational (pair). */
51b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int OFFSET_NUMERATOR = 0;
52b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
53b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** Denominator offset inside a rational (pair). */
54b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int OFFSET_DENOMINATOR = 1;
55b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
56b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /** Number of int elements in this matrix. */
57b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;
58b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
59b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
60b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
61b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
62b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>The elements must be stored in a row-major order.</p>
63b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
64b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param elements An array of {@code 9} elements
65b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
66b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws IllegalArgumentException
67b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *            if the count of {@code elements} is not {@code 9}
68b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws NullPointerException
69b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *            if {@code elements} or any sub-element is {@code null}
70b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
71b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public ColorSpaceTransform(Rational[] elements) {
72b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
73b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkNotNull(elements, "elements must not be null");
74b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (elements.length != COUNT) {
75b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new IllegalArgumentException("elements must be " + COUNT + " length");
76b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
77b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
78b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        mElements = new int[COUNT_INT];
79b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
80b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        for (int i = 0; i < elements.length; ++i) {
81b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            checkNotNull(elements, "element[" + i + "] must not be null");
82b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
83b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
84b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
85b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
86b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
87b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
88b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
89b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
90b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>The elements must be stored in a row-major order. Each rational is stored
91b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * contiguously as a {@code (numerator, denominator)} pair.</p>
92b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
93b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>In particular:<pre>{@code
94b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * int[] elements = new int[
95b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *     N11, D11, N12, D12, N13, D13,
96b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *     N21, D21, N22, D22, N23, D23,
97b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *     N31, D31, N32, D32, N33, D33
98b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * ];
99b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
100b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * new ColorSpaceTransform(elements)}</pre>
101b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
102b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
103b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * column {@code j}.</p>
104b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
105b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param elements An array of {@code 18} elements
106b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
107b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws IllegalArgumentException
108b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *            if the count of {@code elements} is not {@code 18}
109b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws NullPointerException
110b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *            if {@code elements} is {@code null}
111b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
112b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public ColorSpaceTransform(int[] elements) {
113b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkNotNull(elements, "elements must not be null");
114b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (elements.length != COUNT_INT) {
115b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
116b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
117b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
118b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        for (int i = 0; i < elements.length; ++i) {
119b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            checkNotNull(elements, "element " + i + " must not be null");
120b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
121b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
122b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        mElements = Arrays.copyOf(elements, elements.length);
123b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
124b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
125b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
126b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Get an element of this matrix by its row and column.
127b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
128b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>The rows must be within the range [0, 3),
129b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * and the column must be within the range [0, 3).</p>
130b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
131b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @return element (non-{@code null})
132b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
133b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws IllegalArgumentException if column or row was out of range
134b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
135b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public Rational getElement(int column, int row) {
136b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (column < 0 || column >= COLUMNS) {
137b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new IllegalArgumentException("column out of range");
138b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        } else if (row < 0 || row >= ROWS) {
139b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new IllegalArgumentException("row out of range");
140b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
141b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
142884cddcdf46235c1fd205b65623ca7850b607b1cYin-Chia Yeh        int numerator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_NUMERATOR];
143884cddcdf46235c1fd205b65623ca7850b607b1cYin-Chia Yeh        int denominator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_DENOMINATOR];
144b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
145b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        return new Rational(numerator, denominator);
146b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
147b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
148b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
149b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
150b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
151b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param destination
152b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          an array big enough to hold at least {@code 9} elements after the
153b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          {@code offset}
154b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param offset
155b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          a non-negative offset into the array
156b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws NullPointerException
157b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          If {@code destination} was {@code null}
158b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws ArrayIndexOutOfBoundsException
159b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          If there's not enough room to write the elements at the specified destination and
160b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          offset.
161b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
162b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public void copyElements(Rational[] destination, int offset) {
163b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkArgumentNonnegative(offset, "offset must not be negative");
164b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkNotNull(destination, "destination must not be null");
1652bb91a7a68e32530adf730deeef2fe95bad20a96Eino-Ville Talvala        if (destination.length - offset < COUNT) {
166b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
167b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
168b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
169b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
170b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            int numerator = mElements[j + OFFSET_NUMERATOR];
171b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            int denominator = mElements[j + OFFSET_DENOMINATOR];
172b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
173b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            destination[i + offset] = new Rational(numerator, denominator);
174b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
175b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
176b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
177b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
178b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Copy the {@link Rational} elements in row-major order from this matrix into the destination.
179b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
180b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>Each element is stored as a contiguous rational packed as a
181b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * {@code (numerator, denominator)} pair of ints, identical to the
182b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
183b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
184b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param destination
185b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          an array big enough to hold at least {@code 18} elements after the
186b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          {@code offset}
187b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @param offset
188b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          a non-negative offset into the array
189b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws NullPointerException
190b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          If {@code destination} was {@code null}
191b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @throws ArrayIndexOutOfBoundsException
192b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          If there's not enough room to write the elements at the specified destination and
193b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *          offset.
194b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
195b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @see ColorSpaceTransform#ColorSpaceTransform(int[])
196b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
197b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public void copyElements(int[] destination, int offset) {
198b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkArgumentNonnegative(offset, "offset must not be negative");
199b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        checkNotNull(destination, "destination must not be null");
2002bb91a7a68e32530adf730deeef2fe95bad20a96Eino-Ville Talvala        if (destination.length - offset < COUNT_INT) {
201b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
202b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
203b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
204b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        // Manual copy faster than System#arraycopy for very small loops
205b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        for (int i = 0; i < COUNT_INT; ++i) {
206b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            destination[i + offset] = mElements[i];
207b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
208b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
209b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
210b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
211b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
212b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
213b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * <p>Two color space transforms are equal if and only if all of their elements are
214b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * {@link Object#equals equal}.</p>
215b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     *
216b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * @return {@code true} if the objects were equal, {@code false} otherwise
217b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
218b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    @Override
219b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public boolean equals(final Object obj) {
220b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (obj == null) {
221b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            return false;
222b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
223b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (this == obj) {
224b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            return true;
225b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
226b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        if (obj instanceof ColorSpaceTransform) {
227b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin            final ColorSpaceTransform other = (ColorSpaceTransform) obj;
22897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
22997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int numerator = mElements[j + OFFSET_NUMERATOR];
23097376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int denominator = mElements[j + OFFSET_DENOMINATOR];
23197376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int numeratorOther = other.mElements[j + OFFSET_NUMERATOR];
23297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int denominatorOther = other.mElements[j + OFFSET_DENOMINATOR];
23397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                Rational r = new Rational(numerator, denominator);
23497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                Rational rOther = new Rational(numeratorOther, denominatorOther);
23597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                if (!r.equals(rOther)) {
23697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                    return false;
23797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                }
23897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            }
23997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            return true;
240b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        }
241b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        return false;
242b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
243b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
244b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    /**
245b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     * {@inheritDoc}
246b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin     */
247b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    @Override
248b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    public int hashCode() {
249b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin        return HashCodeHelpers.hashCode(mElements);
250b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    }
251b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin
25297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    /**
25397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * Return the color space transform as a string representation.
25497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *
25597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *  <p> Example:
25697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * {@code "ColorSpaceTransform([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an
25797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * identity transform. Elements are printed in row major order. </p>
25897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *
25997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * @return string representation of color space transform
26097376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     */
26197376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    @Override
26297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    public String toString() {
26397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        return String.format("ColorSpaceTransform%s", toShortString());
26497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    }
26597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh
26697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    /**
26797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * Return the color space transform as a compact string representation.
26897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *
26997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *  <p> Example:
27097376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * {@code "([1/1, 0/1, 0/1], [0/1, 1/1, 0/1], [0/1, 0/1, 1/1])"} is an identity transform.
27197376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * Elements are printed in row major order. </p>
27297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     *
27397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     * @return compact string representation of color space transform
27497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh     */
27597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    private String toShortString() {
27697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        StringBuilder sb = new StringBuilder("(");
27797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        for (int row = 0, i = 0; row < ROWS; row++) {
27897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            sb.append("[");
27997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            for (int col = 0; col < COLUMNS; col++, i += RATIONAL_SIZE) {
28097376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int numerator = mElements[i + OFFSET_NUMERATOR];
28197376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                int denominator = mElements[i + OFFSET_DENOMINATOR];
28297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                sb.append(numerator);
28397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                sb.append("/");
28497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                sb.append(denominator);
28597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                if (col < COLUMNS - 1) {
28697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                    sb.append(", ");
28797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                }
28897376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            }
28997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            sb.append("]");
29097376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            if (row < ROWS - 1) {
29197376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh                sb.append(", ");
29297376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh            }
29397376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        }
29497376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        sb.append(")");
29597376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh        return sb.toString();
29697376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh    }
29797376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh
298b3a78b2ca9655396e2d73950221d187b7e5bb3baIgor Murashkin    private final int[] mElements;
29997376d90d660254a934fab7708198d53f03fe2e4Yin-Chia Yeh}
300