Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright (C) 2013 Square, Inc. |
michael@0 | 3 | * |
michael@0 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
michael@0 | 5 | * you may not use this file except in compliance with the License. |
michael@0 | 6 | * You may obtain a copy of the License at |
michael@0 | 7 | * |
michael@0 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
michael@0 | 9 | * |
michael@0 | 10 | * Unless required by applicable law or agreed to in writing, software |
michael@0 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
michael@0 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
michael@0 | 13 | * See the License for the specific language governing permissions and |
michael@0 | 14 | * limitations under the License. |
michael@0 | 15 | */ |
michael@0 | 16 | package com.squareup.picasso; |
michael@0 | 17 | |
michael@0 | 18 | import android.net.Uri; |
michael@0 | 19 | import java.util.ArrayList; |
michael@0 | 20 | import java.util.List; |
michael@0 | 21 | |
michael@0 | 22 | import static java.util.Collections.unmodifiableList; |
michael@0 | 23 | |
michael@0 | 24 | /** Immutable data about an image and the transformations that will be applied to it. */ |
michael@0 | 25 | public final class Request { |
michael@0 | 26 | /** |
michael@0 | 27 | * The image URI. |
michael@0 | 28 | * <p> |
michael@0 | 29 | * This is mutually exclusive with {@link #resourceId}. |
michael@0 | 30 | */ |
michael@0 | 31 | public final Uri uri; |
michael@0 | 32 | /** |
michael@0 | 33 | * The image resource ID. |
michael@0 | 34 | * <p> |
michael@0 | 35 | * This is mutually exclusive with {@link #uri}. |
michael@0 | 36 | */ |
michael@0 | 37 | public final int resourceId; |
michael@0 | 38 | /** List of custom transformations to be applied after the built-in transformations. */ |
michael@0 | 39 | public final List<Transformation> transformations; |
michael@0 | 40 | /** Target image width for resizing. */ |
michael@0 | 41 | public final int targetWidth; |
michael@0 | 42 | /** Target image height for resizing. */ |
michael@0 | 43 | public final int targetHeight; |
michael@0 | 44 | /** |
michael@0 | 45 | * True if the final image should use the 'centerCrop' scale technique. |
michael@0 | 46 | * <p> |
michael@0 | 47 | * This is mutually exclusive with {@link #centerInside}. |
michael@0 | 48 | */ |
michael@0 | 49 | public final boolean centerCrop; |
michael@0 | 50 | /** |
michael@0 | 51 | * True if the final image should use the 'centerInside' scale technique. |
michael@0 | 52 | * <p> |
michael@0 | 53 | * This is mutually exclusive with {@link #centerCrop}. |
michael@0 | 54 | */ |
michael@0 | 55 | public final boolean centerInside; |
michael@0 | 56 | /** Amount to rotate the image in degrees. */ |
michael@0 | 57 | public final float rotationDegrees; |
michael@0 | 58 | /** Rotation pivot on the X axis. */ |
michael@0 | 59 | public final float rotationPivotX; |
michael@0 | 60 | /** Rotation pivot on the Y axis. */ |
michael@0 | 61 | public final float rotationPivotY; |
michael@0 | 62 | /** Whether or not {@link #rotationPivotX} and {@link #rotationPivotY} are set. */ |
michael@0 | 63 | public final boolean hasRotationPivot; |
michael@0 | 64 | |
michael@0 | 65 | private Request(Uri uri, int resourceId, List<Transformation> transformations, int targetWidth, |
michael@0 | 66 | int targetHeight, boolean centerCrop, boolean centerInside, float rotationDegrees, |
michael@0 | 67 | float rotationPivotX, float rotationPivotY, boolean hasRotationPivot) { |
michael@0 | 68 | this.uri = uri; |
michael@0 | 69 | this.resourceId = resourceId; |
michael@0 | 70 | if (transformations == null) { |
michael@0 | 71 | this.transformations = null; |
michael@0 | 72 | } else { |
michael@0 | 73 | this.transformations = unmodifiableList(transformations); |
michael@0 | 74 | } |
michael@0 | 75 | this.targetWidth = targetWidth; |
michael@0 | 76 | this.targetHeight = targetHeight; |
michael@0 | 77 | this.centerCrop = centerCrop; |
michael@0 | 78 | this.centerInside = centerInside; |
michael@0 | 79 | this.rotationDegrees = rotationDegrees; |
michael@0 | 80 | this.rotationPivotX = rotationPivotX; |
michael@0 | 81 | this.rotationPivotY = rotationPivotY; |
michael@0 | 82 | this.hasRotationPivot = hasRotationPivot; |
michael@0 | 83 | } |
michael@0 | 84 | |
michael@0 | 85 | String getName() { |
michael@0 | 86 | if (uri != null) { |
michael@0 | 87 | return uri.getPath(); |
michael@0 | 88 | } |
michael@0 | 89 | return Integer.toHexString(resourceId); |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | public boolean hasSize() { |
michael@0 | 93 | return targetWidth != 0; |
michael@0 | 94 | } |
michael@0 | 95 | |
michael@0 | 96 | boolean needsTransformation() { |
michael@0 | 97 | return needsMatrixTransform() || hasCustomTransformations(); |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | boolean needsMatrixTransform() { |
michael@0 | 101 | return targetWidth != 0 || rotationDegrees != 0; |
michael@0 | 102 | } |
michael@0 | 103 | |
michael@0 | 104 | boolean hasCustomTransformations() { |
michael@0 | 105 | return transformations != null; |
michael@0 | 106 | } |
michael@0 | 107 | |
michael@0 | 108 | public Builder buildUpon() { |
michael@0 | 109 | return new Builder(this); |
michael@0 | 110 | } |
michael@0 | 111 | |
michael@0 | 112 | /** Builder for creating {@link Request} instances. */ |
michael@0 | 113 | public static final class Builder { |
michael@0 | 114 | private Uri uri; |
michael@0 | 115 | private int resourceId; |
michael@0 | 116 | private int targetWidth; |
michael@0 | 117 | private int targetHeight; |
michael@0 | 118 | private boolean centerCrop; |
michael@0 | 119 | private boolean centerInside; |
michael@0 | 120 | private float rotationDegrees; |
michael@0 | 121 | private float rotationPivotX; |
michael@0 | 122 | private float rotationPivotY; |
michael@0 | 123 | private boolean hasRotationPivot; |
michael@0 | 124 | private List<Transformation> transformations; |
michael@0 | 125 | |
michael@0 | 126 | /** Start building a request using the specified {@link Uri}. */ |
michael@0 | 127 | public Builder(Uri uri) { |
michael@0 | 128 | setUri(uri); |
michael@0 | 129 | } |
michael@0 | 130 | |
michael@0 | 131 | /** Start building a request using the specified resource ID. */ |
michael@0 | 132 | public Builder(int resourceId) { |
michael@0 | 133 | setResourceId(resourceId); |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | Builder(Uri uri, int resourceId) { |
michael@0 | 137 | this.uri = uri; |
michael@0 | 138 | this.resourceId = resourceId; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | private Builder(Request request) { |
michael@0 | 142 | uri = request.uri; |
michael@0 | 143 | resourceId = request.resourceId; |
michael@0 | 144 | targetWidth = request.targetWidth; |
michael@0 | 145 | targetHeight = request.targetHeight; |
michael@0 | 146 | centerCrop = request.centerCrop; |
michael@0 | 147 | centerInside = request.centerInside; |
michael@0 | 148 | rotationDegrees = request.rotationDegrees; |
michael@0 | 149 | rotationPivotX = request.rotationPivotX; |
michael@0 | 150 | rotationPivotY = request.rotationPivotY; |
michael@0 | 151 | hasRotationPivot = request.hasRotationPivot; |
michael@0 | 152 | if (request.transformations != null) { |
michael@0 | 153 | transformations = new ArrayList<Transformation>(request.transformations); |
michael@0 | 154 | } |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | boolean hasImage() { |
michael@0 | 158 | return uri != null || resourceId != 0; |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | boolean hasSize() { |
michael@0 | 162 | return targetWidth != 0; |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | /** |
michael@0 | 166 | * Set the target image Uri. |
michael@0 | 167 | * <p> |
michael@0 | 168 | * This will clear an image resource ID if one is set. |
michael@0 | 169 | */ |
michael@0 | 170 | public Builder setUri(Uri uri) { |
michael@0 | 171 | if (uri == null) { |
michael@0 | 172 | throw new IllegalArgumentException("Image URI may not be null."); |
michael@0 | 173 | } |
michael@0 | 174 | this.uri = uri; |
michael@0 | 175 | this.resourceId = 0; |
michael@0 | 176 | return this; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | /** |
michael@0 | 180 | * Set the target image resource ID. |
michael@0 | 181 | * <p> |
michael@0 | 182 | * This will clear an image Uri if one is set. |
michael@0 | 183 | */ |
michael@0 | 184 | public Builder setResourceId(int resourceId) { |
michael@0 | 185 | if (resourceId == 0) { |
michael@0 | 186 | throw new IllegalArgumentException("Image resource ID may not be 0."); |
michael@0 | 187 | } |
michael@0 | 188 | this.resourceId = resourceId; |
michael@0 | 189 | this.uri = null; |
michael@0 | 190 | return this; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | /** Resize the image to the specified size in pixels. */ |
michael@0 | 194 | public Builder resize(int targetWidth, int targetHeight) { |
michael@0 | 195 | if (targetWidth <= 0) { |
michael@0 | 196 | throw new IllegalArgumentException("Width must be positive number."); |
michael@0 | 197 | } |
michael@0 | 198 | if (targetHeight <= 0) { |
michael@0 | 199 | throw new IllegalArgumentException("Height must be positive number."); |
michael@0 | 200 | } |
michael@0 | 201 | this.targetWidth = targetWidth; |
michael@0 | 202 | this.targetHeight = targetHeight; |
michael@0 | 203 | return this; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | /** Clear the resize transformation, if any. This will also clear center crop/inside if set. */ |
michael@0 | 207 | public Builder clearResize() { |
michael@0 | 208 | targetWidth = 0; |
michael@0 | 209 | targetHeight = 0; |
michael@0 | 210 | centerCrop = false; |
michael@0 | 211 | centerInside = false; |
michael@0 | 212 | return this; |
michael@0 | 213 | } |
michael@0 | 214 | |
michael@0 | 215 | /** |
michael@0 | 216 | * Crops an image inside of the bounds specified by {@link #resize(int, int)} rather than |
michael@0 | 217 | * distorting the aspect ratio. This cropping technique scales the image so that it fills the |
michael@0 | 218 | * requested bounds and then crops the extra. |
michael@0 | 219 | */ |
michael@0 | 220 | public Builder centerCrop() { |
michael@0 | 221 | if (centerInside) { |
michael@0 | 222 | throw new IllegalStateException("Center crop can not be used after calling centerInside"); |
michael@0 | 223 | } |
michael@0 | 224 | centerCrop = true; |
michael@0 | 225 | return this; |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | /** Clear the center crop transformation flag, if set. */ |
michael@0 | 229 | public Builder clearCenterCrop() { |
michael@0 | 230 | centerCrop = false; |
michael@0 | 231 | return this; |
michael@0 | 232 | } |
michael@0 | 233 | |
michael@0 | 234 | /** |
michael@0 | 235 | * Centers an image inside of the bounds specified by {@link #resize(int, int)}. This scales |
michael@0 | 236 | * the image so that both dimensions are equal to or less than the requested bounds. |
michael@0 | 237 | */ |
michael@0 | 238 | public Builder centerInside() { |
michael@0 | 239 | if (centerCrop) { |
michael@0 | 240 | throw new IllegalStateException("Center inside can not be used after calling centerCrop"); |
michael@0 | 241 | } |
michael@0 | 242 | centerInside = true; |
michael@0 | 243 | return this; |
michael@0 | 244 | } |
michael@0 | 245 | |
michael@0 | 246 | /** Clear the center inside transformation flag, if set. */ |
michael@0 | 247 | public Builder clearCenterInside() { |
michael@0 | 248 | centerInside = false; |
michael@0 | 249 | return this; |
michael@0 | 250 | } |
michael@0 | 251 | |
michael@0 | 252 | /** Rotate the image by the specified degrees. */ |
michael@0 | 253 | public Builder rotate(float degrees) { |
michael@0 | 254 | rotationDegrees = degrees; |
michael@0 | 255 | return this; |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | /** Rotate the image by the specified degrees around a pivot point. */ |
michael@0 | 259 | public Builder rotate(float degrees, float pivotX, float pivotY) { |
michael@0 | 260 | rotationDegrees = degrees; |
michael@0 | 261 | rotationPivotX = pivotX; |
michael@0 | 262 | rotationPivotY = pivotY; |
michael@0 | 263 | hasRotationPivot = true; |
michael@0 | 264 | return this; |
michael@0 | 265 | } |
michael@0 | 266 | |
michael@0 | 267 | /** Clear the rotation transformation, if any. */ |
michael@0 | 268 | public Builder clearRotation() { |
michael@0 | 269 | rotationDegrees = 0; |
michael@0 | 270 | rotationPivotX = 0; |
michael@0 | 271 | rotationPivotY = 0; |
michael@0 | 272 | hasRotationPivot = false; |
michael@0 | 273 | return this; |
michael@0 | 274 | } |
michael@0 | 275 | |
michael@0 | 276 | /** |
michael@0 | 277 | * Add a custom transformation to be applied to the image. |
michael@0 | 278 | * <p/> |
michael@0 | 279 | * Custom transformations will always be run after the built-in transformations. |
michael@0 | 280 | */ |
michael@0 | 281 | public Builder transform(Transformation transformation) { |
michael@0 | 282 | if (transformation == null) { |
michael@0 | 283 | throw new IllegalArgumentException("Transformation must not be null."); |
michael@0 | 284 | } |
michael@0 | 285 | if (transformations == null) { |
michael@0 | 286 | transformations = new ArrayList<Transformation>(2); |
michael@0 | 287 | } |
michael@0 | 288 | transformations.add(transformation); |
michael@0 | 289 | return this; |
michael@0 | 290 | } |
michael@0 | 291 | |
michael@0 | 292 | /** Create the immutable {@link Request} object. */ |
michael@0 | 293 | public Request build() { |
michael@0 | 294 | if (centerInside && centerCrop) { |
michael@0 | 295 | throw new IllegalStateException("Center crop and center inside can not be used together."); |
michael@0 | 296 | } |
michael@0 | 297 | if (centerCrop && targetWidth == 0) { |
michael@0 | 298 | throw new IllegalStateException("Center crop requires calling resize."); |
michael@0 | 299 | } |
michael@0 | 300 | if (centerInside && targetWidth == 0) { |
michael@0 | 301 | throw new IllegalStateException("Center inside requires calling resize."); |
michael@0 | 302 | } |
michael@0 | 303 | return new Request(uri, resourceId, transformations, targetWidth, targetHeight, centerCrop, |
michael@0 | 304 | centerInside, rotationDegrees, rotationPivotX, rotationPivotY, hasRotationPivot); |
michael@0 | 305 | } |
michael@0 | 306 | } |
michael@0 | 307 | } |