blob: 976fa2e38007f300bf66f2f235f1191da008bf4b [file] [log] [blame]
/*
* 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.
*
* <p>In particular (left, top) is floored, and (right, bottom) is ceiled.</p>
*
* @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.
*
* <p>None of the arguments are mutated.</p>
*
* @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.
*
* <p>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}.</p>
*
* @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> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> 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();
}
}