/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2.utils; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.camera2.CaptureRequest; import android.util.Rational; import android.util.Size; import static com.android.internal.util.Preconditions.*; /** * Various assortment of params utilities. */ public class ParamsUtils { /** Arbitrary denominator used to estimate floats as rationals */ private static final int RATIONAL_DENOMINATOR = 1000000; // 1million /** * Create a {@link Rect} from a {@code Size} by creating a new rectangle with * left, top = {@code (0, 0)} and right, bottom = {@code (width, height)} * * @param size a non-{@code null} size * * @return a {@code non-null} rectangle * * @throws NullPointerException if {@code size} was {@code null} */ public static Rect createRect(Size size) { checkNotNull(size, "size must not be null"); return new Rect(/*left*/0, /*top*/0, size.getWidth(), size.getHeight()); } /** * Create a {@link Rect} from a {@code RectF} by creating a new rectangle with * each corner (left, top, right, bottom) rounded towards the nearest integer bounding box. * *

In particular (left, top) is floored, and (right, bottom) is ceiled.

* * @param size a non-{@code null} rect * * @return a {@code non-null} rectangle * * @throws NullPointerException if {@code rect} was {@code null} */ public static Rect createRect(RectF rect) { checkNotNull(rect, "rect must not be null"); Rect r = new Rect(); rect.roundOut(r); return r; } /** * Map the rectangle in {@code rect} with the transform in {@code transform} into * a new rectangle, with each corner (left, top, right, bottom) rounded towards the nearest * integer bounding box. * *

None of the arguments are mutated.

* * @param transform a non-{@code null} transformation matrix * @param rect a non-{@code null} rectangle * @return a new rectangle that was transformed by {@code transform} * * @throws NullPointerException if any of the args were {@code null} */ public static Rect mapRect(Matrix transform, Rect rect) { checkNotNull(transform, "transform must not be null"); checkNotNull(rect, "rect must not be null"); RectF rectF = new RectF(rect); transform.mapRect(rectF); return createRect(rectF); } /** * Create a {@link Size} from a {@code Rect} by creating a new size whose width * and height are the same as the rectangle's width and heights. * * @param rect a non-{@code null} rectangle * * @return a {@code non-null} size * * @throws NullPointerException if {@code rect} was {@code null} */ public static Size createSize(Rect rect) { checkNotNull(rect, "rect must not be null"); return new Size(rect.width(), rect.height()); } /** * Create a {@link Rational} value by approximating the float value as a rational. * *

Floating points too large to be represented as an integer will be converted to * to {@link Integer#MAX_VALUE}; floating points too small to be represented as an integer * will be converted to {@link Integer#MIN_VALUE}.

* * @param value a floating point value * @return the rational representation of the float */ public static Rational createRational(float value) { if (Float.isNaN(value)) { return Rational.NaN; } else if (value == Float.POSITIVE_INFINITY) { return Rational.POSITIVE_INFINITY; } else if (value == Float.NEGATIVE_INFINITY) { return Rational.NEGATIVE_INFINITY; } else if (value == 0.0f) { return Rational.ZERO; } // normal finite value: approximate it /* * Start out trying to approximate with denominator = 1million, * but if the numerator doesn't fit into an Int then keep making the denominator * smaller until it does. */ int den = RATIONAL_DENOMINATOR; float numF; do { numF = value * den; if ((numF > Integer.MIN_VALUE && numF < Integer.MAX_VALUE) || (den == 1)) { break; } den /= 10; } while (true); /* * By float -> int narrowing conversion in JLS 5.1.3, this will automatically become * MIN_VALUE or MAX_VALUE if numF is too small/large to be represented by an integer */ int num = (int) numF; return new Rational(num, den); } /** * Convert an integral rectangle ({@code source}) to a floating point rectangle * ({@code destination}) in-place. * * @param source the originating integer rectangle will be read from here * @param destination the resulting floating point rectangle will be written out to here * * @throws NullPointerException if {@code rect} was {@code null} */ public static void convertRectF(Rect source, RectF destination) { checkNotNull(source, "source must not be null"); checkNotNull(destination, "destination must not be null"); destination.left = source.left; destination.right = source.right; destination.bottom = source.bottom; destination.top = source.top; } /** * Return the value set by the key, or the {@code defaultValue} if no value was set. * * @throws NullPointerException if any of the args were {@code null} */ public static T getOrDefault(CaptureRequest r, CaptureRequest.Key key, T defaultValue) { checkNotNull(r, "r must not be null"); checkNotNull(key, "key must not be null"); checkNotNull(defaultValue, "defaultValue must not be null"); T value = r.get(key); if (value == null) { return defaultValue; } else { return value; } } private ParamsUtils() { throw new AssertionError(); } }