2014-03-27 3 views

Antwort

15

Ich hatte die gleiche Anforderung. Ich löste es, PhotoView und Cropper kombinierend, indem ich die ImageView durch in cropper lib ersetzte.

Ich hatte die CropWindow Klasse zu ändern, um Berührungsereignisse zu vermeiden, nicht richtig gehandhabt wird:

public void setImageView(PhotoView pv){ 
     mPhotoView = pv; 
    } 
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 

     // If this View is not enabled, don't allow for touch interactions. 
     if (!isEnabled()) { 
      return false; 
     } 

     switch (event.getAction()) { 

      case MotionEvent.ACTION_DOWN: 
        boolean dispatch = onActionDown(event.getX(), event.getY()); 
        if(!dispatch) 
        mPhotoView.dispatchTouchEvent(event); 

       return dispatch; 

      case MotionEvent.ACTION_UP: 
      case MotionEvent.ACTION_CANCEL: 
       getParent().requestDisallowInterceptTouchEvent(false); 
       onActionUp(); 
       return true; 

      case MotionEvent.ACTION_MOVE: 
       onActionMove(event.getX(), event.getY()); 
       getParent().requestDisallowInterceptTouchEvent(true); 
       return true; 

      default: 
       return false; 
     } 
    } 

In CropImageView Klasse auch einige Dinge geändert:

private void init(Context context) { 

    final LayoutInflater inflater = LayoutInflater.from(context); 
    final View v = inflater.inflate(R.layout.crop_image_view, this, true); 

    mImageView = (PhotoView) v.findViewById(R.id.ImageView_image2); 

    setImageResource(mImageResource); 
    mCropOverlayView = (CropOverlayView) v.findViewById(R.id.CropOverlayView); 
    mCropOverlayView.setInitialAttributeValues(mGuidelines, mFixAspectRatio, mAspectRatioX, mAspectRatioY); 
    mCropOverlayView.setImageView(mImageView); 
} 

Sie, dass ich feststellen kann haben ImageView mit PhotoView innerhalb R.layout.crop_image_view in Cropper-Bibliothek ersetzt.

Cropper-Bibliothek unterstützt feste Größe und PhotoView ermöglicht es Ihnen, das Foto zu verschieben und skalieren, so dass Sie das Beste aus beiden Welten erhalten. :)

Hoffe es hilft.

bearbeiten, für diejenigen, die gefragt, wie das Bild zu erhalten, die nur innerhalb der Anbaufläche ist:

private Bitmap getCurrentDisplayedImage(){ 
     Bitmap result = Bitmap.createBitmap(mImageView.getWidth(), mImageView.getHeight(), Bitmap.Config.RGB_565); 
     Canvas c = new Canvas(result); 
     mImageView.draw(c); 
     return result; 
    } 
    public Bitmap getCroppedImage() { 

     Bitmap mCurrentDisplayedBitmap = getCurrentDisplayedImage(); 
     final Rect displayedImageRect = ImageViewUtil2.getBitmapRectCenterInside(mCurrentDisplayedBitmap, mImageView); 

     // Get the scale factor between the actual Bitmap dimensions and the 
     // displayed dimensions for width. 
     final float actualImageWidth =mCurrentDisplayedBitmap.getWidth(); 
     final float displayedImageWidth = displayedImageRect.width(); 
     final float scaleFactorWidth = actualImageWidth/displayedImageWidth; 

     // Get the scale factor between the actual Bitmap dimensions and the 
     // displayed dimensions for height. 
     final float actualImageHeight = mCurrentDisplayedBitmap.getHeight(); 
     final float displayedImageHeight = displayedImageRect.height(); 
     final float scaleFactorHeight = actualImageHeight/displayedImageHeight; 

     // Get crop window position relative to the displayed image. 
     final float cropWindowX = Edge.LEFT.getCoordinate() - displayedImageRect.left; 
     final float cropWindowY = Edge.TOP.getCoordinate() - displayedImageRect.top; 
     final float cropWindowWidth = Edge.getWidth(); 
     final float cropWindowHeight = Edge.getHeight(); 

     // Scale the crop window position to the actual size of the Bitmap. 
     final float actualCropX = cropWindowX * scaleFactorWidth; 
     final float actualCropY = cropWindowY * scaleFactorHeight; 
     final float actualCropWidth = cropWindowWidth * scaleFactorWidth; 
     final float actualCropHeight = cropWindowHeight * scaleFactorHeight; 

     // Crop the subset from the original Bitmap. 
     final Bitmap croppedBitmap = Bitmap.createBitmap(mCurrentDisplayedBitmap, 
                 (int) actualCropX, 
                 (int) actualCropY, 
                 (int) actualCropWidth, 
                 (int) actualCropHeight); 

     return croppedBitmap; 
    } 

    public RectF getActualCropRect() { 

     final Rect displayedImageRect = ImageViewUtil.getBitmapRectCenterInside(mBitmap, mImageView); 

     final float actualImageWidth = mBitmap.getWidth(); 
     final float displayedImageWidth = displayedImageRect.width(); 
     final float scaleFactorWidth = actualImageWidth/displayedImageWidth; 

     // Get the scale factor between the actual Bitmap dimensions and the displayed 
     // dimensions for height. 
     final float actualImageHeight = mBitmap.getHeight(); 
     final float displayedImageHeight = displayedImageRect.height(); 
     final float scaleFactorHeight = actualImageHeight/displayedImageHeight; 

     // Get crop window position relative to the displayed image. 
     final float displayedCropLeft = Edge.LEFT.getCoordinate() - displayedImageRect.left; 
     final float displayedCropTop = Edge.TOP.getCoordinate() - displayedImageRect.top; 
     final float displayedCropWidth = Edge.getWidth(); 
     final float displayedCropHeight = Edge.getHeight(); 

     // Scale the crop window position to the actual size of the Bitmap. 
     float actualCropLeft = displayedCropLeft * scaleFactorWidth; 
     float actualCropTop = displayedCropTop * scaleFactorHeight; 
     float actualCropRight = actualCropLeft + displayedCropWidth * scaleFactorWidth; 
     float actualCropBottom = actualCropTop + displayedCropHeight * scaleFactorHeight; 

     // Correct for floating point errors. Crop rect boundaries should not exceed the 
     // source Bitmap bounds. 
     actualCropLeft = Math.max(0f, actualCropLeft); 
     actualCropTop = Math.max(0f, actualCropTop); 
     actualCropRight = Math.min(mBitmap.getWidth(), actualCropRight); 
     actualCropBottom = Math.min(mBitmap.getHeight(), actualCropBottom); 

     final RectF actualCropRect = new RectF(actualCropLeft, 
               actualCropTop, 
               actualCropRight, 
               actualCropBottom); 

     return actualCropRect; 
    } 




private boolean onActionDown(float x, float y) {  
     final float left = Edge.LEFT.getCoordinate(); 
     final float top = Edge.TOP.getCoordinate(); 
     final float right = Edge.RIGHT.getCoordinate(); 
     final float bottom = Edge.BOTTOM.getCoordinate();  
     mPressedHandle = HandleUtil.getPressedHandle(x, y, left, top, right, bottom, mHandleRadius);  
     if (mPressedHandle == null) 
      return false; 
     mTouchOffset = HandleUtil2.getOffset(mPressedHandle, x, y, left, top, right, bottom); 

     invalidate(); 
     return true; 
    } 
+0

Hallo Nikola, gute Antwort. Ich möchte fragen, wie genau Sie das gezoomte Bild zugeschnitten haben. Da ich die Proportionen nicht genau richtig bekommen konnte. Eine der Methoden, die ich ausprobiert habe, war, die Bildskalierung mithilfe der Getscale-Funktion in der PhotoViewAttacher-Klasse zu verfolgen und diese Skalierung in "croppImageImage" in cropImageView anzuwenden. Kannst du mir sagen, wie du das gemacht hast? – kesari

+1

@kesesi Sorry für meine späte Antwort. Bitte überprüfen Sie mit meiner letzten Bearbeitung, ich habe einige Methoden zum Zuschneiden hinzugefügt. –

+0

@NikolaDespotoski Hallo, Ich habe auch die gleiche Anforderung, und ich habe versucht, Ihren Code, aber es funktioniert nicht. weiß nicht, was das genaue Problem ist. kannst du deinen Code davon teilen? – Riser

2

Ich habe einige Ergänzungen @Nikola Despotoski Antwort. Zunächst müssen Sie ImageView in R.layout.crop_image_view nicht in PhotoView ändern, da die PhotoView-Logik einfach im Code als neuer PhotoViewAttacher (mImageView) angehängt werden kann.

Auch in der Standardlogik berechnet die Overlay-Größe eines CropView nur bei seiner Initialisierung gemäß imageView-Bitmap-Größe. Es ist also keine angemessene Logik für uns, da wir Bitmap-Größe durch Berührungen entsprechend der Anforderung ändern. Daher sollten wir die gespeicherten Bitmap-Größen in CropOverlayView ändern und jedes Mal ungültig machen, wenn wir das Hauptbild ändern.

Und das letzte ist, dass ein Bereich, in dem der Benutzer normalerweise basierend auf der Bildgröße beschneiden kann, aber wenn wir das Bild größer gemacht haben, kann es über den Bildschirmrand hinausgehen, so dass es möglich ist, einen Benutzer zu bewegen Zuschneiden der Ansicht außerhalb des Rahmens, was nicht korrekt ist. Also sollten wir auch mit dieser Situation umgehen und Einschränkungen schaffen.

und der entsprechende Teil des Codes für diese drei Fragen: In CropImageView:

private void init(Context context) { 

    final LayoutInflater inflater = LayoutInflater.from(context); 
    final View v = inflater.inflate(R.layout.crop_image_view, this, true); 

    mImageView = (ImageView) v.findViewById(R.id.ImageView_image); 

    setImageResource(mImageResource); 
    mCropOverlayView = (CropOverlayView) v.findViewById(R.id.CropOverlayView); 
    mCropOverlayView.setInitialAttributeValues(mGuidelines, mFixAspectRatio, mAspectRatioX, mAspectRatioY); 
    mCropOverlayView.setOutlineTouchEventReceiver(mImageView); 

    final PhotoViewAttacher photoAttacher = new PhotoViewAttacher(mImageView); 
    photoAttacher.setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() { 
     @Override 
     public void onMatrixChanged(RectF imageRect) { 
     final Rect visibleRect = ImageViewUtil.getBitmapRectCenterInside(photoAttacher.getVisibleRectangleBitmap(), photoAttacher.getImageView()); 

     imageRect.top = Math.max(imageRect.top, visibleRect.top); 
     imageRect.left = Math.max(imageRect.left, visibleRect.left); 
     imageRect.right = Math.min(imageRect.right, visibleRect.right); 
     imageRect.bottom = Math.min(imageRect.bottom, visibleRect.bottom); 

     Rect bitmapRect = new Rect(); 
     imageRect.round(bitmapRect); 

     mCropOverlayView.changeBitmapRectInvalidate(bitmapRect); 
     } 
    }); 
} 

In CropOverlayView:

@Override 
public boolean onTouchEvent(MotionEvent event) { 

    // If this View is not enabled, don't allow for touch interactions. 
    if (!isEnabled()) { 
     return false; 
    } 

    switch (event.getAction()) { 

     case MotionEvent.ACTION_DOWN: 
      return onActionDown(event.getX(), event.getY()); 

     case MotionEvent.ACTION_UP: 
     case MotionEvent.ACTION_CANCEL: 
      getParent().requestDisallowInterceptTouchEvent(false); 
      return onActionUp(); 

     case MotionEvent.ACTION_MOVE: 
      boolean result = onActionMove(event.getX(), event.getY()); 
      getParent().requestDisallowInterceptTouchEvent(true); 
      return result; 

     default: 
      return false; 
    } 
} 

public void changeBitmapRectInvalidate(Rect bitmapRect) { 
    mBitmapRect = bitmapRect; 
    invalidate(); 
} 

private boolean onActionDown(float x, float y) { 

    final float left = Edge.LEFT.getCoordinate(); 
    final float top = Edge.TOP.getCoordinate(); 
    final float right = Edge.RIGHT.getCoordinate(); 
    final float bottom = Edge.BOTTOM.getCoordinate(); 

    mPressedHandle = HandleUtil.getPressedHandle(x, y, left, top, right, bottom, mHandleRadius); 

    if (mPressedHandle == null){ 
     return false; 
    } 

    // Calculate the offset of the touch point from the precise location 
    // of the handle. Save these values in a member variable since we want 
    // to maintain this offset as we drag the handle. 
    mTouchOffset = HandleUtil.getOffset(mPressedHandle, x, y, left, top, right, bottom); 

    invalidate(); 
    return true; 
} 

/** 
* Handles a {@link MotionEvent#ACTION_UP} or 
* {@link MotionEvent#ACTION_CANCEL} event. 
* @return true if event vas handled, else - false 
*/ 
private boolean onActionUp() { 

    if (mPressedHandle == null) 
     return false; 

    mPressedHandle = null; 

    invalidate(); 
    return true; 
} 

/** 
* Handles a {@link MotionEvent#ACTION_MOVE} event. 
* 
* @param x the x-coordinate of the move event 
* @param y the y-coordinate of the move event 
*/ 
private boolean onActionMove(float x, float y) { 

    if (mPressedHandle == null) 
     return false; 

    // Adjust the coordinates for the finger position's offset (i.e. the 
    // distance from the initial touch to the precise handle location). 
    // We want to maintain the initial touch's distance to the pressed 
    // handle so that the crop window size does not "jump". 
    x += mTouchOffset.first; 
    y += mTouchOffset.second; 

    // Calculate the new crop window size/position. 
    if (mFixAspectRatio) { 
     mPressedHandle.updateCropWindow(x, y, mTargetAspectRatio, mBitmapRect, mSnapRadius); 
    } else { 
     mPressedHandle.updateCropWindow(x, y, mBitmapRect, mSnapRadius); 
    } 
    invalidate(); 
    return true; 
} 

Für richtig zugeschnittene Bild bekommen, sollten Sie den zweiten Teil des @Nikola verwenden Despotoski Antwort

+0

Was muss in SetOutlineTouchEventReceiver (ImageView imageView) in CropOverlayView geschrieben werden? –

+0

@Ramesh Akula nichts, außer Standard-Bibliothekscode. public void setOutlineTouchEventReceiver (Ansicht outlineTouchEventReceiver) { this.outlineTouchEventReceiver = outlineTouchEventReceiver; } – Beloo

+0

Danke, endlich habe ich es funktioniert. https://github.com/rameshkec85/AndroidCropMoveScaleImage –

0

Danke an alle.Mit den obigen Antworten können Sie dies mithilfe der Photoview- und Cropper-Bibliothek erreichen. Optionen zum Auswählen von Bildern aus Kamera oder Galerie hinzugefügt. Teilen Sie das Projekt auf Github. Im Projekt wurde eine APK-Datei hinzugefügt. Verwenden Sie ein echtes Gerät zum Testen der Kamera, da der Emulator die Kamera nicht gut beherrscht. Hier ist der Link zu meinem Projekt.

https://github.com/ozeetee/AndroidImageZoomCrop

Verwandte Themen