@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Draw translucent background for the cropped area. switch (cropType) { case RECT: drawBackground(canvas, mBitmapRect); break; case OVAL: drawOvalBackground(canvas, mBitmapRect); break; default: break; } if (showGuidelines()) { // Determines whether guidelines should be drawn or not if (mGuidelines == GUIDELINES_ON) { drawRuleOfThirdsGuidelines(canvas); } else if (mGuidelines == GUIDELINES_ON_TOUCH) { // Draw only when resizing if (mPressedHandle != null) drawRuleOfThirdsGuidelines(canvas); } else if (mGuidelines == GUIDELINES_OFF) { // Do nothing } } switch (cropType) { case RECT: // Draws the main crop window border. canvas.drawRect( Edge.LEFT.getCoordinate(), Edge.TOP.getCoordinate(), Edge.RIGHT.getCoordinate(), Edge.BOTTOM.getCoordinate(), mBorderPaint); break; case OVAL: oval.set( Edge.LEFT.getCoordinate(), Edge.TOP.getCoordinate(), Edge.RIGHT.getCoordinate(), Edge.BOTTOM.getCoordinate()); canvas.drawOval(oval, mBorderPaint); break; default: break; } drawCorners(canvas); }
private void drawBackground(Canvas canvas, Rect bitmapRect) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); /*- ------------------------------------- | top | ------------------------------------- | | | | | | | | | left | | right | | | | | | | | | ------------------------------------- | bottom | ------------------------------------- */ // Draw "top", "bottom", "left", then "right" quadrants. canvas.drawRect(bitmapRect.left, bitmapRect.top, bitmapRect.right, top, mBackgroundPaint); canvas.drawRect(bitmapRect.left, bottom, bitmapRect.right, bitmapRect.bottom, mBackgroundPaint); canvas.drawRect(bitmapRect.left, top, left, bottom, mBackgroundPaint); canvas.drawRect(right, top, bitmapRect.right, bottom, mBackgroundPaint); }
/** * Indicates whether the crop window is small enough that the guidelines should be shown. Public * because this function is also used to determine if the center handle should be focused. * * @return boolean Whether the guidelines should be shown or not */ public static boolean showGuidelines() { if ((Math.abs(Edge.LEFT.getCoordinate() - Edge.RIGHT.getCoordinate()) < DEFAULT_SHOW_GUIDELINES_LIMIT) || (Math.abs(Edge.TOP.getCoordinate() - Edge.BOTTOM.getCoordinate()) < DEFAULT_SHOW_GUIDELINES_LIMIT)) return false; else return true; }
private void drawOvalBackground(Canvas canvas, Rect bitmapRect) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); RectF r = new RectF(left, top, right, bottom); Path path = new Path(); path.addRect( bitmapRect.left, bitmapRect.top, bitmapRect.right, bitmapRect.bottom, Path.Direction.CW); path.addOval(r, Path.Direction.CCW); path.setFillType(Path.FillType.EVEN_ODD); canvas.drawPath(path, mBackgroundPaint); }
@Override void updateCropWindow(float x, float y, @NonNull RectF imageRect, float snapRadius) { float left = Edge.LEFT.getCoordinate(); float top = Edge.TOP.getCoordinate(); float right = Edge.RIGHT.getCoordinate(); float bottom = Edge.BOTTOM.getCoordinate(); final float currentCenterX = (left + right) / 2; final float currentCenterY = (top + bottom) / 2; final float offsetX = x - currentCenterX; final float offsetY = y - currentCenterY; // Adjust the crop window. Edge.LEFT.offset(offsetX); Edge.TOP.offset(offsetY); Edge.RIGHT.offset(offsetX); Edge.BOTTOM.offset(offsetY); // Check if we have gone out of bounds on the sides, and fix. if (Edge.LEFT.isOutsideMargin(imageRect, snapRadius)) { final float offset = Edge.LEFT.snapToRect(imageRect); Edge.RIGHT.offset(offset); } else if (Edge.RIGHT.isOutsideMargin(imageRect, snapRadius)) { final float offset = Edge.RIGHT.snapToRect(imageRect); Edge.LEFT.offset(offset); } // Check if we have gone out of bounds on the top or bottom, and fix. if (Edge.TOP.isOutsideMargin(imageRect, snapRadius)) { final float offset = Edge.TOP.snapToRect(imageRect); Edge.BOTTOM.offset(offset); } else if (Edge.BOTTOM.isOutsideMargin(imageRect, snapRadius)) { final float offset = Edge.BOTTOM.snapToRect(imageRect); Edge.TOP.offset(offset); } }
private void drawCorners(Canvas canvas) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); // Draws the corner lines // Top left canvas.drawLine( left - mCornerOffset, top - mCornerExtension, left - mCornerOffset, top + mCornerLength, mCornerPaint); canvas.drawLine( left, top - mCornerOffset, left + mCornerLength, top - mCornerOffset, mCornerPaint); // Top right canvas.drawLine( right + mCornerOffset, top - mCornerExtension, right + mCornerOffset, top + mCornerLength, mCornerPaint); canvas.drawLine( right, top - mCornerOffset, right - mCornerLength, top - mCornerOffset, mCornerPaint); // Bottom left canvas.drawLine( left - mCornerOffset, bottom + mCornerExtension, left - mCornerOffset, bottom - mCornerLength, mCornerPaint); canvas.drawLine( left, bottom + mCornerOffset, left + mCornerLength, bottom + mCornerOffset, mCornerPaint); // Bottom left canvas.drawLine( right + mCornerOffset, bottom + mCornerExtension, right + mCornerOffset, bottom - mCornerLength, mCornerPaint); canvas.drawLine( right, bottom + mCornerOffset, right - mCornerLength, bottom + mCornerOffset, mCornerPaint); }
/** * Handles a {@link MotionEvent#ACTION_DOWN} event. * * @param x the x-coordinate of the down action * @param y the y-coordinate of the down action */ private void 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; // 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(); }
/** * Gets the cropped image based on the current crop window. * * @return a new Bitmap representing the cropped image */ public Bitmap getCroppedImage() { final Rect displayedImageRect = ImageViewUtil.getBitmapRectCenterInside(mBitmap, mImageView); // Get the scale factor between the actual Bitmap dimensions and the // displayed dimensions for width. 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 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; // Cropget the subset from the original Bitmap. final Bitmap croppedBitmap = Bitmap.createBitmap( mBitmap, (int) actualCropX, (int) actualCropY, (int) actualCropWidth, (int) actualCropHeight); return croppedBitmap; }
private void drawRuleOfThirdsGuidelines(Canvas canvas) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); // Draw vertical guidelines. final float oneThirdCropWidth = Edge.getWidth() / 3; final float x1 = left + oneThirdCropWidth; canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint); final float x2 = right - oneThirdCropWidth; canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint); // Draw horizontal guidelines. final float oneThirdCropHeight = Edge.getHeight() / 3; final float y1 = top + oneThirdCropHeight; canvas.drawLine(left, y1, right, y1, mGuidelinePaint); final float y2 = bottom - oneThirdCropHeight; canvas.drawLine(left, y2, right, y2, mGuidelinePaint); }
/** * Set the initial crop window size and position. This is dependent on the size and position of * the image being cropped. * * @param bitmapRect the bounding box around the image being cropped */ private void initCropWindow(Rect bitmapRect) { // Tells the attribute functions the crop window has already been // initialized if (initializedCropWindow == false) initializedCropWindow = true; if (mFixAspectRatio) { // If the image aspect ratio is wider than the crop aspect ratio, // then the image height is the determining initial length. Else, // vice-versa. if (AspectRatioUtil.calculateAspectRatio(bitmapRect) > mTargetAspectRatio) { Edge.TOP.setCoordinate(bitmapRect.top); Edge.BOTTOM.setCoordinate(bitmapRect.bottom); final float centerX = getWidth() / 2f; // Limits the aspect ratio to no less than 40 wide or 40 tall final float cropWidth = Math.max( Edge.MIN_CROP_LENGTH_PX, AspectRatioUtil.calculateWidth( Edge.TOP.getCoordinate(), Edge.BOTTOM.getCoordinate(), mTargetAspectRatio)); // Create new TargetAspectRatio if the original one does not fit // the screen if (cropWidth == Edge.MIN_CROP_LENGTH_PX) mTargetAspectRatio = (Edge.MIN_CROP_LENGTH_PX) / (Edge.BOTTOM.getCoordinate() - Edge.TOP.getCoordinate()); final float halfCropWidth = cropWidth / 2f; Edge.LEFT.setCoordinate(centerX - halfCropWidth); Edge.RIGHT.setCoordinate(centerX + halfCropWidth); } else { Edge.LEFT.setCoordinate(bitmapRect.left); Edge.RIGHT.setCoordinate(bitmapRect.right); final float centerY = getHeight() / 2f; // Limits the aspect ratio to no less than 40 wide or 40 tall final float cropHeight = Math.max( Edge.MIN_CROP_LENGTH_PX, AspectRatioUtil.calculateHeight( Edge.LEFT.getCoordinate(), Edge.RIGHT.getCoordinate(), mTargetAspectRatio)); // Create new TargetAspectRatio if the original one does not fit // the screen if (cropHeight == Edge.MIN_CROP_LENGTH_PX) mTargetAspectRatio = (Edge.RIGHT.getCoordinate() - Edge.LEFT.getCoordinate()) / Edge.MIN_CROP_LENGTH_PX; final float halfCropHeight = cropHeight / 2f; Edge.TOP.setCoordinate(centerY - halfCropHeight); Edge.BOTTOM.setCoordinate(centerY + halfCropHeight); } } else { // ... do not fix aspect ratio... // Initialize crop window to have 10% padding w/ respect to image. final float horizontalPadding = 0.1f * bitmapRect.width(); final float verticalPadding = 0.1f * bitmapRect.height(); Edge.LEFT.setCoordinate(bitmapRect.left + horizontalPadding); Edge.TOP.setCoordinate(bitmapRect.top + verticalPadding); Edge.RIGHT.setCoordinate(bitmapRect.right - horizontalPadding); Edge.BOTTOM.setCoordinate(bitmapRect.bottom - verticalPadding); } }