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 17 package com.android.gallery3d.filtershow.crop; 18 19 import android.app.ActionBar; 20 import android.app.Activity; 21 import android.app.WallpaperManager; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.res.Configuration; 25 import android.graphics.Bitmap; 26 import android.graphics.Bitmap.CompressFormat; 27 import android.graphics.BitmapFactory; 28 import android.graphics.BitmapRegionDecoder; 29 import android.graphics.Canvas; 30 import android.graphics.Matrix; 31 import android.graphics.Paint; 32 import android.graphics.Rect; 33 import android.graphics.RectF; 34 import android.net.Uri; 35 import android.os.AsyncTask; 36 import android.os.Bundle; 37 import android.provider.MediaStore; 38 import android.util.DisplayMetrics; 39 import android.util.Log; 40 import android.view.View; 41 import android.view.View.OnClickListener; 42 import android.view.WindowManager; 43 import android.widget.Toast; 44 45 import com.android.gallery3d.R; 46 import com.android.gallery3d.common.Utils; 47 48 import java.io.ByteArrayInputStream; 49 import java.io.ByteArrayOutputStream; 50 import java.io.FileNotFoundException; 51 import java.io.IOException; 52 import java.io.InputStream; 53 import java.io.OutputStream; 54 55 /** 56 * Activity for cropping an image. 57 */ 58 public class CropActivity extends Activity { 59 private static final String LOGTAG = "CropActivity"; 60 public static final String CROP_ACTION = "com.android.camera.action.CROP"; 61 private CropExtras mCropExtras = null; 62 private LoadBitmapTask mLoadBitmapTask = null; 63 64 private int mOutputX = 0; 65 private int mOutputY = 0; 66 private Bitmap mOriginalBitmap = null; 67 private RectF mOriginalBounds = null; 68 private int mOriginalRotation = 0; 69 private Uri mSourceUri = null; 70 private CropView mCropView = null; 71 private View mSaveButton = null; 72 private boolean finalIOGuard = false; 73 74 private static final int SELECT_PICTURE = 1; // request code for picker 75 76 private static final int DEFAULT_COMPRESS_QUALITY = 90; 77 /** 78 * The maximum bitmap size we allow to be returned through the intent. 79 * Intents have a maximum of 1MB in total size. However, the Bitmap seems to 80 * have some overhead to hit so that we go way below the limit here to make 81 * sure the intent stays below 1MB.We should consider just returning a byte 82 * array instead of a Bitmap instance to avoid overhead. 83 */ 84 public static final int MAX_BMAP_IN_INTENT = 750000; 85 86 // Flags 87 private static final int DO_SET_WALLPAPER = 1; 88 private static final int DO_RETURN_DATA = 1 << 1; 89 private static final int DO_EXTRA_OUTPUT = 1 << 2; 90 91 private static final int FLAG_CHECK = DO_SET_WALLPAPER | DO_RETURN_DATA | DO_EXTRA_OUTPUT; 92 93 @Override 94 public void onCreate(Bundle savedInstanceState) { 95 super.onCreate(savedInstanceState); 96 Intent intent = getIntent(); 97 setResult(RESULT_CANCELED, new Intent()); 98 mCropExtras = getExtrasFromIntent(intent); 99 if (mCropExtras != null && mCropExtras.getShowWhenLocked()) { 100 getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); 101 } 102 103 setContentView(R.layout.crop_activity); 104 mCropView = (CropView) findViewById(R.id.cropView); 105 106 ActionBar actionBar = getActionBar(); 107 actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 108 actionBar.setCustomView(R.layout.filtershow_actionbar); 109 110 View mSaveButton = actionBar.getCustomView(); 111 mSaveButton.setOnClickListener(new OnClickListener() { 112 @Override 113 public void onClick(View view) { 114 startFinishOutput(); 115 } 116 }); 117 118 if (intent.getData() != null) { 119 mSourceUri = intent.getData(); 120 startLoadBitmap(mSourceUri); 121 } else { 122 pickImage(); 123 } 124 } 125 126 private void enableSave(boolean enable) { 127 if (mSaveButton != null) { 128 mSaveButton.setEnabled(enable); 129 } 130 } 131 132 @Override 133 protected void onDestroy() { 134 if (mLoadBitmapTask != null) { 135 mLoadBitmapTask.cancel(false); 136 } 137 super.onDestroy(); 138 } 139 140 @Override 141 public void onConfigurationChanged (Configuration newConfig) { 142 super.onConfigurationChanged(newConfig); 143 mCropView.configChanged(); 144 } 145 146 /** 147 * Opens a selector in Gallery to chose an image for use when none was given 148 * in the CROP intent. 149 */ 150 private void pickImage() { 151 Intent intent = new Intent(); 152 intent.setType("image/*"); 153 intent.setAction(Intent.ACTION_GET_CONTENT); 154 startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), 155 SELECT_PICTURE); 156 } 157 158 /** 159 * Callback for pickImage(). 160 */ 161 @Override 162 public void onActivityResult(int requestCode, int resultCode, Intent data) { 163 if (resultCode == RESULT_OK && requestCode == SELECT_PICTURE) { 164 mSourceUri = data.getData(); 165 startLoadBitmap(mSourceUri); 166 } 167 } 168 169 /** 170 * Gets screen size metric. 171 */ 172 private int getScreenImageSize() { 173 DisplayMetrics outMetrics = new DisplayMetrics(); 174 getWindowManager().getDefaultDisplay().getMetrics(outMetrics); 175 return (int) Math.max(outMetrics.heightPixels, outMetrics.widthPixels); 176 } 177 178 /** 179 * Method that loads a bitmap in an async task. 180 */ 181 private void startLoadBitmap(Uri uri) { 182 if (uri != null) { 183 enableSave(false); 184 final View loading = findViewById(R.id.loading); 185 loading.setVisibility(View.VISIBLE); 186 mLoadBitmapTask = new LoadBitmapTask(); 187 mLoadBitmapTask.execute(uri); 188 } else { 189 cannotLoadImage(); 190 done(); 191 } 192 } 193 194 /** 195 * Method called on UI thread with loaded bitmap. 196 */ 197 private void doneLoadBitmap(Bitmap bitmap, RectF bounds, int orientation) { 198 final View loading = findViewById(R.id.loading); 199 loading.setVisibility(View.GONE); 200 mOriginalBitmap = bitmap; 201 mOriginalBounds = bounds; 202 mOriginalRotation = orientation; 203 if (bitmap != null && bitmap.getWidth() != 0 && bitmap.getHeight() != 0) { 204 RectF imgBounds = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()); 205 mCropView.initialize(bitmap, imgBounds, imgBounds, orientation); 206 if (mCropExtras != null) { 207 int aspectX = mCropExtras.getAspectX(); 208 int aspectY = mCropExtras.getAspectY(); 209 mOutputX = mCropExtras.getOutputX(); 210 mOutputY = mCropExtras.getOutputY(); 211 if (mOutputX > 0 && mOutputY > 0) { 212 mCropView.applyAspect(mOutputX, mOutputY); 213 214 } 215 float spotX = mCropExtras.getSpotlightX(); 216 float spotY = mCropExtras.getSpotlightY(); 217 if (spotX > 0 && spotY > 0) { 218 mCropView.setWallpaperSpotlight(spotX, spotY); 219 } 220 if (aspectX > 0 && aspectY > 0) { 221 mCropView.applyAspect(aspectX, aspectY); 222 } 223 } 224 enableSave(true); 225 } else { 226 Log.w(LOGTAG, "could not load image for cropping"); 227 cannotLoadImage(); 228 setResult(RESULT_CANCELED, new Intent()); 229 done(); 230 } 231 } 232 233 /** 234 * Display toast for image loading failure. 235 */ 236 private void cannotLoadImage() { 237 CharSequence text = getString(R.string.cannot_load_image); 238 Toast toast = Toast.makeText(this, text, Toast.LENGTH_SHORT); 239 toast.show(); 240 } 241 242 /** 243 * AsyncTask for loading a bitmap into memory. 244 * 245 * @see #startLoadBitmap(Uri) 246 * @see #doneLoadBitmap(Bitmap) 247 */ 248 private class LoadBitmapTask extends AsyncTask<Uri, Void, Bitmap> { 249 int mBitmapSize; 250 Context mContext; 251 Rect mOriginalBounds; 252 int mOrientation; 253 254 public LoadBitmapTask() { 255 mBitmapSize = getScreenImageSize(); 256 mContext = getApplicationContext(); 257 mOriginalBounds = new Rect(); 258 mOrientation = 0; 259 } 260 261 @Override 262 protected Bitmap doInBackground(Uri... params) { 263 Uri uri = params[0]; 264 Bitmap bmap = CropLoader.getConstrainedBitmap(uri, mContext, mBitmapSize, 265 mOriginalBounds); 266 mOrientation = CropLoader.getMetadataRotation(uri, mContext); 267 return bmap; 268 } 269 270 @Override 271 protected void onPostExecute(Bitmap result) { 272 doneLoadBitmap(result, new RectF(mOriginalBounds), mOrientation); 273 } 274 } 275 276 private void startFinishOutput() { 277 if (finalIOGuard) { 278 return; 279 } else { 280 finalIOGuard = true; 281 } 282 enableSave(false); 283 Uri destinationUri = null; 284 int flags = 0; 285 if (mOriginalBitmap != null && mCropExtras != null) { 286 if (mCropExtras.getExtraOutput() != null) { 287 destinationUri = mCropExtras.getExtraOutput(); 288 if (destinationUri != null) { 289 flags |= DO_EXTRA_OUTPUT; 290 } 291 } 292 if (mCropExtras.getSetAsWallpaper()) { 293 flags |= DO_SET_WALLPAPER; 294 } 295 if (mCropExtras.getReturnData()) { 296 flags |= DO_RETURN_DATA; 297 } 298 } 299 if (flags == 0) { 300 destinationUri = CropLoader.makeAndInsertUri(this, mSourceUri); 301 if (destinationUri != null) { 302 flags |= DO_EXTRA_OUTPUT; 303 } 304 } 305 if ((flags & FLAG_CHECK) != 0 && mOriginalBitmap != null) { 306 RectF photo = new RectF(0, 0, mOriginalBitmap.getWidth(), mOriginalBitmap.getHeight()); 307 RectF crop = getBitmapCrop(photo); 308 startBitmapIO(flags, mOriginalBitmap, mSourceUri, destinationUri, crop, 309 photo, mOriginalBounds, 310 (mCropExtras == null) ? null : mCropExtras.getOutputFormat(), mOriginalRotation); 311 return; 312 } 313 setResult(RESULT_CANCELED, new Intent()); 314 done(); 315 return; 316 } 317 318 private void startBitmapIO(int flags, Bitmap currentBitmap, Uri sourceUri, Uri destUri, 319 RectF cropBounds, RectF photoBounds, RectF currentBitmapBounds, String format, 320 int rotation) { 321 if (cropBounds == null || photoBounds == null || currentBitmap == null 322 || currentBitmap.getWidth() == 0 || currentBitmap.getHeight() == 0 323 || cropBounds.width() == 0 || cropBounds.height() == 0 || photoBounds.width() == 0 324 || photoBounds.height() == 0) { 325 return; // fail fast 326 } 327 if ((flags & FLAG_CHECK) == 0) { 328 return; // no output options 329 } 330 if ((flags & DO_SET_WALLPAPER) != 0) { 331 Toast.makeText(this, R.string.setting_wallpaper, Toast.LENGTH_LONG).show(); 332 } 333 334 final View loading = findViewById(R.id.loading); 335 loading.setVisibility(View.VISIBLE); 336 BitmapIOTask ioTask = new BitmapIOTask(sourceUri, destUri, format, flags, cropBounds, 337 photoBounds, currentBitmapBounds, rotation, mOutputX, mOutputY); 338 ioTask.execute(currentBitmap); 339 } 340 341 private void doneBitmapIO(boolean success, Intent intent) { 342 final View loading = findViewById(R.id.loading); 343 loading.setVisibility(View.GONE); 344 if (success) { 345 setResult(RESULT_OK, intent); 346 } else { 347 setResult(RESULT_CANCELED, intent); 348 } 349 done(); 350 } 351 352 private class BitmapIOTask extends AsyncTask<Bitmap, Void, Boolean> { 353 354 private final WallpaperManager mWPManager; 355 InputStream mInStream = null; 356 OutputStream mOutStream = null; 357 String mOutputFormat = null; 358 Uri mOutUri = null; 359 Uri mInUri = null; 360 int mFlags = 0; 361 RectF mCrop = null; 362 RectF mPhoto = null; 363 RectF mOrig = null; 364 Intent mResultIntent = null; 365 int mRotation = 0; 366 367 // Helper to setup input stream 368 private void regenerateInputStream() { 369 if (mInUri == null) { 370 Log.w(LOGTAG, "cannot read original file, no input URI given"); 371 } else { 372 Utils.closeSilently(mInStream); 373 try { 374 mInStream = getContentResolver().openInputStream(mInUri); 375 } catch (FileNotFoundException e) { 376 Log.w(LOGTAG, "cannot read file: " + mInUri.toString(), e); 377 } 378 } 379 } 380 381 public BitmapIOTask(Uri sourceUri, Uri destUri, String outputFormat, int flags, 382 RectF cropBounds, RectF photoBounds, RectF originalBitmapBounds, int rotation, 383 int outputX, int outputY) { 384 mOutputFormat = outputFormat; 385 mOutStream = null; 386 mOutUri = destUri; 387 mInUri = sourceUri; 388 mFlags = flags; 389 mCrop = cropBounds; 390 mPhoto = photoBounds; 391 mOrig = originalBitmapBounds; 392 mWPManager = WallpaperManager.getInstance(getApplicationContext()); 393 mResultIntent = new Intent(); 394 mRotation = (rotation < 0) ? -rotation : rotation; 395 mRotation %= 360; 396 mRotation = 90 * (int) (mRotation / 90); // now mRotation is a multiple of 90 397 mOutputX = outputX; 398 mOutputY = outputY; 399 400 if ((flags & DO_EXTRA_OUTPUT) != 0) { 401 if (mOutUri == null) { 402 Log.w(LOGTAG, "cannot write file, no output URI given"); 403 } else { 404 try { 405 mOutStream = getContentResolver().openOutputStream(mOutUri); 406 } catch (FileNotFoundException e) { 407 Log.w(LOGTAG, "cannot write file: " + mOutUri.toString(), e); 408 } 409 } 410 } 411 412 if ((flags & (DO_EXTRA_OUTPUT | DO_SET_WALLPAPER)) != 0) { 413 regenerateInputStream(); 414 } 415 } 416 417 @Override 418 protected Boolean doInBackground(Bitmap... params) { 419 boolean failure = false; 420 Bitmap img = params[0]; 421 422 // Set extra for crop bounds 423 if (mCrop != null && mPhoto != null && mOrig != null) { 424 RectF trueCrop = CropMath.getScaledCropBounds(mCrop, mPhoto, mOrig); 425 Matrix m = new Matrix(); 426 m.setRotate(mRotation); 427 m.mapRect(trueCrop); 428 if (trueCrop != null) { 429 Rect rounded = new Rect(); 430 trueCrop.roundOut(rounded); 431 mResultIntent.putExtra(CropExtras.KEY_CROPPED_RECT, rounded); 432 } 433 } 434 435 // Find the small cropped bitmap that is returned in the intent 436 if ((mFlags & DO_RETURN_DATA) != 0) { 437 assert (img != null); 438 Bitmap ret = getCroppedImage(img, mCrop, mPhoto); 439 if (ret != null) { 440 ret = getDownsampledBitmap(ret, MAX_BMAP_IN_INTENT); 441 } 442 if (ret == null) { 443 Log.w(LOGTAG, "could not downsample bitmap to return in data"); 444 failure = true; 445 } else { 446 if (mRotation > 0) { 447 Matrix m = new Matrix(); 448 m.setRotate(mRotation); 449 Bitmap tmp = Bitmap.createBitmap(ret, 0, 0, ret.getWidth(), 450 ret.getHeight(), m, true); 451 if (tmp != null) { 452 ret = tmp; 453 } 454 } 455 mResultIntent.putExtra(CropExtras.KEY_DATA, ret); 456 } 457 } 458 459 // Do the large cropped bitmap and/or set the wallpaper 460 if ((mFlags & (DO_EXTRA_OUTPUT | DO_SET_WALLPAPER)) != 0 && mInStream != null) { 461 // Find crop bounds (scaled to original image size) 462 RectF trueCrop = CropMath.getScaledCropBounds(mCrop, mPhoto, mOrig); 463 if (trueCrop == null) { 464 Log.w(LOGTAG, "cannot find crop for full size image"); 465 failure = true; 466 return false; 467 } 468 Rect roundedTrueCrop = new Rect(); 469 trueCrop.roundOut(roundedTrueCrop); 470 471 if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) { 472 Log.w(LOGTAG, "crop has bad values for full size image"); 473 failure = true; 474 return false; 475 } 476 477 // Attempt to open a region decoder 478 BitmapRegionDecoder decoder = null; 479 try { 480 decoder = BitmapRegionDecoder.newInstance(mInStream, true); 481 } catch (IOException e) { 482 Log.w(LOGTAG, "cannot open region decoder for file: " + mInUri.toString(), e); 483 } 484 485 Bitmap crop = null; 486 if (decoder != null) { 487 // Do region decoding to get crop bitmap 488 BitmapFactory.Options options = new BitmapFactory.Options(); 489 options.inMutable = true; 490 crop = decoder.decodeRegion(roundedTrueCrop, options); 491 decoder.recycle(); 492 } 493 494 if (crop == null) { 495 // BitmapRegionDecoder has failed, try to crop in-memory 496 regenerateInputStream(); 497 Bitmap fullSize = null; 498 if (mInStream != null) { 499 fullSize = BitmapFactory.decodeStream(mInStream); 500 } 501 if (fullSize != null) { 502 crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, 503 roundedTrueCrop.top, roundedTrueCrop.width(), 504 roundedTrueCrop.height()); 505 } 506 } 507 508 if (crop == null) { 509 Log.w(LOGTAG, "cannot decode file: " + mInUri.toString()); 510 failure = true; 511 return false; 512 } 513 if (mOutputX > 0 && mOutputY > 0) { 514 Matrix m = new Matrix(); 515 RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight()); 516 if (mRotation > 0) { 517 m.setRotate(mRotation); 518 m.mapRect(cropRect); 519 } 520 RectF returnRect = new RectF(0, 0, mOutputX, mOutputY); 521 m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL); 522 m.preRotate(mRotation); 523 Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), 524 (int) returnRect.height(), Bitmap.Config.ARGB_8888); 525 if (tmp != null) { 526 Canvas c = new Canvas(tmp); 527 c.drawBitmap(crop, m, new Paint()); 528 crop = tmp; 529 } 530 } else if (mRotation > 0) { 531 Matrix m = new Matrix(); 532 m.setRotate(mRotation); 533 Bitmap tmp = Bitmap.createBitmap(crop, 0, 0, crop.getWidth(), 534 crop.getHeight(), m, true); 535 if (tmp != null) { 536 crop = tmp; 537 } 538 } 539 // Get output compression format 540 CompressFormat cf = 541 convertExtensionToCompressFormat(getFileExtension(mOutputFormat)); 542 543 // If we only need to output to a URI, compress straight to file 544 if (mFlags == DO_EXTRA_OUTPUT) { 545 if (mOutStream == null 546 || !crop.compress(cf, DEFAULT_COMPRESS_QUALITY, mOutStream)) { 547 Log.w(LOGTAG, "failed to compress bitmap to file: " + mOutUri.toString()); 548 failure = true; 549 } else { 550 mResultIntent.setData(mOutUri); 551 } 552 } else { 553 // Compress to byte array 554 ByteArrayOutputStream tmpOut = new ByteArrayOutputStream(2048); 555 if (crop.compress(cf, DEFAULT_COMPRESS_QUALITY, tmpOut)) { 556 557 // If we need to output to a Uri, write compressed 558 // bitmap out 559 if ((mFlags & DO_EXTRA_OUTPUT) != 0) { 560 if (mOutStream == null) { 561 Log.w(LOGTAG, 562 "failed to compress bitmap to file: " + mOutUri.toString()); 563 failure = true; 564 } else { 565 try { 566 mOutStream.write(tmpOut.toByteArray()); 567 mResultIntent.setData(mOutUri); 568 } catch (IOException e) { 569 Log.w(LOGTAG, 570 "failed to compress bitmap to file: " 571 + mOutUri.toString(), e); 572 failure = true; 573 } 574 } 575 } 576 577 // If we need to set to the wallpaper, set it 578 if ((mFlags & DO_SET_WALLPAPER) != 0 && mWPManager != null) { 579 if (mWPManager == null) { 580 Log.w(LOGTAG, "no wallpaper manager"); 581 failure = true; 582 } else { 583 try { 584 mWPManager.setStream(new ByteArrayInputStream(tmpOut 585 .toByteArray())); 586 } catch (IOException e) { 587 Log.w(LOGTAG, "cannot write stream to wallpaper", e); 588 failure = true; 589 } 590 } 591 } 592 } else { 593 Log.w(LOGTAG, "cannot compress bitmap"); 594 failure = true; 595 } 596 } 597 } 598 return !failure; // True if any of the operations failed 599 } 600 601 @Override 602 protected void onPostExecute(Boolean result) { 603 Utils.closeSilently(mOutStream); 604 Utils.closeSilently(mInStream); 605 doneBitmapIO(result.booleanValue(), mResultIntent); 606 } 607 608 } 609 610 private void done() { 611 finish(); 612 } 613 614 protected static Bitmap getCroppedImage(Bitmap image, RectF cropBounds, RectF photoBounds) { 615 RectF imageBounds = new RectF(0, 0, image.getWidth(), image.getHeight()); 616 RectF crop = CropMath.getScaledCropBounds(cropBounds, photoBounds, imageBounds); 617 if (crop == null) { 618 return null; 619 } 620 Rect intCrop = new Rect(); 621 crop.roundOut(intCrop); 622 return Bitmap.createBitmap(image, intCrop.left, intCrop.top, intCrop.width(), 623 intCrop.height()); 624 } 625 626 protected static Bitmap getDownsampledBitmap(Bitmap image, int max_size) { 627 if (image == null || image.getWidth() == 0 || image.getHeight() == 0 || max_size < 16) { 628 throw new IllegalArgumentException("Bad argument to getDownsampledBitmap()"); 629 } 630 int shifts = 0; 631 int size = CropMath.getBitmapSize(image); 632 while (size > max_size) { 633 shifts++; 634 size /= 4; 635 } 636 Bitmap ret = Bitmap.createScaledBitmap(image, image.getWidth() >> shifts, 637 image.getHeight() >> shifts, true); 638 if (ret == null) { 639 return null; 640 } 641 // Handle edge case for rounding. 642 if (CropMath.getBitmapSize(ret) > max_size) { 643 return Bitmap.createScaledBitmap(ret, ret.getWidth() >> 1, ret.getHeight() >> 1, true); 644 } 645 return ret; 646 } 647 648 /** 649 * Gets the crop extras from the intent, or null if none exist. 650 */ 651 protected static CropExtras getExtrasFromIntent(Intent intent) { 652 Bundle extras = intent.getExtras(); 653 if (extras != null) { 654 return new CropExtras(extras.getInt(CropExtras.KEY_OUTPUT_X, 0), 655 extras.getInt(CropExtras.KEY_OUTPUT_Y, 0), 656 extras.getBoolean(CropExtras.KEY_SCALE, true) && 657 extras.getBoolean(CropExtras.KEY_SCALE_UP_IF_NEEDED, false), 658 extras.getInt(CropExtras.KEY_ASPECT_X, 0), 659 extras.getInt(CropExtras.KEY_ASPECT_Y, 0), 660 extras.getBoolean(CropExtras.KEY_SET_AS_WALLPAPER, false), 661 extras.getBoolean(CropExtras.KEY_RETURN_DATA, false), 662 (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT), 663 extras.getString(CropExtras.KEY_OUTPUT_FORMAT), 664 extras.getBoolean(CropExtras.KEY_SHOW_WHEN_LOCKED, false), 665 extras.getFloat(CropExtras.KEY_SPOTLIGHT_X), 666 extras.getFloat(CropExtras.KEY_SPOTLIGHT_Y)); 667 } 668 return null; 669 } 670 671 protected static CompressFormat convertExtensionToCompressFormat(String extension) { 672 return extension.equals("png") ? CompressFormat.PNG : CompressFormat.JPEG; 673 } 674 675 protected static String getFileExtension(String requestFormat) { 676 String outputFormat = (requestFormat == null) 677 ? "jpg" 678 : requestFormat; 679 outputFormat = outputFormat.toLowerCase(); 680 return (outputFormat.equals("png") || outputFormat.equals("gif")) 681 ? "png" // We don't support gif compression. 682 : "jpg"; 683 } 684 685 private RectF getBitmapCrop(RectF imageBounds) { 686 RectF crop = mCropView.getCrop(); 687 RectF photo = mCropView.getPhoto(); 688 if (crop == null || photo == null) { 689 Log.w(LOGTAG, "could not get crop"); 690 return null; 691 } 692 RectF scaledCrop = CropMath.getScaledCropBounds(crop, photo, imageBounds); 693 return scaledCrop; 694 } 695 } 696