• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 com.android.camera.one.v2.common;
18 
19 import android.graphics.Rect;
20 
21 import com.android.camera.one.OneCameraAccessException;
22 import com.android.camera.one.OneCameraCharacteristics;
23 import com.android.camera.util.AspectRatio;
24 import com.android.camera.util.Size;
25 import com.google.common.base.Objects;
26 import com.google.common.base.Preconditions;
27 
28 import java.util.List;
29 
30 import javax.annotation.Nonnull;
31 import javax.annotation.ParametersAreNonnullByDefault;
32 
33 /**
34  * Selects the optimal picture size and crop for a particular target size.
35  * <p>
36  * A particular camera2 device will support a finite set of output resolutions.
37  * However, we may wish to take pictures with a size that is not directly
38  * supported.
39  * <p>
40  * For example, we may wish to use a large 4:3 output size to capture
41  * as-large-as-possible 16:9 images. This requires determining the smallest
42  * output size which can contain the target size, and then computing the
43  * appropriate crop region.
44  */
45 @ParametersAreNonnullByDefault
46 public final class PictureSizeCalculator {
47     private final OneCameraCharacteristics mCameraCharacteristics;
48 
PictureSizeCalculator(OneCameraCharacteristics cameraCharacteristics)49     public PictureSizeCalculator(OneCameraCharacteristics cameraCharacteristics) {
50         mCameraCharacteristics = cameraCharacteristics;
51     }
52 
53     public static final class Configuration {
54         private final Size mSize;
55         private final Rect mPostCrop;
56 
Configuration(Size size, Rect postCrop)57         private Configuration(Size size, Rect postCrop) {
58             mSize = size;
59             mPostCrop = postCrop;
60         }
61 
62         /**
63          * @return The crop to be applied to Images returned from the camera
64          *         device.
65          */
getPostCaptureCrop()66         public Rect getPostCaptureCrop() {
67             return mPostCrop;
68         }
69 
70         /**
71          * @return The best natively-supported size to use.
72          */
getNativeOutputSize()73         public Size getNativeOutputSize() {
74             return mSize;
75         }
76 
77         @Override
toString()78         public String toString() {
79             return Objects.toStringHelper("PictureSizeCalculator.Configuration")
80                     .add("native size", mSize)
81                     .add("crop", mPostCrop)
82                     .toString();
83         }
84 
85         @Override
equals(Object o)86         public boolean equals(Object o) {
87             if (this == o) {
88                 return true;
89             } else if (!(o instanceof Configuration)) {
90                 return false;
91             }
92 
93             Configuration that = (Configuration) o;
94 
95             if (!mPostCrop.equals(that.mPostCrop)) {
96                 return false;
97             } else if (!mSize.equals(that.mSize)) {
98                 return false;
99             }
100 
101             return true;
102         }
103 
104         @Override
hashCode()105         public int hashCode() {
106             return Objects.hashCode(mSize, mPostCrop);
107         }
108     }
109 
110     @Nonnull
getSmallestSupportedSizeContainingTarget(List<Size> supported, Size target)111     private Size getSmallestSupportedSizeContainingTarget(List<Size> supported, Size target) {
112         Preconditions.checkState(!supported.isEmpty());
113         Size best = null;
114         long bestArea = Long.MAX_VALUE;
115         for (Size candidate : supported) {
116             long pixels = candidate.area();
117             if (candidate.getWidth() >= target.getWidth() &&
118                     candidate.getHeight() >= target.getHeight() &&
119                     pixels < bestArea) {
120                 best = candidate;
121                 bestArea = pixels;
122             }
123         }
124 
125         if (best == null) {
126             // If no supported sizes contain the target size, then select the
127             // largest one.
128             best = getLargestSupportedSize(supported);
129         }
130 
131         return best;
132     }
133 
134     /**
135      * A picture size Configuration consists of a device-supported size and a
136      * crop-region to apply to images retrieved from the device. The combination
137      * of these should achieve the desired image size specified in
138      * {@link #computeConfiguration}.
139      *
140      * @return The optimal configuration of device-supported picture size and
141      *         post-capture crop region to use.
142      * @throws com.android.camera.one.OneCameraAccessException if a
143      *             configuration could not be computed.
144      */
computeConfiguration(Size targetSize, int imageFormat)145     public Configuration computeConfiguration(Size targetSize, int imageFormat)
146             throws OneCameraAccessException {
147         List<Size> supportedPictureSizes = mCameraCharacteristics
148                 .getSupportedPictureSizes(imageFormat);
149         if (supportedPictureSizes.isEmpty()) {
150             throw new OneCameraAccessException("No picture sizes supported for format: "
151                     + imageFormat);
152         }
153         Size size = getSmallestSupportedSizeContainingTarget(supportedPictureSizes, targetSize);
154         Rect cropRegion = getPostCrop(AspectRatio.of(targetSize), size);
155         return new Configuration(size, cropRegion);
156     }
157 
158     @Nonnull
getLargestSupportedSize(List<Size> supported)159     private Size getLargestSupportedSize(List<Size> supported) {
160         Preconditions.checkState(!supported.isEmpty());
161         Size largestSize = supported.get(0);
162         long largestArea = largestSize.area();
163         for (Size candidate : supported) {
164             long area = candidate.area();
165             if (area > largestArea) {
166                 largestSize = candidate;
167             }
168         }
169         return largestSize;
170     }
171 
getPostCrop(AspectRatio targetAspect, Size actualSize)172     private Rect getPostCrop(AspectRatio targetAspect, Size actualSize) {
173         return targetAspect.getLargestCenterCrop(actualSize);
174     }
175 }
176