WallpaperCropActivity.java revision e8d1bf7a439450b9979701909164a6baffbe8bae
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/* Copied from Launcher3 */ 17package com.android.wallpapercropper; 18 19import android.app.ActionBar; 20import android.app.Activity; 21import android.app.WallpaperManager; 22import android.content.Context; 23import android.content.Intent; 24import android.content.SharedPreferences; 25import android.content.res.Configuration; 26import android.content.res.Resources; 27import android.graphics.Bitmap; 28import android.graphics.Bitmap.CompressFormat; 29import android.graphics.BitmapFactory; 30import android.graphics.BitmapRegionDecoder; 31import android.graphics.Canvas; 32import android.graphics.Matrix; 33import android.graphics.Paint; 34import android.graphics.Point; 35import android.graphics.Rect; 36import android.graphics.RectF; 37import android.net.Uri; 38import android.os.AsyncTask; 39import android.os.Bundle; 40import android.util.Log; 41import android.view.Display; 42import android.view.View; 43import android.view.WindowManager; 44 45import com.android.gallery3d.common.Utils; 46import com.android.photos.BitmapRegionTileSource; 47 48import java.io.BufferedInputStream; 49import java.io.ByteArrayInputStream; 50import java.io.ByteArrayOutputStream; 51import java.io.FileNotFoundException; 52import java.io.IOException; 53import java.io.InputStream; 54 55public class WallpaperCropActivity extends Activity { 56 private static final String LOGTAG = "Launcher3.CropActivity"; 57 58 protected static final String WALLPAPER_WIDTH_KEY = "wallpaper.width"; 59 protected static final String WALLPAPER_HEIGHT_KEY = "wallpaper.height"; 60 private static final int DEFAULT_COMPRESS_QUALITY = 90; 61 /** 62 * The maximum bitmap size we allow to be returned through the intent. 63 * Intents have a maximum of 1MB in total size. However, the Bitmap seems to 64 * have some overhead to hit so that we go way below the limit here to make 65 * sure the intent stays below 1MB.We should consider just returning a byte 66 * array instead of a Bitmap instance to avoid overhead. 67 */ 68 public static final int MAX_BMAP_IN_INTENT = 750000; 69 private static final float WALLPAPER_SCREENS_SPAN = 2f; 70 71 protected CropView mCropView; 72 protected Uri mUri; 73 74 @Override 75 protected void onCreate(Bundle savedInstanceState) { 76 super.onCreate(savedInstanceState); 77 init(); 78 } 79 80 protected void init() { 81 setContentView(R.layout.wallpaper_cropper); 82 83 mCropView = (CropView) findViewById(R.id.cropView); 84 85 Intent cropIntent = this.getIntent(); 86 final Uri imageUri = cropIntent.getData(); 87 88 mCropView.setTileSource(new BitmapRegionTileSource(this, imageUri, 1024, 0), null); 89 mCropView.setTouchEnabled(true); 90 // Action bar 91 // Show the custom action bar view 92 final ActionBar actionBar = getActionBar(); 93 actionBar.setCustomView(R.layout.actionbar_set_wallpaper); 94 actionBar.getCustomView().setOnClickListener( 95 new View.OnClickListener() { 96 @Override 97 public void onClick(View v) { 98 boolean finishActivityWhenDone = true; 99 cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone); 100 } 101 }); 102 } 103 104 public static String getSharedPreferencesKey() { 105 return WallpaperCropActivity.class.getName(); 106 } 107 108 // As a ratio of screen height, the total distance we want the parallax effect to span 109 // horizontally 110 private static float wallpaperTravelToScreenWidthRatio(int width, int height) { 111 float aspectRatio = width / (float) height; 112 113 // At an aspect ratio of 16/10, the wallpaper parallax effect should span 1.5 * screen width 114 // At an aspect ratio of 10/16, the wallpaper parallax effect should span 1.2 * screen width 115 // We will use these two data points to extrapolate how much the wallpaper parallax effect 116 // to span (ie travel) at any aspect ratio: 117 118 final float ASPECT_RATIO_LANDSCAPE = 16/10f; 119 final float ASPECT_RATIO_PORTRAIT = 10/16f; 120 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE = 1.5f; 121 final float WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT = 1.2f; 122 123 // To find out the desired width at different aspect ratios, we use the following two 124 // formulas, where the coefficient on x is the aspect ratio (width/height): 125 // (16/10)x + y = 1.5 126 // (10/16)x + y = 1.2 127 // We solve for x and y and end up with a final formula: 128 final float x = 129 (WALLPAPER_WIDTH_TO_SCREEN_RATIO_LANDSCAPE - WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT) / 130 (ASPECT_RATIO_LANDSCAPE - ASPECT_RATIO_PORTRAIT); 131 final float y = WALLPAPER_WIDTH_TO_SCREEN_RATIO_PORTRAIT - x * ASPECT_RATIO_PORTRAIT; 132 return x * aspectRatio + y; 133 } 134 135 static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) { 136 Point minDims = new Point(); 137 Point maxDims = new Point(); 138 windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims); 139 140 int maxDim = Math.max(maxDims.x, maxDims.y); 141 final int minDim = Math.min(minDims.x, minDims.y); 142 143 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { 144 Point realSize = new Point(); 145 windowManager.getDefaultDisplay().getRealSize(realSize); 146 maxDim = Math.max(realSize.x, realSize.y); 147 } 148 149 // We need to ensure that there is enough extra space in the wallpaper 150 // for the intended 151 // parallax effects 152 final int defaultWidth, defaultHeight; 153 if (isScreenLarge(res)) { 154 defaultWidth = (int) (maxDim * wallpaperTravelToScreenWidthRatio(maxDim, minDim)); 155 defaultHeight = maxDim; 156 } else { 157 defaultWidth = Math.max((int) (minDim * WALLPAPER_SCREENS_SPAN), maxDim); 158 defaultHeight = maxDim; 159 } 160 return new Point(defaultWidth, defaultHeight); 161 } 162 163 protected void setWallpaper(String filePath, final boolean finishActivityWhenDone) { 164 165 BitmapCropTask cropTask = new BitmapCropTask(this, 166 filePath, null, 0, 0, true, false, null); 167 final Point bounds = cropTask.getImageBounds(); 168 Runnable onEndCrop = new Runnable() { 169 public void run() { 170 updateWallpaperDimensions(bounds.x, bounds.y); 171 if (finishActivityWhenDone) { 172 setResult(Activity.RESULT_OK); 173 finish(); 174 } 175 } 176 }; 177 cropTask.setOnEndRunnable(onEndCrop); 178 cropTask.setNoCrop(true); 179 cropTask.execute(); 180 } 181 182 protected void cropImageAndSetWallpaper( 183 Resources res, int resId, final boolean finishActivityWhenDone) { 184 // crop this image and scale it down to the default wallpaper size for 185 // this device 186 Point inSize = mCropView.getSourceDimensions(); 187 Point outSize = getDefaultWallpaperSize(getResources(), 188 getWindowManager()); 189 RectF crop = getMaxCropRect( 190 inSize.x, inSize.y, outSize.x, outSize.y, false); 191 Runnable onEndCrop = new Runnable() { 192 public void run() { 193 // Passing 0, 0 will cause launcher to revert to using the 194 // default wallpaper size 195 updateWallpaperDimensions(0, 0); 196 if (finishActivityWhenDone) { 197 setResult(Activity.RESULT_OK); 198 finish(); 199 } 200 } 201 }; 202 BitmapCropTask cropTask = new BitmapCropTask(res, resId, 203 crop, outSize.x, outSize.y, 204 true, false, onEndCrop); 205 cropTask.execute(); 206 } 207 208 private static boolean isScreenLarge(Resources res) { 209 Configuration config = res.getConfiguration(); 210 return config.smallestScreenWidthDp >= 720; 211 } 212 213 protected void cropImageAndSetWallpaper(Uri uri, 214 OnBitmapCroppedHandler onBitmapCroppedHandler, final boolean finishActivityWhenDone) { 215 // Get the crop 216 Point inSize = mCropView.getSourceDimensions(); 217 218 Point minDims = new Point(); 219 Point maxDims = new Point(); 220 Display d = getWindowManager().getDefaultDisplay(); 221 d.getCurrentSizeRange(minDims, maxDims); 222 223 Point displaySize = new Point(); 224 d.getSize(displaySize); 225 226 int maxDim = Math.max(maxDims.x, maxDims.y); 227 final int minDim = Math.min(minDims.x, minDims.y); 228 int defaultWidth; 229 if (isScreenLarge(getResources())) { 230 defaultWidth = (int) (maxDim * 231 wallpaperTravelToScreenWidthRatio(maxDim, minDim)); 232 } else { 233 defaultWidth = Math.max((int) 234 (minDim * WALLPAPER_SCREENS_SPAN), maxDim); 235 } 236 237 boolean isPortrait = displaySize.x < displaySize.y; 238 int portraitHeight; 239 if (isPortrait) { 240 portraitHeight = mCropView.getHeight(); 241 } else { 242 // TODO: how to actually get the proper portrait height? 243 // This is not quite right: 244 portraitHeight = Math.max(maxDims.x, maxDims.y); 245 } 246 if (android.os.Build.VERSION.SDK_INT >= 247 android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { 248 Point realSize = new Point(); 249 d.getRealSize(realSize); 250 portraitHeight = Math.max(realSize.x, realSize.y); 251 } 252 // Get the crop 253 RectF cropRect = mCropView.getCrop(); 254 float cropScale = mCropView.getWidth() / (float) cropRect.width(); 255 256 // ADJUST CROP WIDTH 257 // Extend the crop all the way to the right, for parallax 258 float extraSpaceToRight = inSize.x - cropRect.right; 259 // Cap the amount of extra width 260 float maxExtraSpace = defaultWidth / cropScale - cropRect.width(); 261 extraSpaceToRight = Math.min(extraSpaceToRight, maxExtraSpace); 262 263 cropRect.right += extraSpaceToRight; 264 265 // ADJUST CROP HEIGHT 266 if (isPortrait) { 267 cropRect.bottom = cropRect.top + portraitHeight / cropScale; 268 } else { // LANDSCAPE 269 float extraPortraitHeight = 270 portraitHeight / cropScale - cropRect.height(); 271 float expandHeight = 272 Math.min(Math.min(inSize.y - cropRect.bottom, cropRect.top), 273 extraPortraitHeight / 2); 274 cropRect.top -= expandHeight; 275 cropRect.bottom += expandHeight; 276 } 277 final int outWidth = (int) Math.round(cropRect.width() * cropScale); 278 final int outHeight = (int) Math.round(cropRect.height() * cropScale); 279 280 Runnable onEndCrop = new Runnable() { 281 public void run() { 282 updateWallpaperDimensions(outWidth, outHeight); 283 if (finishActivityWhenDone) { 284 setResult(Activity.RESULT_OK); 285 finish(); 286 } 287 } 288 }; 289 BitmapCropTask cropTask = new BitmapCropTask(uri, 290 cropRect, outWidth, outHeight, true, false, onEndCrop); 291 if (onBitmapCroppedHandler != null) { 292 cropTask.setOnBitmapCropped(onBitmapCroppedHandler); 293 } 294 cropTask.execute(); 295 } 296 297 public interface OnBitmapCroppedHandler { 298 public void onBitmapCropped(byte[] imageBytes); 299 } 300 301 protected class BitmapCropTask extends AsyncTask<Void, Void, Boolean> { 302 Uri mInUri = null; 303 Context mContext; 304 String mInFilePath; 305 byte[] mInImageBytes; 306 int mInResId = 0; 307 InputStream mInStream; 308 RectF mCropBounds = null; 309 int mOutWidth, mOutHeight; 310 int mRotation = 0; // for now 311 protected final WallpaperManager mWPManager; 312 String mOutputFormat = "jpg"; // for now 313 boolean mSetWallpaper; 314 boolean mSaveCroppedBitmap; 315 Bitmap mCroppedBitmap; 316 Runnable mOnEndRunnable; 317 Resources mResources; 318 OnBitmapCroppedHandler mOnBitmapCroppedHandler; 319 boolean mNoCrop; 320 321 public BitmapCropTask(Context c, String filePath, 322 RectF cropBounds, int outWidth, int outHeight, 323 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 324 mContext = c; 325 mInFilePath = filePath; 326 mWPManager = WallpaperManager.getInstance(getApplicationContext()); 327 init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 328 } 329 330 public BitmapCropTask(byte[] imageBytes, 331 RectF cropBounds, int outWidth, int outHeight, 332 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 333 mInImageBytes = imageBytes; 334 mWPManager = WallpaperManager.getInstance(getApplicationContext()); 335 init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 336 } 337 338 public BitmapCropTask(Uri inUri, 339 RectF cropBounds, int outWidth, int outHeight, 340 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 341 mInUri = inUri; 342 mWPManager = WallpaperManager.getInstance(getApplicationContext()); 343 init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 344 } 345 346 public BitmapCropTask(Resources res, int inResId, 347 RectF cropBounds, int outWidth, int outHeight, 348 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 349 mInResId = inResId; 350 mResources = res; 351 mWPManager = WallpaperManager.getInstance(getApplicationContext()); 352 init(cropBounds, outWidth, outHeight, setWallpaper, saveCroppedBitmap, onEndRunnable); 353 } 354 355 private void init(RectF cropBounds, int outWidth, int outHeight, 356 boolean setWallpaper, boolean saveCroppedBitmap, Runnable onEndRunnable) { 357 mCropBounds = cropBounds; 358 mOutWidth = outWidth; 359 mOutHeight = outHeight; 360 mSetWallpaper = setWallpaper; 361 mSaveCroppedBitmap = saveCroppedBitmap; 362 mOnEndRunnable = onEndRunnable; 363 } 364 365 public void setOnBitmapCropped(OnBitmapCroppedHandler handler) { 366 mOnBitmapCroppedHandler = handler; 367 } 368 369 public void setNoCrop(boolean value) { 370 mNoCrop = value; 371 } 372 373 public void setOnEndRunnable(Runnable onEndRunnable) { 374 mOnEndRunnable = onEndRunnable; 375 } 376 377 // Helper to setup input stream 378 private void regenerateInputStream() { 379 if (mInUri == null && mInResId == 0 && mInFilePath == null && mInImageBytes == null) { 380 Log.w(LOGTAG, "cannot read original file, no input URI, resource ID, or " + 381 "image byte array given"); 382 } else { 383 Utils.closeSilently(mInStream); 384 try { 385 if (mInUri != null) { 386 mInStream = new BufferedInputStream( 387 getContentResolver().openInputStream(mInUri)); 388 } else if (mInFilePath != null) { 389 mInStream = mContext.openFileInput(mInFilePath); 390 } else if (mInImageBytes != null) { 391 mInStream = new BufferedInputStream( 392 new ByteArrayInputStream(mInImageBytes)); 393 } else { 394 mInStream = new BufferedInputStream( 395 mResources.openRawResource(mInResId)); 396 } 397 } catch (FileNotFoundException e) { 398 Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); 399 } 400 } 401 } 402 403 public Point getImageBounds() { 404 regenerateInputStream(); 405 if (mInStream != null) { 406 BitmapFactory.Options options = new BitmapFactory.Options(); 407 options.inJustDecodeBounds = true; 408 BitmapFactory.decodeStream(mInStream, null, options); 409 if (options.outWidth != 0 && options.outHeight != 0) { 410 return new Point(options.outWidth, options.outHeight); 411 } 412 } 413 return null; 414 } 415 416 public void setCropBounds(RectF cropBounds) { 417 mCropBounds = cropBounds; 418 } 419 420 public Bitmap getCroppedBitmap() { 421 return mCroppedBitmap; 422 } 423 public boolean cropBitmap() { 424 boolean failure = false; 425 426 regenerateInputStream(); 427 428 if (mNoCrop && mInStream != null) { 429 try { 430 mWPManager.setStream(mInStream); 431 } catch (IOException e) { 432 Log.w(LOGTAG, "cannot write stream to wallpaper", e); 433 failure = true; 434 } 435 if (mOnEndRunnable != null) { 436 mOnEndRunnable.run(); 437 } 438 return !failure; 439 } 440 if (mInStream != null) { 441 // Find crop bounds (scaled to original image size) 442 Rect roundedTrueCrop = new Rect(); 443 mCropBounds.roundOut(roundedTrueCrop); 444 445 if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) { 446 Log.w(LOGTAG, "crop has bad values for full size image"); 447 failure = true; 448 return false; 449 } 450 451 // See how much we're reducing the size of the image 452 int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / mOutWidth, 453 roundedTrueCrop.height() / mOutHeight); 454 455 // Attempt to open a region decoder 456 BitmapRegionDecoder decoder = null; 457 try { 458 decoder = BitmapRegionDecoder.newInstance(mInStream, true); 459 } catch (IOException e) { 460 Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); 461 } 462 463 Bitmap crop = null; 464 if (decoder != null) { 465 // Do region decoding to get crop bitmap 466 BitmapFactory.Options options = new BitmapFactory.Options(); 467 if (scaleDownSampleSize > 1) { 468 options.inSampleSize = scaleDownSampleSize; 469 } 470 crop = decoder.decodeRegion(roundedTrueCrop, options); 471 decoder.recycle(); 472 } 473 474 if (crop == null) { 475 // BitmapRegionDecoder has failed, try to crop in-memory 476 regenerateInputStream(); 477 Bitmap fullSize = null; 478 if (mInStream != null) { 479 BitmapFactory.Options options = new BitmapFactory.Options(); 480 if (scaleDownSampleSize > 1) { 481 options.inSampleSize = scaleDownSampleSize; 482 } 483 fullSize = BitmapFactory.decodeStream(mInStream, null, options); 484 } 485 if (fullSize != null) { 486 crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, 487 roundedTrueCrop.top, roundedTrueCrop.width(), 488 roundedTrueCrop.height()); 489 } 490 } 491 492 if (crop == null) { 493 Log.w(LOGTAG, "cannot decode file: " + mInUri.toString()); 494 failure = true; 495 return false; 496 } 497 if (mOutWidth > 0 && mOutHeight > 0) { 498 Matrix m = new Matrix(); 499 RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight()); 500 if (mRotation > 0) { 501 m.setRotate(mRotation); 502 m.mapRect(cropRect); 503 } 504 RectF returnRect = new RectF(0, 0, mOutWidth, mOutHeight); 505 m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); 506 m.preRotate(mRotation); 507 Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), 508 (int) returnRect.height(), Bitmap.Config.ARGB_8888); 509 if (tmp != null) { 510 Canvas c = new Canvas(tmp); 511 c.drawBitmap(crop, m, new Paint()); 512 crop = tmp; 513 } 514 } else if (mRotation > 0) { 515 Matrix m = new Matrix(); 516 m.setRotate(mRotation); 517 Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(), 518 crop.getHeight(), m, true); 519 if (tmp != null) { 520 crop = tmp; 521 } 522 } 523 524 if (mSaveCroppedBitmap) { 525 mCroppedBitmap = crop; 526 } 527 528 // Get output compression format 529 CompressFormat cf = 530 convertExtensionToCompressFormat(getFileExtension(mOutputFormat)); 531 532 // Compress to byte array 533 ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); 534 if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) { 535 // If we need to set to the wallpaper, set it 536 if (mSetWallpaper && mWPManager != null) { 537 if (mWPManager == null) { 538 Log.w(LOGTAG, "no wallpaper manager"); 539 failure = true; 540 } else { 541 try { 542 byte[] outByteArray = tmpOut.toByteArray(); 543 mWPManager.setStream(new ByteArrayInputStream(outByteArray)); 544 if (mOnBitmapCroppedHandler != null) { 545 mOnBitmapCroppedHandler.onBitmapCropped(outByteArray); 546 } 547 } catch (IOException e) { 548 Log.w(LOGTAG, "cannot write stream to wallpaper", e); 549 failure = true; 550 } 551 } 552 } 553 if (mOnEndRunnable != null) { 554 mOnEndRunnable.run(); 555 } 556 } else { 557 Log.w(LOGTAG, "cannot compress bitmap"); 558 failure = true; 559 } 560 } 561 return !failure; // True if any of the operations failed 562 } 563 564 @Override 565 protected Boolean doInBackground(Void... params) { 566 return cropBitmap(); 567 } 568 569 @Override 570 protected void onPostExecute(Boolean result) { 571 setResult(Activity.RESULT_OK); 572 finish(); 573 } 574 } 575 576 protected void updateWallpaperDimensions(int width, int height) { 577 String spKey = getSharedPreferencesKey(); 578 SharedPreferences sp = getSharedPreferences(spKey, Context.MODE_PRIVATE); 579 SharedPreferences.Editor editor = sp.edit(); 580 if (width != 0 && height != 0) { 581 editor.putInt(WALLPAPER_WIDTH_KEY, width); 582 editor.putInt(WALLPAPER_HEIGHT_KEY, height); 583 } else { 584 editor.remove(WALLPAPER_WIDTH_KEY); 585 editor.remove(WALLPAPER_HEIGHT_KEY); 586 } 587 editor.commit(); 588 589 suggestWallpaperDimension(getResources(), 590 sp, getWindowManager(), WallpaperManager.getInstance(this)); 591 } 592 593 static public void suggestWallpaperDimension(Resources res, 594 final SharedPreferences sharedPrefs, 595 WindowManager windowManager, 596 final WallpaperManager wallpaperManager) { 597 final Point defaultWallpaperSize = 598 WallpaperCropActivity.getDefaultWallpaperSize(res, windowManager); 599 600 new Thread("suggestWallpaperDimension") { 601 public void run() { 602 // If we have saved a wallpaper width/height, use that instead 603 int savedWidth = sharedPrefs.getInt(WALLPAPER_WIDTH_KEY, defaultWallpaperSize.x); 604 int savedHeight = sharedPrefs.getInt(WALLPAPER_HEIGHT_KEY, defaultWallpaperSize.y); 605 wallpaperManager.suggestDesiredDimensions(savedWidth, savedHeight); 606 } 607 }.start(); 608 } 609 610 611 protected static RectF getMaxCropRect( 612 int inWidth, int inHeight, int outWidth, int outHeight, boolean leftAligned) { 613 RectF cropRect = new RectF(); 614 // Get a crop rect that will fit this 615 if (inWidth / (float) inHeight > outWidth / (float) outHeight) { 616 cropRect.top = 0; 617 cropRect.bottom = inHeight; 618 cropRect.left = (inWidth - (outWidth / (float) outHeight) * inHeight) / 2; 619 cropRect.right = inWidth - cropRect.left; 620 if (leftAligned) { 621 cropRect.right -= cropRect.left; 622 cropRect.left = 0; 623 } 624 } else { 625 cropRect.left = 0; 626 cropRect.right = inWidth; 627 cropRect.top = (inHeight - (outHeight / (float) outWidth) * inWidth) / 2; 628 cropRect.bottom = inHeight - cropRect.top; 629 } 630 return cropRect; 631 } 632 633 protected static CompressFormat convertExtensionToCompressFormat(String extension) { 634 return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG; 635 } 636 637 protected static String getFileExtension(String requestFormat) { 638 String outputFormat = (requestFormat == null) 639 ? "jpg" 640 : requestFormat; 641 outputFormat = outputFormat.toLowerCase(); 642 return (outputFormat.equals("png") || outputFormat.equals("gif")) 643 ? "png" // We don't support gif compression. 644 : "jpg"; 645 } 646} 647