Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package com.android.camera;
 
 
 
 
 import java.io.File;
The activity can crop specific region of interest from an image.
 
 public class CropImage extends MonitoredActivity {
     private static final String TAG = "CropImage";
 
     // These are various options can be specified in the intent.
     private Bitmap.CompressFormat mOutputFormat =
             ..// only used with mSaveUri
     private Uri mSaveUri = null;
     private boolean mSetWallpaper = false;
     private int mAspectXmAspectY;
     private boolean mDoFaceDetection = true;
     private boolean mCircleCrop = false;
     private final Handler mHandler = new Handler();
 
     // These options specifiy the output image size and whether we should
     // scale the output to fit it (or just crop it).
     private int mOutputXmOutputY;
     private boolean mScale;
     private boolean mScaleUp = true;
 
     boolean mWaitingToPick// Whether we are wait the user to pick a face.
     boolean mSaving;  // Whether the "save" button is already clicked.
 
     private CropImageView mImageView;
     private ContentResolver mContentResolver;
 
     private Bitmap mBitmap;
 
     private IImageList mAllImages;
     private IImage mImage;
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
          = getContentResolver();
 
         setContentView(..);
 
          = (CropImageViewfindViewById(..);
 
        MenuHelper.showStorageToast(this);
        Intent intent = getIntent();
        Bundle extras = intent.getExtras();
        if (extras != null) {
            if (extras.getString("circleCrop") != null) {
                 = true;
                 = 1;
                 = 1;
            }
             = (Uriextras.getParcelable(.);
            if ( != null) {
                String outputFormatString = extras.getString("outputFormat");
                if (outputFormatString != null) {
                     = Bitmap.CompressFormat.valueOf(
                            outputFormatString);
                }
            } else {
                 = extras.getBoolean("setWallpaper");
            }
             = (Bitmapextras.getParcelable("data");
             = extras.getInt("aspectX");
             = extras.getInt("aspectY");
             = extras.getInt("outputX");
             = extras.getInt("outputY");
             = extras.getBoolean("scale"true);
             = extras.getBoolean("scaleUpIfNeeded"true);
             = extras.containsKey("noFaceDetection")
                    ? !extras.getBoolean("noFaceDetection")
                    : true;
        }
        if ( == null) {
            Uri target = intent.getData();
             = ImageManager.makeImageList(target,
                    .);
             = .getImageForUri(target);
            if ( != null) {
                // Don't read in really large bitmaps. Use the (big) thumbnail
                // instead.
                // TODO when saving the resulting bitmap use the
                // decode/crop/encode api so we don't lose any resolution.
                 = .thumbBitmap(.);
            }
        }
        if ( == null) {
            finish();
            return;
        }
        // Make UI fullscreen.
                new View.OnClickListener() {
                    public void onClick(View v) {
                        setResult();
                        finish();
                    }
                });
                new View.OnClickListener() {
                    public void onClick(View v) {
                        onSaveClicked();
                    }
                });
        startFaceDetection();
    }
    private void startFaceDetection() {
        if (isFinishing()) {
            return;
        }
        Util.startBackgroundJob(thisnull,
                getResources().getString(..),
                new Runnable() {
            public void run() {
                final CountDownLatch latch = new CountDownLatch(1);
                final Bitmap b = ( != null)
                        ? .fullSizeBitmap(.,
                        1024 * 1024)
                        : ;
                .post(new Runnable() {
                    public void run() {
                        if (b !=  && b != null) {
                            .setImageBitmapResetBase(btrue);
                            .recycle();
                             = b;
                        }
                        if (.getScale() == 1F) {
                            .center(truetrue);
                        }
                        latch.countDown();
                    }
                });
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                .run();
            }
        }, );
    }
    private void onSaveClicked() {
        // TODO this code needs to change to use the decode/crop/encode single
        // step api so that we don't require that the whole (possibly large)
        // bitmap doesn't have to be read into memory
        if ( == null) {
            return;
        }
        if (return;
         = true;
        Bitmap croppedImage;
        // If the output is required to a specific size, create an new image
        // with the cropped image in the center and the extra space filled.
        if ( != 0 &&  != 0 && !) {
            // Don't scale the image but instead fill it so it's the
            // required dimension
            croppedImage = Bitmap.createBitmap(,
                    ..);
            Canvas canvas = new Canvas(croppedImage);
            Rect srcRect = .getCropRect();
            Rect dstRect = new Rect(0, 0, );
            int dx = (srcRect.width() - dstRect.width()) / 2;
            int dy = (srcRect.height() - dstRect.height()) / 2;
            // If the srcRect is too big, use the center part of it.
            srcRect.inset(Math.max(0, dx), Math.max(0, dy));
            // If the dstRect is too big, use the center part of it.
            dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));
            // Draw the cropped bitmap in the center
            canvas.drawBitmap(srcRectdstRectnull);
            // Release bitmap memory as soon as possible
            .clear();
            .recycle();
        } else {
            Rect r = .getCropRect();
            int width = r.width();
            int height = r.height();
            // If we are circle cropping, we want alpha channel, which is the
            // third param here.
            croppedImage = Bitmap.createBitmap(widthheight,
                    
                    ? ..
                    : ..);
            Canvas canvas = new Canvas(croppedImage);
            Rect dstRect = new Rect(0, 0, widthheight);
            canvas.drawBitmap(rdstRectnull);
            // Release bitmap memory as soon as possible
            .clear();
            .recycle();
            if () {
                // OK, so what's all this about?
                // Bitmaps are inherently rectangular but we want to return
                // something that's basically a circle.  So we fill in the
                // area around the circle with alpha.  Note the all important
                // PortDuff.Mode.CLEAR.
                Canvas c = new Canvas(croppedImage);
                Path p = new Path();
                p.addCircle(width / 2F, height / 2F, width / 2F,
                        ..);
                c.clipPath(p..);
                c.drawColor(0x00000000, ..);
            }
            // If the required dimension is specified, scale the image.
            if ( != 0 &&  != 0 && ) {
                croppedImage = Util.transform(new Matrix(), croppedImage,
                        .);
            }
        }
        .setImageBitmapResetBase(croppedImagetrue);
        .center(truetrue);
        // Return the cropped image directly or save it to the specified URI.
        Bundle myExtras = getIntent().getExtras();
        if (myExtras != null && (myExtras.getParcelable("data") != null
                || myExtras.getBoolean("return-data"))) {
            Bundle extras = new Bundle();
            extras.putParcelable("data"croppedImage);
            setResult(,
                    (new Intent()).setAction("inline-data").putExtras(extras));
            finish();
        } else {
            final Bitmap b = croppedImage;
            final int msdId = 
                    ? ..
                    : ..;
            Util.startBackgroundJob(thisnull,
                    getResources().getString(msdId),
                    new Runnable() {
                public void run() {
                    saveOutput(b);
                }
            }, );
        }
    }
    private void saveOutput(Bitmap croppedImage) {
        if ( != null) {
            OutputStream outputStream = null;
            try {
                outputStream = .openOutputStream();
                if (outputStream != null) {
                    croppedImage.compress(, 75, outputStream);
                }
            } catch (IOException ex) {
                // TODO: report error to caller
                Log.e("Cannot open file: " + ex);
            } finally {
                Util.closeSilently(outputStream);
            }
            Bundle extras = new Bundle();
            setResult(new Intent(.toString())
                    .putExtras(extras));
        } else if () {
            try {
                WallpaperManager.getInstance(this).setBitmap(croppedImage);
                setResult();
            } catch (IOException e) {
                Log.e("Failed to set wallpaper."e);
                setResult();
            }
        } else {
            Bundle extras = new Bundle();
            extras.putString("rect".getCropRect().toString());
            File oldPath = new File(.getDataPath());
            File directory = new File(oldPath.getParent());
            int x = 0;
            String fileName = oldPath.getName();
            fileName = fileName.substring(0, fileName.lastIndexOf("."));
            // Try file-1.jpg, file-2.jpg, ... until we find a filename which
            // does not exist yet.
            while (true) {
                x += 1;
                String candidate = directory.toString()
                        + "/" + fileName + "-" + x + ".jpg";
                boolean exists = (new File(candidate)).exists();
                if (!exists) {
                    break;
                }
            }
            try {
                int[] degree = new int[1];
                Uri newUri = ImageManager.addImage(
                        ,
                        .getTitle(),
                        .getDateTaken(),
                        null,    // TODO this null is going to cause us to lose
                                 // the location (gps).
                        directory.toString(), fileName + "-" + x + ".jpg",
                        croppedImagenull,
                        degree);
                setResult(new Intent()
                        .setAction(newUri.toString())
                        .putExtras(extras));
            } catch (Exception ex) {
                // basically ignore this or put up
                // some ui saying we failed
                Log.e("store image fail, continue anyway"ex);
            }
        }
        final Bitmap b = croppedImage;
        .post(new Runnable() {
            public void run() {
                .clear();
                b.recycle();
            }
        });
        finish();
    }
    @Override
    protected void onPause() {
        super.onPause();
    }
    @Override
    protected void onDestroy() {
        if ( != null) {
            .close();
        }
        super.onDestroy();
    }
    Runnable mRunFaceDetection = new Runnable() {
        @SuppressWarnings("hiding")
        float mScale = 1F;
        Matrix mImageMatrix;
        FaceDetector.Face[] mFaces = new FaceDetector.Face[3];
        int mNumFaces;
        // For each face, we create a HightlightView for it.
        private void handleFace(FaceDetector.Face f) {
            PointF midPoint = new PointF();
            int r = ((int) (f.eyesDistance() * )) * 2;
            f.getMidPoint(midPoint);
            midPoint.x *= ;
            midPoint.y *= ;
            int midX = (intmidPoint.x;
            int midY = (intmidPoint.y;
            HighlightView hv = new HighlightView();
            int width = .getWidth();
            int height = .getHeight();
            Rect imageRect = new Rect(0, 0, widthheight);
            RectF faceRect = new RectF(midXmidYmidXmidY);
            faceRect.inset(-r, -r);
            if (faceRect.left < 0) {
                faceRect.inset(-faceRect.left, -faceRect.left);
            }
            if (faceRect.top < 0) {
                faceRect.inset(-faceRect.top, -faceRect.top);
            }
            if (faceRect.right > imageRect.right) {
                faceRect.inset(faceRect.right - imageRect.right,
                               faceRect.right - imageRect.right);
            }
            if (faceRect.bottom > imageRect.bottom) {
                faceRect.inset(faceRect.bottom - imageRect.bottom,
                               faceRect.bottom - imageRect.bottom);
            }
            hv.setup(imageRectfaceRect,
                      != 0 &&  != 0);
            .add(hv);
        }
        // Create a default HightlightView if we found no face in the picture.
        private void makeDefault() {
            HighlightView hv = new HighlightView();
            int width = .getWidth();
            int height = .getHeight();
            Rect imageRect = new Rect(0, 0, widthheight);
            // make the default size about 4/5 of the width or height
            int cropWidth = Math.min(widthheight) * 4 / 5;
            int cropHeight = cropWidth;
            if ( != 0 &&  != 0) {
                if ( > ) {
                    cropHeight = cropWidth *  / ;
                } else {
                    cropWidth = cropHeight *  / ;
                }
            }
            int x = (width - cropWidth) / 2;
            int y = (height - cropHeight) / 2;
            RectF cropRect = new RectF(xyx + cropWidthy + cropHeight);
            hv.setup(imageRectcropRect,
                      != 0 &&  != 0);
            .add(hv);
        }
        // Scale the image down for faster face detection.
        private Bitmap prepareBitmap() {
            if ( == null) {
                return null;
            }
            // 256 pixels wide is enough.
            if (.getWidth() > 256) {
                 = 256.0F / .getWidth();
            }
            Matrix matrix = new Matrix();
            matrix.setScale();
            Bitmap faceBitmap = Bitmap.createBitmap(, 0, 0, 
                    .getWidth(), .getHeight(), matrixtrue);
            return faceBitmap;
        }
        public void run() {
             = .getImageMatrix();
            Bitmap faceBitmap = prepareBitmap();
             = 1.0F / ;
            if (faceBitmap != null && ) {
                FaceDetector detector = new FaceDetector(faceBitmap.getWidth(),
                        faceBitmap.getHeight(), .);
                 = detector.findFaces(faceBitmap);
            }
            if (faceBitmap != null && faceBitmap != ) {
                faceBitmap.recycle();
            }
            .post(new Runnable() {
                public void run() {
                     =  > 1;
                    if ( > 0) {
                        for (int i = 0; i < i++) {
                            handleFace([i]);
                        }
                    } else {
                        makeDefault();
                    }
                    .invalidate();
                    if (..size() == 1) {
                         = ..get(0);
                        .setFocus(true);
                    }
                    if ( > 1) {
                        Toast t = Toast.makeText(CropImage.this,
                                ..,
                                .);
                        t.show();
                    }
                }
            });
        }
    };
    float mLastXmLastY;
    int mMotionEdge;
    @Override
    protected void onLayout(boolean changedint leftint top,
                            int rightint bottom) {
        super.onLayout(changedlefttoprightbottom);
        if (.getBitmap() != null) {
            for (HighlightView hv : ) {
                hv.mMatrix.set(getImageMatrix());
                hv.invalidate();
                if (hv.mIsFocused) {
                    centerBasedOnHighlightView(hv);
                }
            }
        }
    }
    public CropImageView(Context contextAttributeSet attrs) {
        super(contextattrs);
    }
    @Override
    protected void zoomTo(float scalefloat centerXfloat centerY) {
        super.zoomTo(scalecenterXcenterY);
        for (HighlightView hv : ) {
            hv.mMatrix.set(getImageMatrix());
            hv.invalidate();
        }
    }
    @Override
    protected void zoomIn() {
        super.zoomIn();
        for (HighlightView hv : ) {
            hv.mMatrix.set(getImageMatrix());
            hv.invalidate();
        }
    }
    @Override
    protected void zoomOut() {
        super.zoomOut();
        for (HighlightView hv : ) {
            hv.mMatrix.set(getImageMatrix());
            hv.invalidate();
        }
    }
    @Override
    protected void postTranslate(float deltaXfloat deltaY) {
        super.postTranslate(deltaXdeltaY);
        for (int i = 0; i < .size(); i++) {
            HighlightView hv = .get(i);
            hv.mMatrix.postTranslate(deltaXdeltaY);
            hv.invalidate();
        }
    }
    // According to the event's position, change the focus to the first
    // hitting cropping rectangle.
    private void recomputeFocus(MotionEvent event) {
        for (int i = 0; i < .size(); i++) {
            HighlightView hv = .get(i);
            hv.setFocus(false);
            hv.invalidate();
        }
        for (int i = 0; i < .size(); i++) {
            HighlightView hv = .get(i);
            int edge = hv.getHit(event.getX(), event.getY());
            if (edge != .) {
                if (!hv.hasFocus()) {
                    hv.setFocus(true);
                    hv.invalidate();
                }
                break;
            }
        }
        invalidate();
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        CropImage cropImage = (CropImage;
        if (cropImage.mSaving) {
            return false;
        }
        switch (event.getAction()) {
            case .:
                if (cropImage.mWaitingToPick) {
                    recomputeFocus(event);
                } else {
                    for (int i = 0; i < .size(); i++) {
                        HighlightView hv = .get(i);
                        int edge = hv.getHit(event.getX(), event.getY());
                        if (edge != .) {
                             = edge;
                             = hv;
                             = event.getX();
                             = event.getY();
                            .setMode(
                                    (edge == .)
                                    ? ..
                                    : ..);
                            break;
                        }
                    }
                }
                break;
            case .:
                if (cropImage.mWaitingToPick) {
                    for (int i = 0; i < .size(); i++) {
                        HighlightView hv = .get(i);
                        if (hv.hasFocus()) {
                            cropImage.mCrop = hv;
                            for (int j = 0; j < .size(); j++) {
                                if (j == i) {
                                    continue;
                                }
                                .get(j).setHidden(true);
                            }
                            centerBasedOnHighlightView(hv);
                            ((CropImage). = false;
                            return true;
                        }
                    }
                } else if ( != null) {
                    centerBasedOnHighlightView();
                    .setMode(
                            ..);
                }
                 = null;
                break;
            case .:
                if (cropImage.mWaitingToPick) {
                    recomputeFocus(event);
                } else if ( != null) {
                    .handleMotion(,
                            event.getX() - ,
                            event.getY() - );
                     = event.getX();
                     = event.getY();
                    if (true) {
                        // This section of code is optional. It has some user
                        // benefit in that moving the crop rectangle against
                        // the edge of the screen causes scrolling but it means
                        // that the crop rectangle is no longer fixed under
                        // the user's finger.
                        ensureVisible();
                    }
                }
                break;
        }
        switch (event.getAction()) {
            case .:
                center(truetrue);
                break;
            case .:
                // if we're not zoomed then there's no point in even allowing
                // the user to move the image around.  This call to center puts
                // it back to the normalized location (with false meaning don't
                // animate).
                if (getScale() == 1F) {
                    center(truetrue);
                }
                break;
        }
        return true;
    }
    // Pan the displayed image to make sure the cropping rectangle is visible.
    private void ensureVisible(HighlightView hv) {
        Rect r = hv.mDrawRect;
        int panDeltaX1 = Math.max(0,  - r.left);
        int panDeltaX2 = Math.min(0,  - r.right);
        int panDeltaY1 = Math.max(0,  - r.top);
        int panDeltaY2 = Math.min(0,  - r.bottom);
        int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2;
        int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2;
        if (panDeltaX != 0 || panDeltaY != 0) {
            panBy(panDeltaXpanDeltaY);
        }
    }
    // If the cropping rectangle's size changed significantly, change the
    // view's center and scale according to the cropping rectangle.
    private void centerBasedOnHighlightView(HighlightView hv) {
        Rect drawRect = hv.mDrawRect;
        float width = drawRect.width();
        float height = drawRect.height();
        float thisWidth = getWidth();
        float thisHeight = getHeight();
        float z1 = thisWidth / width * .6F;
        float z2 = thisHeight / height * .6F;
        float zoom = Math.min(z1z2);
        zoom = zoom * this.getScale();
        zoom = Math.max(1F, zoom);
        if ((Math.abs(zoom - getScale()) / zoom) > .1) {
            float [] coordinates = new float[] {hv.mCropRect.centerX(),
                                                hv.mCropRect.centerY()};
            getImageMatrix().mapPoints(coordinates);
            zoomTo(zoomcoordinates[0], coordinates[1], 300F);
        }
        ensureVisible(hv);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < .size(); i++) {
            .get(i).draw(canvas);
        }
    }
    public void add(HighlightView hv) {
        .add(hv);
        invalidate();
    }