1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2007 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Linimport com.android.gallery.R; 20d6c2fb7a38fcdb58742fcfffd67a4594487ec71cOwen Lin 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImageList; 23666ea1b28a76aeba74744148b15099254d918671Owen Lin 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.WallpaperManager; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver; 26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Context; 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Intent; 28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap; 29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Canvas; 30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix; 31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Path; 32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PointF; 33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PorterDuff; 34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Rect; 35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.RectF; 36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Region; 37666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.media.FaceDetector; 38666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri; 39666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Bundle; 40666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler; 41666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore; 42666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.AttributeSet; 43666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log; 44666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.MotionEvent; 45666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View; 46666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.Window; 47666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.WindowManager; 48666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.Toast; 49666ea1b28a76aeba74744148b15099254d918671Owen Lin 50666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.File; 51666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.IOException; 52666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.OutputStream; 53666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.ArrayList; 54666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.concurrent.CountDownLatch; 55666ea1b28a76aeba74744148b15099254d918671Owen Lin 56666ea1b28a76aeba74744148b15099254d918671Owen Lin/** 57666ea1b28a76aeba74744148b15099254d918671Owen Lin * The activity can crop specific region of interest from an image. 58666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 59666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class CropImage extends MonitoredActivity { 60666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "CropImage"; 61666ea1b28a76aeba74744148b15099254d918671Owen Lin 62666ea1b28a76aeba74744148b15099254d918671Owen Lin // These are various options can be specified in the intent. 63666ea1b28a76aeba74744148b15099254d918671Owen Lin private Bitmap.CompressFormat mOutputFormat = 64666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap.CompressFormat.JPEG; // only used with mSaveUri 65666ea1b28a76aeba74744148b15099254d918671Owen Lin private Uri mSaveUri = null; 66666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mSetWallpaper = false; 67666ea1b28a76aeba74744148b15099254d918671Owen Lin private int mAspectX, mAspectY; 68666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mDoFaceDetection = true; 69666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mCircleCrop = false; 70666ea1b28a76aeba74744148b15099254d918671Owen Lin private final Handler mHandler = new Handler(); 71666ea1b28a76aeba74744148b15099254d918671Owen Lin 72666ea1b28a76aeba74744148b15099254d918671Owen Lin // These options specifiy the output image size and whether we should 73666ea1b28a76aeba74744148b15099254d918671Owen Lin // scale the output to fit it (or just crop it). 74666ea1b28a76aeba74744148b15099254d918671Owen Lin private int mOutputX, mOutputY; 75666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mScale; 76666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mScaleUp = true; 77666ea1b28a76aeba74744148b15099254d918671Owen Lin 78666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean mWaitingToPick; // Whether we are wait the user to pick a face. 79666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean mSaving; // Whether the "save" button is already clicked. 80666ea1b28a76aeba74744148b15099254d918671Owen Lin 81666ea1b28a76aeba74744148b15099254d918671Owen Lin private CropImageView mImageView; 82666ea1b28a76aeba74744148b15099254d918671Owen Lin private ContentResolver mContentResolver; 83666ea1b28a76aeba74744148b15099254d918671Owen Lin 84666ea1b28a76aeba74744148b15099254d918671Owen Lin private Bitmap mBitmap; 85666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView mCrop; 86666ea1b28a76aeba74744148b15099254d918671Owen Lin 87666ea1b28a76aeba74744148b15099254d918671Owen Lin private IImageList mAllImages; 88666ea1b28a76aeba74744148b15099254d918671Owen Lin private IImage mImage; 89666ea1b28a76aeba74744148b15099254d918671Owen Lin 90666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 91666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onCreate(Bundle icicle) { 92666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onCreate(icicle); 93666ea1b28a76aeba74744148b15099254d918671Owen Lin mContentResolver = getContentResolver(); 94666ea1b28a76aeba74744148b15099254d918671Owen Lin 95666ea1b28a76aeba74744148b15099254d918671Owen Lin requestWindowFeature(Window.FEATURE_NO_TITLE); 96666ea1b28a76aeba74744148b15099254d918671Owen Lin setContentView(R.layout.cropimage); 97666ea1b28a76aeba74744148b15099254d918671Owen Lin 98666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView = (CropImageView) findViewById(R.id.image); 99666ea1b28a76aeba74744148b15099254d918671Owen Lin 100666ea1b28a76aeba74744148b15099254d918671Owen Lin MenuHelper.showStorageToast(this); 101666ea1b28a76aeba74744148b15099254d918671Owen Lin 102666ea1b28a76aeba74744148b15099254d918671Owen Lin Intent intent = getIntent(); 103666ea1b28a76aeba74744148b15099254d918671Owen Lin Bundle extras = intent.getExtras(); 104666ea1b28a76aeba74744148b15099254d918671Owen Lin 105666ea1b28a76aeba74744148b15099254d918671Owen Lin if (extras != null) { 106666ea1b28a76aeba74744148b15099254d918671Owen Lin if (extras.getString("circleCrop") != null) { 107666ea1b28a76aeba74744148b15099254d918671Owen Lin mCircleCrop = true; 108666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectX = 1; 109666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectY = 1; 110666ea1b28a76aeba74744148b15099254d918671Owen Lin } 111666ea1b28a76aeba74744148b15099254d918671Owen Lin mSaveUri = (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT); 112666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mSaveUri != null) { 113666ea1b28a76aeba74744148b15099254d918671Owen Lin String outputFormatString = extras.getString("outputFormat"); 114666ea1b28a76aeba74744148b15099254d918671Owen Lin if (outputFormatString != null) { 115666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutputFormat = Bitmap.CompressFormat.valueOf( 116666ea1b28a76aeba74744148b15099254d918671Owen Lin outputFormatString); 117666ea1b28a76aeba74744148b15099254d918671Owen Lin } 118666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 119666ea1b28a76aeba74744148b15099254d918671Owen Lin mSetWallpaper = extras.getBoolean("setWallpaper"); 120666ea1b28a76aeba74744148b15099254d918671Owen Lin } 121666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap = (Bitmap) extras.getParcelable("data"); 122666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectX = extras.getInt("aspectX"); 123666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectY = extras.getInt("aspectY"); 124666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutputX = extras.getInt("outputX"); 125666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutputY = extras.getInt("outputY"); 126666ea1b28a76aeba74744148b15099254d918671Owen Lin mScale = extras.getBoolean("scale", true); 127666ea1b28a76aeba74744148b15099254d918671Owen Lin mScaleUp = extras.getBoolean("scaleUpIfNeeded", true); 128666ea1b28a76aeba74744148b15099254d918671Owen Lin mDoFaceDetection = extras.containsKey("noFaceDetection") 129666ea1b28a76aeba74744148b15099254d918671Owen Lin ? !extras.getBoolean("noFaceDetection") 130666ea1b28a76aeba74744148b15099254d918671Owen Lin : true; 131666ea1b28a76aeba74744148b15099254d918671Owen Lin } 132666ea1b28a76aeba74744148b15099254d918671Owen Lin 133666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmap == null) { 134666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri target = intent.getData(); 135666ea1b28a76aeba74744148b15099254d918671Owen Lin mAllImages = ImageManager.makeImageList(mContentResolver, target, 136666ea1b28a76aeba74744148b15099254d918671Owen Lin ImageManager.SORT_ASCENDING); 137666ea1b28a76aeba74744148b15099254d918671Owen Lin mImage = mAllImages.getImageForUri(target); 138666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mImage != null) { 139666ea1b28a76aeba74744148b15099254d918671Owen Lin // Don't read in really large bitmaps. Use the (big) thumbnail 140666ea1b28a76aeba74744148b15099254d918671Owen Lin // instead. 141666ea1b28a76aeba74744148b15099254d918671Owen Lin // TODO when saving the resulting bitmap use the 142666ea1b28a76aeba74744148b15099254d918671Owen Lin // decode/crop/encode api so we don't lose any resolution. 143666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap = mImage.thumbBitmap(IImage.ROTATE_AS_NEEDED); 144666ea1b28a76aeba74744148b15099254d918671Owen Lin } 145666ea1b28a76aeba74744148b15099254d918671Owen Lin } 146666ea1b28a76aeba74744148b15099254d918671Owen Lin 147666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmap == null) { 148666ea1b28a76aeba74744148b15099254d918671Owen Lin finish(); 149666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 150666ea1b28a76aeba74744148b15099254d918671Owen Lin } 151666ea1b28a76aeba74744148b15099254d918671Owen Lin 152666ea1b28a76aeba74744148b15099254d918671Owen Lin // Make UI fullscreen. 153666ea1b28a76aeba74744148b15099254d918671Owen Lin getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); 154666ea1b28a76aeba74744148b15099254d918671Owen Lin 155666ea1b28a76aeba74744148b15099254d918671Owen Lin findViewById(R.id.discard).setOnClickListener( 156666ea1b28a76aeba74744148b15099254d918671Owen Lin new View.OnClickListener() { 157666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onClick(View v) { 158666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_CANCELED); 159666ea1b28a76aeba74744148b15099254d918671Owen Lin finish(); 160666ea1b28a76aeba74744148b15099254d918671Owen Lin } 161666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 162666ea1b28a76aeba74744148b15099254d918671Owen Lin 163666ea1b28a76aeba74744148b15099254d918671Owen Lin findViewById(R.id.save).setOnClickListener( 164666ea1b28a76aeba74744148b15099254d918671Owen Lin new View.OnClickListener() { 165666ea1b28a76aeba74744148b15099254d918671Owen Lin public void onClick(View v) { 166666ea1b28a76aeba74744148b15099254d918671Owen Lin onSaveClicked(); 167666ea1b28a76aeba74744148b15099254d918671Owen Lin } 168666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 169666ea1b28a76aeba74744148b15099254d918671Owen Lin 170666ea1b28a76aeba74744148b15099254d918671Owen Lin startFaceDetection(); 171666ea1b28a76aeba74744148b15099254d918671Owen Lin } 172666ea1b28a76aeba74744148b15099254d918671Owen Lin 173666ea1b28a76aeba74744148b15099254d918671Owen Lin private void startFaceDetection() { 174666ea1b28a76aeba74744148b15099254d918671Owen Lin if (isFinishing()) { 175666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 176666ea1b28a76aeba74744148b15099254d918671Owen Lin } 177666ea1b28a76aeba74744148b15099254d918671Owen Lin 178666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.setImageBitmapResetBase(mBitmap, true); 179666ea1b28a76aeba74744148b15099254d918671Owen Lin 180666ea1b28a76aeba74744148b15099254d918671Owen Lin Util.startBackgroundJob(this, null, 181666ea1b28a76aeba74744148b15099254d918671Owen Lin getResources().getString(R.string.runningFaceDetection), 182666ea1b28a76aeba74744148b15099254d918671Owen Lin new Runnable() { 183666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 184666ea1b28a76aeba74744148b15099254d918671Owen Lin final CountDownLatch latch = new CountDownLatch(1); 185666ea1b28a76aeba74744148b15099254d918671Owen Lin final Bitmap b = (mImage != null) 186666ea1b28a76aeba74744148b15099254d918671Owen Lin ? mImage.fullSizeBitmap(IImage.UNCONSTRAINED, 187666ea1b28a76aeba74744148b15099254d918671Owen Lin 1024 * 1024) 188666ea1b28a76aeba74744148b15099254d918671Owen Lin : mBitmap; 189666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(new Runnable() { 190666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 191666ea1b28a76aeba74744148b15099254d918671Owen Lin if (b != mBitmap && b != null) { 192666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.setImageBitmapResetBase(b, true); 193666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap.recycle(); 194666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap = b; 195666ea1b28a76aeba74744148b15099254d918671Owen Lin } 196666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mImageView.getScale() == 1F) { 197666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.center(true, true); 198666ea1b28a76aeba74744148b15099254d918671Owen Lin } 199666ea1b28a76aeba74744148b15099254d918671Owen Lin latch.countDown(); 200666ea1b28a76aeba74744148b15099254d918671Owen Lin } 201666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 202666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 203666ea1b28a76aeba74744148b15099254d918671Owen Lin latch.await(); 204666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (InterruptedException e) { 205666ea1b28a76aeba74744148b15099254d918671Owen Lin throw new RuntimeException(e); 206666ea1b28a76aeba74744148b15099254d918671Owen Lin } 207666ea1b28a76aeba74744148b15099254d918671Owen Lin mRunFaceDetection.run(); 208666ea1b28a76aeba74744148b15099254d918671Owen Lin } 209666ea1b28a76aeba74744148b15099254d918671Owen Lin }, mHandler); 210666ea1b28a76aeba74744148b15099254d918671Owen Lin } 211666ea1b28a76aeba74744148b15099254d918671Owen Lin 212666ea1b28a76aeba74744148b15099254d918671Owen Lin private void onSaveClicked() { 213666ea1b28a76aeba74744148b15099254d918671Owen Lin // TODO this code needs to change to use the decode/crop/encode single 214666ea1b28a76aeba74744148b15099254d918671Owen Lin // step api so that we don't require that the whole (possibly large) 215666ea1b28a76aeba74744148b15099254d918671Owen Lin // bitmap doesn't have to be read into memory 216666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mCrop == null) { 217666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 218666ea1b28a76aeba74744148b15099254d918671Owen Lin } 219666ea1b28a76aeba74744148b15099254d918671Owen Lin 220666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mSaving) return; 221666ea1b28a76aeba74744148b15099254d918671Owen Lin mSaving = true; 222666ea1b28a76aeba74744148b15099254d918671Owen Lin 223666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap croppedImage; 224666ea1b28a76aeba74744148b15099254d918671Owen Lin 225666ea1b28a76aeba74744148b15099254d918671Owen Lin // If the output is required to a specific size, create an new image 226666ea1b28a76aeba74744148b15099254d918671Owen Lin // with the cropped image in the center and the extra space filled. 227666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mOutputX != 0 && mOutputY != 0 && !mScale) { 228666ea1b28a76aeba74744148b15099254d918671Owen Lin // Don't scale the image but instead fill it so it's the 229666ea1b28a76aeba74744148b15099254d918671Owen Lin // required dimension 230666ea1b28a76aeba74744148b15099254d918671Owen Lin croppedImage = Bitmap.createBitmap(mOutputX, mOutputY, 231666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap.Config.RGB_565); 232666ea1b28a76aeba74744148b15099254d918671Owen Lin Canvas canvas = new Canvas(croppedImage); 233666ea1b28a76aeba74744148b15099254d918671Owen Lin 234666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect srcRect = mCrop.getCropRect(); 235666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect dstRect = new Rect(0, 0, mOutputX, mOutputY); 236666ea1b28a76aeba74744148b15099254d918671Owen Lin 237666ea1b28a76aeba74744148b15099254d918671Owen Lin int dx = (srcRect.width() - dstRect.width()) / 2; 238666ea1b28a76aeba74744148b15099254d918671Owen Lin int dy = (srcRect.height() - dstRect.height()) / 2; 239666ea1b28a76aeba74744148b15099254d918671Owen Lin 240666ea1b28a76aeba74744148b15099254d918671Owen Lin // If the srcRect is too big, use the center part of it. 241666ea1b28a76aeba74744148b15099254d918671Owen Lin srcRect.inset(Math.max(0, dx), Math.max(0, dy)); 242666ea1b28a76aeba74744148b15099254d918671Owen Lin 243666ea1b28a76aeba74744148b15099254d918671Owen Lin // If the dstRect is too big, use the center part of it. 244666ea1b28a76aeba74744148b15099254d918671Owen Lin dstRect.inset(Math.max(0, -dx), Math.max(0, -dy)); 245666ea1b28a76aeba74744148b15099254d918671Owen Lin 246666ea1b28a76aeba74744148b15099254d918671Owen Lin // Draw the cropped bitmap in the center 247666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.drawBitmap(mBitmap, srcRect, dstRect, null); 248666ea1b28a76aeba74744148b15099254d918671Owen Lin 249666ea1b28a76aeba74744148b15099254d918671Owen Lin // Release bitmap memory as soon as possible 250666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.clear(); 251666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap.recycle(); 252666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 253666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect r = mCrop.getCropRect(); 254666ea1b28a76aeba74744148b15099254d918671Owen Lin 255666ea1b28a76aeba74744148b15099254d918671Owen Lin int width = r.width(); 256666ea1b28a76aeba74744148b15099254d918671Owen Lin int height = r.height(); 257666ea1b28a76aeba74744148b15099254d918671Owen Lin 258666ea1b28a76aeba74744148b15099254d918671Owen Lin // If we are circle cropping, we want alpha channel, which is the 259666ea1b28a76aeba74744148b15099254d918671Owen Lin // third param here. 260666ea1b28a76aeba74744148b15099254d918671Owen Lin croppedImage = Bitmap.createBitmap(width, height, 261666ea1b28a76aeba74744148b15099254d918671Owen Lin mCircleCrop 262666ea1b28a76aeba74744148b15099254d918671Owen Lin ? Bitmap.Config.ARGB_8888 263666ea1b28a76aeba74744148b15099254d918671Owen Lin : Bitmap.Config.RGB_565); 264666ea1b28a76aeba74744148b15099254d918671Owen Lin 265666ea1b28a76aeba74744148b15099254d918671Owen Lin Canvas canvas = new Canvas(croppedImage); 266666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect dstRect = new Rect(0, 0, width, height); 267666ea1b28a76aeba74744148b15099254d918671Owen Lin canvas.drawBitmap(mBitmap, r, dstRect, null); 268666ea1b28a76aeba74744148b15099254d918671Owen Lin 269666ea1b28a76aeba74744148b15099254d918671Owen Lin // Release bitmap memory as soon as possible 270666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.clear(); 271666ea1b28a76aeba74744148b15099254d918671Owen Lin mBitmap.recycle(); 272666ea1b28a76aeba74744148b15099254d918671Owen Lin 273666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mCircleCrop) { 274666ea1b28a76aeba74744148b15099254d918671Owen Lin // OK, so what's all this about? 275666ea1b28a76aeba74744148b15099254d918671Owen Lin // Bitmaps are inherently rectangular but we want to return 276666ea1b28a76aeba74744148b15099254d918671Owen Lin // something that's basically a circle. So we fill in the 277666ea1b28a76aeba74744148b15099254d918671Owen Lin // area around the circle with alpha. Note the all important 278666ea1b28a76aeba74744148b15099254d918671Owen Lin // PortDuff.Mode.CLEAR. 279666ea1b28a76aeba74744148b15099254d918671Owen Lin Canvas c = new Canvas(croppedImage); 280666ea1b28a76aeba74744148b15099254d918671Owen Lin Path p = new Path(); 281666ea1b28a76aeba74744148b15099254d918671Owen Lin p.addCircle(width / 2F, height / 2F, width / 2F, 282666ea1b28a76aeba74744148b15099254d918671Owen Lin Path.Direction.CW); 283666ea1b28a76aeba74744148b15099254d918671Owen Lin c.clipPath(p, Region.Op.DIFFERENCE); 284666ea1b28a76aeba74744148b15099254d918671Owen Lin c.drawColor(0x00000000, PorterDuff.Mode.CLEAR); 285666ea1b28a76aeba74744148b15099254d918671Owen Lin } 286666ea1b28a76aeba74744148b15099254d918671Owen Lin 287666ea1b28a76aeba74744148b15099254d918671Owen Lin // If the required dimension is specified, scale the image. 288666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mOutputX != 0 && mOutputY != 0 && mScale) { 289666ea1b28a76aeba74744148b15099254d918671Owen Lin croppedImage = Util.transform(new Matrix(), croppedImage, 290666ea1b28a76aeba74744148b15099254d918671Owen Lin mOutputX, mOutputY, mScaleUp, Util.RECYCLE_INPUT); 291666ea1b28a76aeba74744148b15099254d918671Owen Lin } 292666ea1b28a76aeba74744148b15099254d918671Owen Lin } 293666ea1b28a76aeba74744148b15099254d918671Owen Lin 294666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.setImageBitmapResetBase(croppedImage, true); 295666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.center(true, true); 296666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.mHighlightViews.clear(); 297666ea1b28a76aeba74744148b15099254d918671Owen Lin 298666ea1b28a76aeba74744148b15099254d918671Owen Lin // Return the cropped image directly or save it to the specified URI. 299666ea1b28a76aeba74744148b15099254d918671Owen Lin Bundle myExtras = getIntent().getExtras(); 300666ea1b28a76aeba74744148b15099254d918671Owen Lin if (myExtras != null && (myExtras.getParcelable("data") != null 301666ea1b28a76aeba74744148b15099254d918671Owen Lin || myExtras.getBoolean("return-data"))) { 302666ea1b28a76aeba74744148b15099254d918671Owen Lin Bundle extras = new Bundle(); 303666ea1b28a76aeba74744148b15099254d918671Owen Lin extras.putParcelable("data", croppedImage); 304666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_OK, 305666ea1b28a76aeba74744148b15099254d918671Owen Lin (new Intent()).setAction("inline-data").putExtras(extras)); 306666ea1b28a76aeba74744148b15099254d918671Owen Lin finish(); 307666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 308666ea1b28a76aeba74744148b15099254d918671Owen Lin final Bitmap b = croppedImage; 309666ea1b28a76aeba74744148b15099254d918671Owen Lin final int msdId = mSetWallpaper 310666ea1b28a76aeba74744148b15099254d918671Owen Lin ? R.string.wallpaper 311666ea1b28a76aeba74744148b15099254d918671Owen Lin : R.string.savingImage; 312666ea1b28a76aeba74744148b15099254d918671Owen Lin Util.startBackgroundJob(this, null, 313666ea1b28a76aeba74744148b15099254d918671Owen Lin getResources().getString(msdId), 314666ea1b28a76aeba74744148b15099254d918671Owen Lin new Runnable() { 315666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 316666ea1b28a76aeba74744148b15099254d918671Owen Lin saveOutput(b); 317666ea1b28a76aeba74744148b15099254d918671Owen Lin } 318666ea1b28a76aeba74744148b15099254d918671Owen Lin }, mHandler); 319666ea1b28a76aeba74744148b15099254d918671Owen Lin } 320666ea1b28a76aeba74744148b15099254d918671Owen Lin } 321666ea1b28a76aeba74744148b15099254d918671Owen Lin 322666ea1b28a76aeba74744148b15099254d918671Owen Lin private void saveOutput(Bitmap croppedImage) { 323666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mSaveUri != null) { 324666ea1b28a76aeba74744148b15099254d918671Owen Lin OutputStream outputStream = null; 325666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 326666ea1b28a76aeba74744148b15099254d918671Owen Lin outputStream = mContentResolver.openOutputStream(mSaveUri); 327666ea1b28a76aeba74744148b15099254d918671Owen Lin if (outputStream != null) { 328666ea1b28a76aeba74744148b15099254d918671Owen Lin croppedImage.compress(mOutputFormat, 75, outputStream); 329666ea1b28a76aeba74744148b15099254d918671Owen Lin } 330666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (IOException ex) { 331666ea1b28a76aeba74744148b15099254d918671Owen Lin // TODO: report error to caller 332666ea1b28a76aeba74744148b15099254d918671Owen Lin Log.e(TAG, "Cannot open file: " + mSaveUri, ex); 333666ea1b28a76aeba74744148b15099254d918671Owen Lin } finally { 334666ea1b28a76aeba74744148b15099254d918671Owen Lin Util.closeSilently(outputStream); 335666ea1b28a76aeba74744148b15099254d918671Owen Lin } 336666ea1b28a76aeba74744148b15099254d918671Owen Lin Bundle extras = new Bundle(); 337666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_OK, new Intent(mSaveUri.toString()) 338666ea1b28a76aeba74744148b15099254d918671Owen Lin .putExtras(extras)); 339666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (mSetWallpaper) { 340666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 341666ea1b28a76aeba74744148b15099254d918671Owen Lin WallpaperManager.getInstance(this).setBitmap(croppedImage); 342666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_OK); 343666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (IOException e) { 344666ea1b28a76aeba74744148b15099254d918671Owen Lin Log.e(TAG, "Failed to set wallpaper.", e); 345666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_CANCELED); 346666ea1b28a76aeba74744148b15099254d918671Owen Lin } 347666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 348666ea1b28a76aeba74744148b15099254d918671Owen Lin Bundle extras = new Bundle(); 349666ea1b28a76aeba74744148b15099254d918671Owen Lin extras.putString("rect", mCrop.getCropRect().toString()); 350666ea1b28a76aeba74744148b15099254d918671Owen Lin 351666ea1b28a76aeba74744148b15099254d918671Owen Lin File oldPath = new File(mImage.getDataPath()); 352666ea1b28a76aeba74744148b15099254d918671Owen Lin File directory = new File(oldPath.getParent()); 353666ea1b28a76aeba74744148b15099254d918671Owen Lin 354666ea1b28a76aeba74744148b15099254d918671Owen Lin int x = 0; 355666ea1b28a76aeba74744148b15099254d918671Owen Lin String fileName = oldPath.getName(); 356666ea1b28a76aeba74744148b15099254d918671Owen Lin fileName = fileName.substring(0, fileName.lastIndexOf(".")); 357666ea1b28a76aeba74744148b15099254d918671Owen Lin 358666ea1b28a76aeba74744148b15099254d918671Owen Lin // Try file-1.jpg, file-2.jpg, ... until we find a filename which 359666ea1b28a76aeba74744148b15099254d918671Owen Lin // does not exist yet. 360666ea1b28a76aeba74744148b15099254d918671Owen Lin while (true) { 361666ea1b28a76aeba74744148b15099254d918671Owen Lin x += 1; 362666ea1b28a76aeba74744148b15099254d918671Owen Lin String candidate = directory.toString() 363666ea1b28a76aeba74744148b15099254d918671Owen Lin + "/" + fileName + "-" + x + ".jpg"; 364666ea1b28a76aeba74744148b15099254d918671Owen Lin boolean exists = (new File(candidate)).exists(); 365666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!exists) { 366666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 367666ea1b28a76aeba74744148b15099254d918671Owen Lin } 368666ea1b28a76aeba74744148b15099254d918671Owen Lin } 369666ea1b28a76aeba74744148b15099254d918671Owen Lin 370666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 371666ea1b28a76aeba74744148b15099254d918671Owen Lin int[] degree = new int[1]; 372666ea1b28a76aeba74744148b15099254d918671Owen Lin Uri newUri = ImageManager.addImage( 373666ea1b28a76aeba74744148b15099254d918671Owen Lin mContentResolver, 374666ea1b28a76aeba74744148b15099254d918671Owen Lin mImage.getTitle(), 375666ea1b28a76aeba74744148b15099254d918671Owen Lin mImage.getDateTaken(), 376666ea1b28a76aeba74744148b15099254d918671Owen Lin null, // TODO this null is going to cause us to lose 377666ea1b28a76aeba74744148b15099254d918671Owen Lin // the location (gps). 378666ea1b28a76aeba74744148b15099254d918671Owen Lin directory.toString(), fileName + "-" + x + ".jpg", 379666ea1b28a76aeba74744148b15099254d918671Owen Lin croppedImage, null, 380666ea1b28a76aeba74744148b15099254d918671Owen Lin degree); 381666ea1b28a76aeba74744148b15099254d918671Owen Lin 382666ea1b28a76aeba74744148b15099254d918671Owen Lin setResult(RESULT_OK, new Intent() 383666ea1b28a76aeba74744148b15099254d918671Owen Lin .setAction(newUri.toString()) 384666ea1b28a76aeba74744148b15099254d918671Owen Lin .putExtras(extras)); 385666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (Exception ex) { 386666ea1b28a76aeba74744148b15099254d918671Owen Lin // basically ignore this or put up 387666ea1b28a76aeba74744148b15099254d918671Owen Lin // some ui saying we failed 388666ea1b28a76aeba74744148b15099254d918671Owen Lin Log.e(TAG, "store image fail, continue anyway", ex); 389666ea1b28a76aeba74744148b15099254d918671Owen Lin } 390666ea1b28a76aeba74744148b15099254d918671Owen Lin } 391666ea1b28a76aeba74744148b15099254d918671Owen Lin 392666ea1b28a76aeba74744148b15099254d918671Owen Lin final Bitmap b = croppedImage; 393666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(new Runnable() { 394666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 395666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.clear(); 396666ea1b28a76aeba74744148b15099254d918671Owen Lin b.recycle(); 397666ea1b28a76aeba74744148b15099254d918671Owen Lin } 398666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 399666ea1b28a76aeba74744148b15099254d918671Owen Lin 400666ea1b28a76aeba74744148b15099254d918671Owen Lin finish(); 401666ea1b28a76aeba74744148b15099254d918671Owen Lin } 402666ea1b28a76aeba74744148b15099254d918671Owen Lin 403666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 404666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void onPause() { 405666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onPause(); 406666ea1b28a76aeba74744148b15099254d918671Owen Lin } 407666ea1b28a76aeba74744148b15099254d918671Owen Lin 408666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 409666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void onDestroy() { 410666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mAllImages != null) { 411666ea1b28a76aeba74744148b15099254d918671Owen Lin mAllImages.close(); 412666ea1b28a76aeba74744148b15099254d918671Owen Lin } 413666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onDestroy(); 414666ea1b28a76aeba74744148b15099254d918671Owen Lin } 415666ea1b28a76aeba74744148b15099254d918671Owen Lin 416666ea1b28a76aeba74744148b15099254d918671Owen Lin Runnable mRunFaceDetection = new Runnable() { 417666ea1b28a76aeba74744148b15099254d918671Owen Lin @SuppressWarnings("hiding") 418666ea1b28a76aeba74744148b15099254d918671Owen Lin float mScale = 1F; 419666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix mImageMatrix; 420666ea1b28a76aeba74744148b15099254d918671Owen Lin FaceDetector.Face[] mFaces = new FaceDetector.Face[3]; 421666ea1b28a76aeba74744148b15099254d918671Owen Lin int mNumFaces; 422666ea1b28a76aeba74744148b15099254d918671Owen Lin 423666ea1b28a76aeba74744148b15099254d918671Owen Lin // For each face, we create a HightlightView for it. 424666ea1b28a76aeba74744148b15099254d918671Owen Lin private void handleFace(FaceDetector.Face f) { 425666ea1b28a76aeba74744148b15099254d918671Owen Lin PointF midPoint = new PointF(); 426666ea1b28a76aeba74744148b15099254d918671Owen Lin 427666ea1b28a76aeba74744148b15099254d918671Owen Lin int r = ((int) (f.eyesDistance() * mScale)) * 2; 428666ea1b28a76aeba74744148b15099254d918671Owen Lin f.getMidPoint(midPoint); 429666ea1b28a76aeba74744148b15099254d918671Owen Lin midPoint.x *= mScale; 430666ea1b28a76aeba74744148b15099254d918671Owen Lin midPoint.y *= mScale; 431666ea1b28a76aeba74744148b15099254d918671Owen Lin 432666ea1b28a76aeba74744148b15099254d918671Owen Lin int midX = (int) midPoint.x; 433666ea1b28a76aeba74744148b15099254d918671Owen Lin int midY = (int) midPoint.y; 434666ea1b28a76aeba74744148b15099254d918671Owen Lin 435666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = new HighlightView(mImageView); 436666ea1b28a76aeba74744148b15099254d918671Owen Lin 437666ea1b28a76aeba74744148b15099254d918671Owen Lin int width = mBitmap.getWidth(); 438666ea1b28a76aeba74744148b15099254d918671Owen Lin int height = mBitmap.getHeight(); 439666ea1b28a76aeba74744148b15099254d918671Owen Lin 440666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect imageRect = new Rect(0, 0, width, height); 441666ea1b28a76aeba74744148b15099254d918671Owen Lin 442666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF faceRect = new RectF(midX, midY, midX, midY); 443666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.inset(-r, -r); 444666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceRect.left < 0) { 445666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.inset(-faceRect.left, -faceRect.left); 446666ea1b28a76aeba74744148b15099254d918671Owen Lin } 447666ea1b28a76aeba74744148b15099254d918671Owen Lin 448666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceRect.top < 0) { 449666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.inset(-faceRect.top, -faceRect.top); 450666ea1b28a76aeba74744148b15099254d918671Owen Lin } 451666ea1b28a76aeba74744148b15099254d918671Owen Lin 452666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceRect.right > imageRect.right) { 453666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.inset(faceRect.right - imageRect.right, 454666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.right - imageRect.right); 455666ea1b28a76aeba74744148b15099254d918671Owen Lin } 456666ea1b28a76aeba74744148b15099254d918671Owen Lin 457666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceRect.bottom > imageRect.bottom) { 458666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.inset(faceRect.bottom - imageRect.bottom, 459666ea1b28a76aeba74744148b15099254d918671Owen Lin faceRect.bottom - imageRect.bottom); 460666ea1b28a76aeba74744148b15099254d918671Owen Lin } 461666ea1b28a76aeba74744148b15099254d918671Owen Lin 462666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.setup(mImageMatrix, imageRect, faceRect, mCircleCrop, 463666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectX != 0 && mAspectY != 0); 464666ea1b28a76aeba74744148b15099254d918671Owen Lin 465666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.add(hv); 466666ea1b28a76aeba74744148b15099254d918671Owen Lin } 467666ea1b28a76aeba74744148b15099254d918671Owen Lin 468666ea1b28a76aeba74744148b15099254d918671Owen Lin // Create a default HightlightView if we found no face in the picture. 469666ea1b28a76aeba74744148b15099254d918671Owen Lin private void makeDefault() { 470666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = new HighlightView(mImageView); 471666ea1b28a76aeba74744148b15099254d918671Owen Lin 472666ea1b28a76aeba74744148b15099254d918671Owen Lin int width = mBitmap.getWidth(); 473666ea1b28a76aeba74744148b15099254d918671Owen Lin int height = mBitmap.getHeight(); 474666ea1b28a76aeba74744148b15099254d918671Owen Lin 475666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect imageRect = new Rect(0, 0, width, height); 476666ea1b28a76aeba74744148b15099254d918671Owen Lin 477666ea1b28a76aeba74744148b15099254d918671Owen Lin // make the default size about 4/5 of the width or height 478666ea1b28a76aeba74744148b15099254d918671Owen Lin int cropWidth = Math.min(width, height) * 4 / 5; 479666ea1b28a76aeba74744148b15099254d918671Owen Lin int cropHeight = cropWidth; 480666ea1b28a76aeba74744148b15099254d918671Owen Lin 481666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mAspectX != 0 && mAspectY != 0) { 482666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mAspectX > mAspectY) { 483666ea1b28a76aeba74744148b15099254d918671Owen Lin cropHeight = cropWidth * mAspectY / mAspectX; 484666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 485666ea1b28a76aeba74744148b15099254d918671Owen Lin cropWidth = cropHeight * mAspectX / mAspectY; 486666ea1b28a76aeba74744148b15099254d918671Owen Lin } 487666ea1b28a76aeba74744148b15099254d918671Owen Lin } 488666ea1b28a76aeba74744148b15099254d918671Owen Lin 489666ea1b28a76aeba74744148b15099254d918671Owen Lin int x = (width - cropWidth) / 2; 490666ea1b28a76aeba74744148b15099254d918671Owen Lin int y = (height - cropHeight) / 2; 491666ea1b28a76aeba74744148b15099254d918671Owen Lin 492666ea1b28a76aeba74744148b15099254d918671Owen Lin RectF cropRect = new RectF(x, y, x + cropWidth, y + cropHeight); 493666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.setup(mImageMatrix, imageRect, cropRect, mCircleCrop, 494666ea1b28a76aeba74744148b15099254d918671Owen Lin mAspectX != 0 && mAspectY != 0); 495666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.add(hv); 496666ea1b28a76aeba74744148b15099254d918671Owen Lin } 497666ea1b28a76aeba74744148b15099254d918671Owen Lin 498666ea1b28a76aeba74744148b15099254d918671Owen Lin // Scale the image down for faster face detection. 499666ea1b28a76aeba74744148b15099254d918671Owen Lin private Bitmap prepareBitmap() { 500666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmap == null) { 501666ea1b28a76aeba74744148b15099254d918671Owen Lin return null; 502666ea1b28a76aeba74744148b15099254d918671Owen Lin } 503666ea1b28a76aeba74744148b15099254d918671Owen Lin 504666ea1b28a76aeba74744148b15099254d918671Owen Lin // 256 pixels wide is enough. 505666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmap.getWidth() > 256) { 506666ea1b28a76aeba74744148b15099254d918671Owen Lin mScale = 256.0F / mBitmap.getWidth(); 507666ea1b28a76aeba74744148b15099254d918671Owen Lin } 508666ea1b28a76aeba74744148b15099254d918671Owen Lin Matrix matrix = new Matrix(); 509666ea1b28a76aeba74744148b15099254d918671Owen Lin matrix.setScale(mScale, mScale); 510666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap faceBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap 511666ea1b28a76aeba74744148b15099254d918671Owen Lin .getWidth(), mBitmap.getHeight(), matrix, true); 512666ea1b28a76aeba74744148b15099254d918671Owen Lin return faceBitmap; 513666ea1b28a76aeba74744148b15099254d918671Owen Lin } 514666ea1b28a76aeba74744148b15099254d918671Owen Lin 515666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 516666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageMatrix = mImageView.getImageMatrix(); 517666ea1b28a76aeba74744148b15099254d918671Owen Lin Bitmap faceBitmap = prepareBitmap(); 518666ea1b28a76aeba74744148b15099254d918671Owen Lin 519666ea1b28a76aeba74744148b15099254d918671Owen Lin mScale = 1.0F / mScale; 520666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceBitmap != null && mDoFaceDetection) { 521666ea1b28a76aeba74744148b15099254d918671Owen Lin FaceDetector detector = new FaceDetector(faceBitmap.getWidth(), 522666ea1b28a76aeba74744148b15099254d918671Owen Lin faceBitmap.getHeight(), mFaces.length); 523666ea1b28a76aeba74744148b15099254d918671Owen Lin mNumFaces = detector.findFaces(faceBitmap, mFaces); 524666ea1b28a76aeba74744148b15099254d918671Owen Lin } 525666ea1b28a76aeba74744148b15099254d918671Owen Lin 526666ea1b28a76aeba74744148b15099254d918671Owen Lin if (faceBitmap != null && faceBitmap != mBitmap) { 527666ea1b28a76aeba74744148b15099254d918671Owen Lin faceBitmap.recycle(); 528666ea1b28a76aeba74744148b15099254d918671Owen Lin } 529666ea1b28a76aeba74744148b15099254d918671Owen Lin 530666ea1b28a76aeba74744148b15099254d918671Owen Lin mHandler.post(new Runnable() { 531666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 532666ea1b28a76aeba74744148b15099254d918671Owen Lin mWaitingToPick = mNumFaces > 1; 533666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mNumFaces > 0) { 534666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mNumFaces; i++) { 535666ea1b28a76aeba74744148b15099254d918671Owen Lin handleFace(mFaces[i]); 536666ea1b28a76aeba74744148b15099254d918671Owen Lin } 537666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 538666ea1b28a76aeba74744148b15099254d918671Owen Lin makeDefault(); 539666ea1b28a76aeba74744148b15099254d918671Owen Lin } 540666ea1b28a76aeba74744148b15099254d918671Owen Lin mImageView.invalidate(); 541666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mImageView.mHighlightViews.size() == 1) { 542666ea1b28a76aeba74744148b15099254d918671Owen Lin mCrop = mImageView.mHighlightViews.get(0); 543666ea1b28a76aeba74744148b15099254d918671Owen Lin mCrop.setFocus(true); 544666ea1b28a76aeba74744148b15099254d918671Owen Lin } 545666ea1b28a76aeba74744148b15099254d918671Owen Lin 546666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mNumFaces > 1) { 547666ea1b28a76aeba74744148b15099254d918671Owen Lin Toast t = Toast.makeText(CropImage.this, 548666ea1b28a76aeba74744148b15099254d918671Owen Lin R.string.multiface_crop_help, 549666ea1b28a76aeba74744148b15099254d918671Owen Lin Toast.LENGTH_SHORT); 550666ea1b28a76aeba74744148b15099254d918671Owen Lin t.show(); 551666ea1b28a76aeba74744148b15099254d918671Owen Lin } 552666ea1b28a76aeba74744148b15099254d918671Owen Lin } 553666ea1b28a76aeba74744148b15099254d918671Owen Lin }); 554666ea1b28a76aeba74744148b15099254d918671Owen Lin } 555666ea1b28a76aeba74744148b15099254d918671Owen Lin }; 556666ea1b28a76aeba74744148b15099254d918671Owen Lin} 557666ea1b28a76aeba74744148b15099254d918671Owen Lin 558666ea1b28a76aeba74744148b15099254d918671Owen Linclass CropImageView extends ImageViewTouchBase { 559666ea1b28a76aeba74744148b15099254d918671Owen Lin ArrayList<HighlightView> mHighlightViews = new ArrayList<HighlightView>(); 560666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView mMotionHighlightView = null; 561666ea1b28a76aeba74744148b15099254d918671Owen Lin float mLastX, mLastY; 562666ea1b28a76aeba74744148b15099254d918671Owen Lin int mMotionEdge; 563666ea1b28a76aeba74744148b15099254d918671Owen Lin 564666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 565666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void onLayout(boolean changed, int left, int top, 566666ea1b28a76aeba74744148b15099254d918671Owen Lin int right, int bottom) { 567666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onLayout(changed, left, top, right, bottom); 568666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mBitmapDisplayed.getBitmap() != null) { 569666ea1b28a76aeba74744148b15099254d918671Owen Lin for (HighlightView hv : mHighlightViews) { 570666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mMatrix.set(getImageMatrix()); 571666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 572666ea1b28a76aeba74744148b15099254d918671Owen Lin if (hv.mIsFocused) { 573666ea1b28a76aeba74744148b15099254d918671Owen Lin centerBasedOnHighlightView(hv); 574666ea1b28a76aeba74744148b15099254d918671Owen Lin } 575666ea1b28a76aeba74744148b15099254d918671Owen Lin } 576666ea1b28a76aeba74744148b15099254d918671Owen Lin } 577666ea1b28a76aeba74744148b15099254d918671Owen Lin } 578666ea1b28a76aeba74744148b15099254d918671Owen Lin 579666ea1b28a76aeba74744148b15099254d918671Owen Lin public CropImageView(Context context, AttributeSet attrs) { 580666ea1b28a76aeba74744148b15099254d918671Owen Lin super(context, attrs); 581666ea1b28a76aeba74744148b15099254d918671Owen Lin } 582666ea1b28a76aeba74744148b15099254d918671Owen Lin 583666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 584666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomTo(float scale, float centerX, float centerY) { 585666ea1b28a76aeba74744148b15099254d918671Owen Lin super.zoomTo(scale, centerX, centerY); 586666ea1b28a76aeba74744148b15099254d918671Owen Lin for (HighlightView hv : mHighlightViews) { 587666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mMatrix.set(getImageMatrix()); 588666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 589666ea1b28a76aeba74744148b15099254d918671Owen Lin } 590666ea1b28a76aeba74744148b15099254d918671Owen Lin } 591666ea1b28a76aeba74744148b15099254d918671Owen Lin 592666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 593666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomIn() { 594666ea1b28a76aeba74744148b15099254d918671Owen Lin super.zoomIn(); 595666ea1b28a76aeba74744148b15099254d918671Owen Lin for (HighlightView hv : mHighlightViews) { 596666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mMatrix.set(getImageMatrix()); 597666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 598666ea1b28a76aeba74744148b15099254d918671Owen Lin } 599666ea1b28a76aeba74744148b15099254d918671Owen Lin } 600666ea1b28a76aeba74744148b15099254d918671Owen Lin 601666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 602666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void zoomOut() { 603666ea1b28a76aeba74744148b15099254d918671Owen Lin super.zoomOut(); 604666ea1b28a76aeba74744148b15099254d918671Owen Lin for (HighlightView hv : mHighlightViews) { 605666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mMatrix.set(getImageMatrix()); 606666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 607666ea1b28a76aeba74744148b15099254d918671Owen Lin } 608666ea1b28a76aeba74744148b15099254d918671Owen Lin } 609666ea1b28a76aeba74744148b15099254d918671Owen Lin 610666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 611666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void postTranslate(float deltaX, float deltaY) { 612666ea1b28a76aeba74744148b15099254d918671Owen Lin super.postTranslate(deltaX, deltaY); 613666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 614666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = mHighlightViews.get(i); 615666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mMatrix.postTranslate(deltaX, deltaY); 616666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 617666ea1b28a76aeba74744148b15099254d918671Owen Lin } 618666ea1b28a76aeba74744148b15099254d918671Owen Lin } 619666ea1b28a76aeba74744148b15099254d918671Owen Lin 620666ea1b28a76aeba74744148b15099254d918671Owen Lin // According to the event's position, change the focus to the first 621666ea1b28a76aeba74744148b15099254d918671Owen Lin // hitting cropping rectangle. 622666ea1b28a76aeba74744148b15099254d918671Owen Lin private void recomputeFocus(MotionEvent event) { 623666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 624666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = mHighlightViews.get(i); 625666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.setFocus(false); 626666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 627666ea1b28a76aeba74744148b15099254d918671Owen Lin } 628666ea1b28a76aeba74744148b15099254d918671Owen Lin 629666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 630666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = mHighlightViews.get(i); 631666ea1b28a76aeba74744148b15099254d918671Owen Lin int edge = hv.getHit(event.getX(), event.getY()); 632666ea1b28a76aeba74744148b15099254d918671Owen Lin if (edge != HighlightView.GROW_NONE) { 633666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!hv.hasFocus()) { 634666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.setFocus(true); 635666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.invalidate(); 636666ea1b28a76aeba74744148b15099254d918671Owen Lin } 637666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 638666ea1b28a76aeba74744148b15099254d918671Owen Lin } 639666ea1b28a76aeba74744148b15099254d918671Owen Lin } 640666ea1b28a76aeba74744148b15099254d918671Owen Lin invalidate(); 641666ea1b28a76aeba74744148b15099254d918671Owen Lin } 642666ea1b28a76aeba74744148b15099254d918671Owen Lin 643666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 644666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean onTouchEvent(MotionEvent event) { 645666ea1b28a76aeba74744148b15099254d918671Owen Lin CropImage cropImage = (CropImage) mContext; 646666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cropImage.mSaving) { 647666ea1b28a76aeba74744148b15099254d918671Owen Lin return false; 648666ea1b28a76aeba74744148b15099254d918671Owen Lin } 649666ea1b28a76aeba74744148b15099254d918671Owen Lin 650666ea1b28a76aeba74744148b15099254d918671Owen Lin switch (event.getAction()) { 651666ea1b28a76aeba74744148b15099254d918671Owen Lin case MotionEvent.ACTION_DOWN: 652666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cropImage.mWaitingToPick) { 653666ea1b28a76aeba74744148b15099254d918671Owen Lin recomputeFocus(event); 654666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 655666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 656666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = mHighlightViews.get(i); 657666ea1b28a76aeba74744148b15099254d918671Owen Lin int edge = hv.getHit(event.getX(), event.getY()); 658666ea1b28a76aeba74744148b15099254d918671Owen Lin if (edge != HighlightView.GROW_NONE) { 659666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionEdge = edge; 660666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionHighlightView = hv; 661666ea1b28a76aeba74744148b15099254d918671Owen Lin mLastX = event.getX(); 662666ea1b28a76aeba74744148b15099254d918671Owen Lin mLastY = event.getY(); 663666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionHighlightView.setMode( 664666ea1b28a76aeba74744148b15099254d918671Owen Lin (edge == HighlightView.MOVE) 665666ea1b28a76aeba74744148b15099254d918671Owen Lin ? HighlightView.ModifyMode.Move 666666ea1b28a76aeba74744148b15099254d918671Owen Lin : HighlightView.ModifyMode.Grow); 667666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 668666ea1b28a76aeba74744148b15099254d918671Owen Lin } 669666ea1b28a76aeba74744148b15099254d918671Owen Lin } 670666ea1b28a76aeba74744148b15099254d918671Owen Lin } 671666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 672666ea1b28a76aeba74744148b15099254d918671Owen Lin case MotionEvent.ACTION_UP: 673666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cropImage.mWaitingToPick) { 674666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 675666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView hv = mHighlightViews.get(i); 676666ea1b28a76aeba74744148b15099254d918671Owen Lin if (hv.hasFocus()) { 677666ea1b28a76aeba74744148b15099254d918671Owen Lin cropImage.mCrop = hv; 678666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int j = 0; j < mHighlightViews.size(); j++) { 679666ea1b28a76aeba74744148b15099254d918671Owen Lin if (j == i) { 680666ea1b28a76aeba74744148b15099254d918671Owen Lin continue; 681666ea1b28a76aeba74744148b15099254d918671Owen Lin } 682666ea1b28a76aeba74744148b15099254d918671Owen Lin mHighlightViews.get(j).setHidden(true); 683666ea1b28a76aeba74744148b15099254d918671Owen Lin } 684666ea1b28a76aeba74744148b15099254d918671Owen Lin centerBasedOnHighlightView(hv); 685666ea1b28a76aeba74744148b15099254d918671Owen Lin ((CropImage) mContext).mWaitingToPick = false; 686666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 687666ea1b28a76aeba74744148b15099254d918671Owen Lin } 688666ea1b28a76aeba74744148b15099254d918671Owen Lin } 689666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (mMotionHighlightView != null) { 690666ea1b28a76aeba74744148b15099254d918671Owen Lin centerBasedOnHighlightView(mMotionHighlightView); 691666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionHighlightView.setMode( 692666ea1b28a76aeba74744148b15099254d918671Owen Lin HighlightView.ModifyMode.None); 693666ea1b28a76aeba74744148b15099254d918671Owen Lin } 694666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionHighlightView = null; 695666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 696666ea1b28a76aeba74744148b15099254d918671Owen Lin case MotionEvent.ACTION_MOVE: 697666ea1b28a76aeba74744148b15099254d918671Owen Lin if (cropImage.mWaitingToPick) { 698666ea1b28a76aeba74744148b15099254d918671Owen Lin recomputeFocus(event); 699666ea1b28a76aeba74744148b15099254d918671Owen Lin } else if (mMotionHighlightView != null) { 700666ea1b28a76aeba74744148b15099254d918671Owen Lin mMotionHighlightView.handleMotion(mMotionEdge, 701666ea1b28a76aeba74744148b15099254d918671Owen Lin event.getX() - mLastX, 702666ea1b28a76aeba74744148b15099254d918671Owen Lin event.getY() - mLastY); 703666ea1b28a76aeba74744148b15099254d918671Owen Lin mLastX = event.getX(); 704666ea1b28a76aeba74744148b15099254d918671Owen Lin mLastY = event.getY(); 705666ea1b28a76aeba74744148b15099254d918671Owen Lin 706666ea1b28a76aeba74744148b15099254d918671Owen Lin if (true) { 707666ea1b28a76aeba74744148b15099254d918671Owen Lin // This section of code is optional. It has some user 708666ea1b28a76aeba74744148b15099254d918671Owen Lin // benefit in that moving the crop rectangle against 709666ea1b28a76aeba74744148b15099254d918671Owen Lin // the edge of the screen causes scrolling but it means 710666ea1b28a76aeba74744148b15099254d918671Owen Lin // that the crop rectangle is no longer fixed under 711666ea1b28a76aeba74744148b15099254d918671Owen Lin // the user's finger. 712666ea1b28a76aeba74744148b15099254d918671Owen Lin ensureVisible(mMotionHighlightView); 713666ea1b28a76aeba74744148b15099254d918671Owen Lin } 714666ea1b28a76aeba74744148b15099254d918671Owen Lin } 715666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 716666ea1b28a76aeba74744148b15099254d918671Owen Lin } 717666ea1b28a76aeba74744148b15099254d918671Owen Lin 718666ea1b28a76aeba74744148b15099254d918671Owen Lin switch (event.getAction()) { 719666ea1b28a76aeba74744148b15099254d918671Owen Lin case MotionEvent.ACTION_UP: 720666ea1b28a76aeba74744148b15099254d918671Owen Lin center(true, true); 721666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 722666ea1b28a76aeba74744148b15099254d918671Owen Lin case MotionEvent.ACTION_MOVE: 723666ea1b28a76aeba74744148b15099254d918671Owen Lin // if we're not zoomed then there's no point in even allowing 724666ea1b28a76aeba74744148b15099254d918671Owen Lin // the user to move the image around. This call to center puts 725666ea1b28a76aeba74744148b15099254d918671Owen Lin // it back to the normalized location (with false meaning don't 726666ea1b28a76aeba74744148b15099254d918671Owen Lin // animate). 727666ea1b28a76aeba74744148b15099254d918671Owen Lin if (getScale() == 1F) { 728666ea1b28a76aeba74744148b15099254d918671Owen Lin center(true, true); 729666ea1b28a76aeba74744148b15099254d918671Owen Lin } 730666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 731666ea1b28a76aeba74744148b15099254d918671Owen Lin } 732666ea1b28a76aeba74744148b15099254d918671Owen Lin 733666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 734666ea1b28a76aeba74744148b15099254d918671Owen Lin } 735666ea1b28a76aeba74744148b15099254d918671Owen Lin 736666ea1b28a76aeba74744148b15099254d918671Owen Lin // Pan the displayed image to make sure the cropping rectangle is visible. 737666ea1b28a76aeba74744148b15099254d918671Owen Lin private void ensureVisible(HighlightView hv) { 738666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect r = hv.mDrawRect; 739666ea1b28a76aeba74744148b15099254d918671Owen Lin 740666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaX1 = Math.max(0, mLeft - r.left); 741666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaX2 = Math.min(0, mRight - r.right); 742666ea1b28a76aeba74744148b15099254d918671Owen Lin 743666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaY1 = Math.max(0, mTop - r.top); 744666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaY2 = Math.min(0, mBottom - r.bottom); 745666ea1b28a76aeba74744148b15099254d918671Owen Lin 746666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2; 747666ea1b28a76aeba74744148b15099254d918671Owen Lin int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2; 748666ea1b28a76aeba74744148b15099254d918671Owen Lin 749666ea1b28a76aeba74744148b15099254d918671Owen Lin if (panDeltaX != 0 || panDeltaY != 0) { 750666ea1b28a76aeba74744148b15099254d918671Owen Lin panBy(panDeltaX, panDeltaY); 751666ea1b28a76aeba74744148b15099254d918671Owen Lin } 752666ea1b28a76aeba74744148b15099254d918671Owen Lin } 753666ea1b28a76aeba74744148b15099254d918671Owen Lin 754666ea1b28a76aeba74744148b15099254d918671Owen Lin // If the cropping rectangle's size changed significantly, change the 755666ea1b28a76aeba74744148b15099254d918671Owen Lin // view's center and scale according to the cropping rectangle. 756666ea1b28a76aeba74744148b15099254d918671Owen Lin private void centerBasedOnHighlightView(HighlightView hv) { 757666ea1b28a76aeba74744148b15099254d918671Owen Lin Rect drawRect = hv.mDrawRect; 758666ea1b28a76aeba74744148b15099254d918671Owen Lin 759666ea1b28a76aeba74744148b15099254d918671Owen Lin float width = drawRect.width(); 760666ea1b28a76aeba74744148b15099254d918671Owen Lin float height = drawRect.height(); 761666ea1b28a76aeba74744148b15099254d918671Owen Lin 762666ea1b28a76aeba74744148b15099254d918671Owen Lin float thisWidth = getWidth(); 763666ea1b28a76aeba74744148b15099254d918671Owen Lin float thisHeight = getHeight(); 764666ea1b28a76aeba74744148b15099254d918671Owen Lin 765666ea1b28a76aeba74744148b15099254d918671Owen Lin float z1 = thisWidth / width * .6F; 766666ea1b28a76aeba74744148b15099254d918671Owen Lin float z2 = thisHeight / height * .6F; 767666ea1b28a76aeba74744148b15099254d918671Owen Lin 768666ea1b28a76aeba74744148b15099254d918671Owen Lin float zoom = Math.min(z1, z2); 769666ea1b28a76aeba74744148b15099254d918671Owen Lin zoom = zoom * this.getScale(); 770666ea1b28a76aeba74744148b15099254d918671Owen Lin zoom = Math.max(1F, zoom); 771666ea1b28a76aeba74744148b15099254d918671Owen Lin 772666ea1b28a76aeba74744148b15099254d918671Owen Lin if ((Math.abs(zoom - getScale()) / zoom) > .1) { 773666ea1b28a76aeba74744148b15099254d918671Owen Lin float [] coordinates = new float[] {hv.mCropRect.centerX(), 774666ea1b28a76aeba74744148b15099254d918671Owen Lin hv.mCropRect.centerY()}; 775666ea1b28a76aeba74744148b15099254d918671Owen Lin getImageMatrix().mapPoints(coordinates); 776666ea1b28a76aeba74744148b15099254d918671Owen Lin zoomTo(zoom, coordinates[0], coordinates[1], 300F); 777666ea1b28a76aeba74744148b15099254d918671Owen Lin } 778666ea1b28a76aeba74744148b15099254d918671Owen Lin 779666ea1b28a76aeba74744148b15099254d918671Owen Lin ensureVisible(hv); 780666ea1b28a76aeba74744148b15099254d918671Owen Lin } 781666ea1b28a76aeba74744148b15099254d918671Owen Lin 782666ea1b28a76aeba74744148b15099254d918671Owen Lin @Override 783666ea1b28a76aeba74744148b15099254d918671Owen Lin protected void onDraw(Canvas canvas) { 784666ea1b28a76aeba74744148b15099254d918671Owen Lin super.onDraw(canvas); 785666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mHighlightViews.size(); i++) { 786666ea1b28a76aeba74744148b15099254d918671Owen Lin mHighlightViews.get(i).draw(canvas); 787666ea1b28a76aeba74744148b15099254d918671Owen Lin } 788666ea1b28a76aeba74744148b15099254d918671Owen Lin } 789666ea1b28a76aeba74744148b15099254d918671Owen Lin 790666ea1b28a76aeba74744148b15099254d918671Owen Lin public void add(HighlightView hv) { 791666ea1b28a76aeba74744148b15099254d918671Owen Lin mHighlightViews.add(hv); 792666ea1b28a76aeba74744148b15099254d918671Owen Lin invalidate(); 793666ea1b28a76aeba74744148b15099254d918671Owen Lin } 794666ea1b28a76aeba74744148b15099254d918671Owen Lin} 795