1/*
2 * Copyright (C) 2013 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
17package com.android.bitmap.util;
18
19import android.graphics.Rect;
20
21public abstract class BitmapUtils {
22
23    /**
24     * Calculate a rectangle for the given input and output parameters. The output
25     * rectangle to use is written in the given outRect.
26     *
27     * @param srcW the source width
28     * @param srcH the source height
29     * @param dstW the destination width
30     * @param dstH the destination height
31     * @param dstSliceH the height extent (in destination coordinates) to
32     *            exclude when cropping. You would typically pass dstH, unless
33     *            you are trying to normalize different items to the same
34     *            vertical crop range.
35     * @param sampleSize a scaling factor that rect calculation will only use if
36     *            it's more aggressive than regular scaling
37     * @param horizSliceFrac horizontal slice fraction determines the horizontal
38     *            center point for the crop rect. Range is from [0.0, 1.0]. To
39     *            perform a horizontally centered crop, use 0.5.
40     * @param vertSliceFrac vertical slice fraction determines the vertical
41     *            center point for the crop rect. Range is from [0.0, 1.0]. To
42     *            perform a vertically centered crop, use 0.5. Otherwise, see
43     *            absoluteFrac.
44     * @param absoluteFrac determines how the vertSliceFrac affects the vertical
45     *            center point. If this parameter is true, the vertical center
46     *            of the resulting output rectangle will be exactly
47     *            [vertSliceFrac * srcH], with care taken to keep the bounds
48     *            within the source rectangle. If this parameter is false, the
49     *            vertical center will be calculated so that the values of
50     *            vertSliceFrac from 0.0 to 1.0 will linearly cover the entirety
51     *            of the source rectangle.
52     * @param verticalMultiplier an optional multiplier that will alter the
53     *            output Rect's aspect ratio to be this much taller in the event
54     *            that y is the limiting dimension
55     * @param outRect a Rect to write the resulting crop coordinates into
56     */
57    public static void calculateCroppedSrcRect(final int srcW, final int srcH, final int dstW,
58            final int dstH, final int dstSliceH, int sampleSize, final float horizSliceFrac,
59            final float vertSliceFrac, final boolean absoluteFrac, final float verticalMultiplier,
60            final Rect outRect) {
61        if (sampleSize < 1) {
62            sampleSize = 1;
63        }
64        final float regularScale;
65        final float wScale = (float) srcW / dstW;
66        final float hScale = (float) srcH / dstH;
67        if (hScale < wScale) {
68            regularScale = hScale / verticalMultiplier;
69        } else {
70            regularScale = wScale;
71        }
72
73        final float scale = Math.min(sampleSize, regularScale);
74
75        final int srcCroppedW = Math.round(dstW * scale);
76        final int srcCroppedH = Math.round(dstH * scale);
77        final int srcCroppedSliceH = Math.round(dstSliceH * scale);
78        final int srcHalfSliceH = Math.min(srcCroppedSliceH, srcH) / 2;
79
80        outRect.left = (int) (horizSliceFrac * (srcW - srcCroppedW));
81        outRect.right = outRect.left + srcCroppedW;
82
83        final int centerV;
84        if (absoluteFrac) {
85            final int minCenterV = srcHalfSliceH;
86            final int maxCenterV = srcH - srcHalfSliceH;
87            centerV = Math.max(minCenterV, Math.min(maxCenterV, Math.round(srcH * vertSliceFrac)));
88        } else {
89            centerV = Math
90                    .round(Math.abs(srcH - srcCroppedSliceH) * vertSliceFrac + srcHalfSliceH);
91        }
92
93        outRect.top = centerV - srcCroppedH / 2;
94        outRect.bottom = outRect.top + srcCroppedH;
95    }
96
97    /**
98     * @param srcW
99     * @param srcH
100     * @param dstW
101     * @param dstH
102     * @param outRect
103     */
104    public static void calculateCroppedSrcRect(int srcW, int srcH, int dstW, int dstH,
105            Rect outRect) {
106        calculateCroppedSrcRect(srcW, srcH, dstW, dstH, Integer.MAX_VALUE, outRect);
107    }
108
109    public static void calculateCroppedSrcRect(int srcW, int srcH, int dstW, int dstH,
110            int sampleSize, Rect outRect) {
111        if (sampleSize < 1) {
112            sampleSize = 1;
113        }
114        final float regularScale = Math.min(
115                (float) srcW / dstW,
116                (float) srcH / dstH);
117
118        final float scale = Math.min(sampleSize, regularScale);
119
120        final int srcCroppedW = Math.round(dstW * scale);
121        final int srcCroppedH = Math.round(dstH * scale);
122
123        outRect.left = (srcW - srcCroppedW) / 2;
124        outRect.right = outRect.left + srcCroppedW;
125
126        outRect.top = (srcH - srcCroppedH) / 2;
127        outRect.bottom = outRect.top + srcCroppedH;
128    }
129}
130