***********com.app.cropwindow***************
1)AspectRatioUtil.java
======================
1)AspectRatioUtil.java
======================
/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow; import android.graphics.Rect; /** * Utility class for handling calculations involving a fixed aspect ratio. */public class AspectRatioUtil { /** * Calculates the aspect ratio given a rectangle. */ public static float calculateAspectRatio(float left, float top, float right, float bottom) { final float width = right - left; final float height = bottom - top; final float aspectRatio = width / height; return aspectRatio; } /** * Calculates the aspect ratio given a rectangle. */ public static float calculateAspectRatio(Rect rect) { final float aspectRatio = (float) rect.width() / (float) rect.height(); return aspectRatio; } /** * Calculates the x-coordinate of the left edge given the other sides of the * rectangle and an aspect ratio. */ public static float calculateLeft(float top, float right, float bottom, float targetAspectRatio) { final float height = bottom - top; // targetAspectRatio = width / height // width = targetAspectRatio * height // right - left = targetAspectRatio * height final float left = right - (targetAspectRatio * height); return left; } /** * Calculates the y-coordinate of the top edge given the other sides of the * rectangle and an aspect ratio. */ public static float calculateTop(float left, float right, float bottom, float targetAspectRatio) { final float width = right - left; // targetAspectRatio = width / height // width = targetAspectRatio * height // height = width / targetAspectRatio // bottom - top = width / targetAspectRatio final float top = bottom - (width / targetAspectRatio); return top; } /** * Calculates the x-coordinate of the right edge given the other sides of * the rectangle and an aspect ratio. */ public static float calculateRight(float left, float top, float bottom, float targetAspectRatio) { final float height = bottom - top; // targetAspectRatio = width / height // width = targetAspectRatio * height // right - left = targetAspectRatio * height final float right = (targetAspectRatio * height) + left; return right; } /** * Calculates the y-coordinate of the bottom edge given the other sides of * the rectangle and an aspect ratio. */ public static float calculateBottom(float left, float top, float right, float targetAspectRatio) { final float width = right - left; // targetAspectRatio = width / height // width = targetAspectRatio * height // height = width / targetAspectRatio // bottom - top = width / targetAspectRatio final float bottom = (width / targetAspectRatio) + top; return bottom; } /** * Calculates the width of a rectangle given the top and bottom edges and an * aspect ratio. */ public static float calculateWidth(float top, float bottom, float targetAspectRatio) { final float height = bottom - top; final float width = targetAspectRatio * height; return width; } /** * Calculates the height of a rectangle given the left and right edges and * an aspect ratio. */ public static float calculateHeight(float left, float right, float targetAspectRatio) { final float width = right - left; final float height = width / targetAspectRatio; return height; } }
2)Constants.java
=================
package com.eppico.cropwindow; import android.graphics.Bitmap;import android.net.Uri; /** * Created by manisha on 12/12/16. */ public class Constants { public static Uri IMAGE_URI; public static Bitmap CROPPED_BITMAP; public static boolean BTN_OK_CLICKED = false;}3)HandleUtil.java===================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow; import android.content.Context;import android.util.Pair;import android.util.TypedValue;import com.eppico.cropwindow.handle.Handle;import com.eppico.widgets.CropImageView;import com.eppico.widgets.CropOverlayView; /** * Utility class to perform basic operations with Handles. */public class HandleUtil { // Private Constants /////////////////////////////////////////////////////// // The radius (in dp) of the touchable area around the handle. We are basing // this value off of the recommended 48dp Rhythm. See: // http://developer.android.com/design/style/metrics-grids.html#48dp-rhythm private static final int TARGET_RADIUS_DP = 24; // Public Methods ////////////////////////////////////////////////////////// /** * Gets the default target radius (in pixels). This is the radius of the * circular area that can be touched in order to activate the handle. * * @param context the Context * @return the target radius (in pixels) */ public static float getTargetRadius(Context context) { final float targetRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, TARGET_RADIUS_DP, context.getResources().getDisplayMetrics()); return targetRadius; } /** * Determines which, if any, of the handles are pressed given the touch * coordinates, the bounding box, and the touch radius. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param left the x-coordinate of the left bound * @param top the y-coordinate of the top bound * @param right the x-coordinate of the right bound * @param bottom the y-coordinate of the bottom bound * @param targetRadius the target radius in pixels * @return the Handle that was pressed; null if no Handle was pressed */ public static Handle getPressedHandle(float x, float y, float left, float top, float right, float bottom, float targetRadius, CropImageView.CropShape cropShape) { Handle pressedHandle = null; if (cropShape == CropImageView.CropShape.RECTANGLE) { pressedHandle = getRectanglePressedHandle(x, y, left, top, right, bottom, targetRadius); } else if (cropShape == CropImageView.CropShape.OVAL) { pressedHandle = getOvalPressedHandle(x, y, left, top, right, bottom); } return pressedHandle; } /** * Determines which, if any, of the handles are pressed given the touch * coordinates, the bounding box, and the touch radius. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param left the x-coordinate of the left bound * @param top the y-coordinate of the top bound * @param right the x-coordinate of the right bound * @param bottom the y-coordinate of the bottom bound * @param targetRadius the target radius in pixels * @return the Handle that was pressed; null if no Handle was pressed */ private static Handle getRectanglePressedHandle(float x, float y, float left, float top, float right, float bottom, float targetRadius) { Handle pressedHandle = null; // Note: corner-handles take precedence, then side-handles, then center. if (HandleUtil.isInCornerTargetZone(x, y, left, top, targetRadius)) { pressedHandle = Handle.TOP_LEFT; } else if (HandleUtil.isInCornerTargetZone(x, y, right, top, targetRadius)) { pressedHandle = Handle.TOP_RIGHT; } else if (HandleUtil.isInCornerTargetZone(x, y, left, bottom, targetRadius)) { pressedHandle = Handle.BOTTOM_LEFT; } else if (HandleUtil.isInCornerTargetZone(x, y, right, bottom, targetRadius)) { pressedHandle = Handle.BOTTOM_RIGHT; } else if (HandleUtil.isInCenterTargetZone(x, y, left, top, right, bottom) && focusCenter()) { pressedHandle = Handle.CENTER; } else if (HandleUtil.isInHorizontalTargetZone(x, y, left, right, top, targetRadius)) { pressedHandle = Handle.TOP; } else if (HandleUtil.isInHorizontalTargetZone(x, y, left, right, bottom, targetRadius)) { pressedHandle = Handle.BOTTOM; } else if (HandleUtil.isInVerticalTargetZone(x, y, left, top, bottom, targetRadius)) { pressedHandle = Handle.LEFT; } else if (HandleUtil.isInVerticalTargetZone(x, y, right, top, bottom, targetRadius)) { pressedHandle = Handle.RIGHT; } else if (HandleUtil.isInCenterTargetZone(x, y, left, top, right, bottom) && !focusCenter()) { pressedHandle = Handle.CENTER; } return pressedHandle; } /** * Determines which, if any, of the handles are pressed given the touch * coordinates, the bounding box/oval, and the touch radius. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param left the x-coordinate of the left bound * @param top the y-coordinate of the top bound * @param right the x-coordinate of the right bound * @param bottom the y-coordinate of the bottom bound * @return the Handle that was pressed; null if no Handle was pressed */ private static Handle getOvalPressedHandle(float x, float y, float left, float top, float right, float bottom) { /* Use a 6x6 grid system divided into 9 "handles", with the center the biggest region. While this is not perfect, it's a good quick-to-ship approach. TL T T T T TR L C C C C R L C C C C R L C C C C R L C C C C R BL B B B B BR */ final float cellLength = (right - left) / 6; final float leftCenter = left + cellLength; final float rightCenter = left + (5 * cellLength); final float cellHeight = (bottom - top) / 6; final float topCenter = top + cellHeight; final float bottomCenter = top + 5 * cellHeight; final Handle pressedHandle; if (x < leftCenter) { if (y < topCenter) { pressedHandle = Handle.TOP_LEFT; } else if (y < bottomCenter) { pressedHandle = Handle.LEFT; } else { pressedHandle = Handle.BOTTOM_LEFT; } } else if (x < rightCenter) { if (y < topCenter) { pressedHandle = Handle.TOP; } else if (y < bottomCenter) { pressedHandle = Handle.CENTER; } else { pressedHandle = Handle.BOTTOM; } } else { if (y < topCenter) { pressedHandle = Handle.TOP_RIGHT; } else if (y < bottomCenter) { pressedHandle = Handle.RIGHT; } else { pressedHandle = Handle.BOTTOM_RIGHT; } } return pressedHandle; } /** * Calculates the offset of the touch point from the precise location of the * specified handle. * * @return the offset as a Pair where the x-offset is the first value and * the y-offset is the second value; null if the handle is null */ public static Pair<Float, Float> getOffset(Handle handle, float x, float y, float left, float top, float right, float bottom) { if (handle == null) { return null; } float touchOffsetX = 0; float touchOffsetY = 0; // Calculate the offset from the appropriate handle. switch (handle) { case TOP_LEFT: touchOffsetX = left - x; touchOffsetY = top - y; break; case TOP_RIGHT: touchOffsetX = right - x; touchOffsetY = top - y; break; case BOTTOM_LEFT: touchOffsetX = left - x; touchOffsetY = bottom - y; break; case BOTTOM_RIGHT: touchOffsetX = right - x; touchOffsetY = bottom - y; break; case LEFT: touchOffsetX = left - x; touchOffsetY = 0; break; case TOP: touchOffsetX = 0; touchOffsetY = top - y; break; case RIGHT: touchOffsetX = right - x; touchOffsetY = 0; break; case BOTTOM: touchOffsetX = 0; touchOffsetY = bottom - y; break; case CENTER: final float centerX = (right + left) / 2; final float centerY = (top + bottom) / 2; touchOffsetX = centerX - x; touchOffsetY = centerY - y; break; } final Pair<Float, Float> result = new Pair<Float, Float>(touchOffsetX, touchOffsetY); return result; } // Private Methods ///////////////////////////////////////////////////////// /** * Determines if the specified coordinate is in the target touch zone for a * corner handle. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param handleX the x-coordinate of the corner handle * @param handleY the y-coordinate of the corner handle * @param targetRadius the target radius in pixels * @return true if the touch point is in the target touch zone; false * otherwise */ private static boolean isInCornerTargetZone(float x, float y, float handleX, float handleY, float targetRadius) { if (Math.abs(x - handleX) <= targetRadius && Math.abs(y - handleY) <= targetRadius) { return true; } return false; } /** * Determines if the specified coordinate is in the target touch zone for a * horizontal bar handle. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param handleXStart the left x-coordinate of the horizontal bar handle * @param handleXEnd the right x-coordinate of the horizontal bar handle * @param handleY the y-coordinate of the horizontal bar handle * @param targetRadius the target radius in pixels * @return true if the touch point is in the target touch zone; false * otherwise */ private static boolean isInHorizontalTargetZone(float x, float y, float handleXStart, float handleXEnd, float handleY, float targetRadius) { if (x > handleXStart && x < handleXEnd && Math.abs(y - handleY) <= targetRadius) { return true; } return false; } /** * Determines if the specified coordinate is in the target touch zone for a * vertical bar handle. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param handleX the x-coordinate of the vertical bar handle * @param handleYStart the top y-coordinate of the vertical bar handle * @param handleYEnd the bottom y-coordinate of the vertical bar handle * @param targetRadius the target radius in pixels * @return true if the touch point is in the target touch zone; false * otherwise */ private static boolean isInVerticalTargetZone(float x, float y, float handleX, float handleYStart, float handleYEnd, float targetRadius) { if (Math.abs(x - handleX) <= targetRadius && y > handleYStart && y < handleYEnd) { return true; } return false; } /** * Determines if the specified coordinate falls anywhere inside the given * bounds. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param left the x-coordinate of the left bound * @param top the y-coordinate of the top bound * @param right the x-coordinate of the right bound * @param bottom the y-coordinate of the bottom bound * @return true if the touch point is inside the bounding rectangle; false * otherwise */ private static boolean isInCenterTargetZone(float x, float y, float left, float top, float right, float bottom) { if (x > left && x < right && y > top && y < bottom) { return true; } return false; } /** * Determines if the cropper should focus on the center handle or the side * handles. If it is a small image, focus on the center handle so the user * can move it. If it is a large image, focus on the side handles so user * can grab them. Corresponds to the appearance of the * RuleOfThirdsGuidelines. * * @return true if it is small enough such that it should focus on the * center; less than show_guidelines limit */ private static boolean focusCenter() { return (!CropOverlayView.showGuidelines()); } }4)ImageViewUtil.java=====================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow; import android.content.ContentResolver;import android.content.Context;import android.database.Cursor;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.BitmapRegionDecoder;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.media.ExifInterface;import android.net.Uri;import android.provider.MediaStore;import android.view.View;import android.widget.ImageView; import java.io.Closeable;import java.io.File;import java.io.IOException;import java.io.InputStream; /** * Utility class that deals with operations with an ImageView. */public class ImageViewUtil { /** * Gets the rectangular position of a Bitmap if it were placed inside a View. * * @param bitmap the Bitmap * @param view the parent View of the Bitmap * @param scaleType the desired scale type * @return the rectangular position of the Bitmap */ public static Rect getBitmapRect(Bitmap bitmap, View view, ImageView.ScaleType scaleType) { final int bitmapWidth = bitmap.getWidth(); final int bitmapHeight = bitmap.getHeight(); final int viewWidth = view.getWidth(); final int viewHeight = view.getHeight(); switch (scaleType) { default: case CENTER_INSIDE: return getBitmapRectCenterInsideHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight); case FIT_CENTER: return getBitmapRectFitCenterHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight); } } /** * Gets the rectangular position of a Bitmap if it were placed inside a View. * * @param bitmapWidth the Bitmap's width * @param bitmapHeight the Bitmap's height * @param viewWidth the parent View's width * @param viewHeight the parent View's height * @param scaleType the desired scale type * @return the rectangular position of the Bitmap */ public static Rect getBitmapRect(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight, ImageView.ScaleType scaleType) { switch (scaleType) { default: case CENTER_INSIDE: return getBitmapRectCenterInsideHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight); case FIT_CENTER: return getBitmapRectFitCenterHelper(bitmapWidth, bitmapHeight, viewWidth, viewHeight); } } /** * Rotate the given image by reading the Exif value of the image (uri).<br> * If no rotation is required the image will not be rotated.<br> * New bitmap is created and the old one is recycled. */ public static RotateBitmapResult rotateBitmapByExif(Context context, Bitmap bitmap, Uri uri) { try { File file = getFileFromUri(context, uri); if (file.exists()) { ExifInterface ei = new ExifInterface(file.getAbsolutePath()); return rotateBitmapByExif(bitmap, ei); } } catch (Exception ignored) { } return new RotateBitmapResult(bitmap, 0); } /** * Rotate the given image by given Exif value.<br> * If no rotation is required the image will not be rotated.<br> * New bitmap is created and the old one is recycled. */ public static RotateBitmapResult rotateBitmapByExif(Bitmap bitmap, ExifInterface exif) { int degrees = 0; int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degrees = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degrees = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degrees = 270; break; } if (degrees > 0) { bitmap = rotateBitmap(bitmap, degrees); } return new RotateBitmapResult(bitmap, degrees); } /** * Decode bitmap from stream using sampling to get bitmap with the requested limit. */ public static DecodeBitmapResult decodeSampledBitmap(Context context, Uri uri, int reqWidth, int reqHeight) { InputStream stream = null; try { ContentResolver resolver = context.getContentResolver(); stream = resolver.openInputStream(uri); // First decode with inJustDecodeBounds=true to check dimensions BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeStream(stream, new Rect(0, 0, 0, 0), options); options.inJustDecodeBounds = false; // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight); // Decode bitmap with inSampleSize set closeSafe(stream); stream = resolver.openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(stream, new Rect(0, 0, 0, 0), options); return new DecodeBitmapResult(bitmap, options.inSampleSize); } catch (Exception e) { throw new RuntimeException("Failed to load sampled bitmap", e); } finally { closeSafe(stream); } } /** * Decode specific rectangle bitmap from stream using sampling to get bitmap with the requested limit. */ public static DecodeBitmapResult decodeSampledBitmapRegion(Context context, Uri uri, Rect rect, int reqWidth, int reqHeight) { InputStream stream = null; try { ContentResolver resolver = context.getContentResolver(); stream = resolver.openInputStream(uri); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = calculateInSampleSize(rect.width(), rect.height(), reqWidth, reqHeight); BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(stream, false); Bitmap bitmap = decoder.decodeRegion(rect, options); return new DecodeBitmapResult(bitmap, options.inSampleSize); } catch (Exception e) { throw new RuntimeException("Failed to load sampled bitmap", e); } finally { closeSafe(stream); } } /** * Crop image bitmap from URI by decoding it with specific width and height to down-sample if required. */ public static Bitmap cropBitmap(Context context, Uri loadedImageUri, Rect rect, int degreesRotated, int reqWidth, int reqHeight) { reqWidth = reqWidth > 0 ? reqWidth : rect.width(); reqHeight = reqHeight > 0 ? reqHeight : rect.height(); DecodeBitmapResult result = ImageViewUtil.decodeSampledBitmapRegion(context, loadedImageUri, rect, reqWidth, reqHeight); Bitmap bitmap = result.bitmap; if (degreesRotated > 0) { bitmap = ImageViewUtil.rotateBitmap(bitmap, degreesRotated); } return bitmap; } /** * Crop image bitmap from given bitmap. */ public static Bitmap cropBitmap(Bitmap bitmap, Rect rect) { return Bitmap.createBitmap(bitmap, rect.left, rect.top, rect.width(), rect.height()); } /** * Create a new bitmap that has all pixels beyond the oval shape transparent. */ public static Bitmap toOvalBitmap(Bitmap bitmap) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(output); int color = 0xff424242; Paint paint = new Paint(); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); RectF rect = new RectF(0, 0, width, height); canvas.drawOval(rect, paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(bitmap, 0, 0, paint); bitmap.recycle(); return output; } /** * Calculate the largest inSampleSize value that is a power of 2 and keeps both * height and width larger than the requested height and width. */ public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) { int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } /** * Get {@link File} object for the given Android URI.<br> * Use content resolver to get real path if direct path doesn't return valid file. */ public static File getFileFromUri(Context context, Uri uri) { // first try by direct path File file = new File(uri.getPath()); if (file.exists()) { return file; } // try reading real path from content resolver (gallery images) Cursor cursor = null; try { String[] proj = {MediaStore.Images.Media.DATA}; cursor = context.getContentResolver().query(uri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String realPath = cursor.getString(column_index); file = new File(realPath); } catch (Exception ignored) { } finally { if (cursor != null) cursor.close(); } return file; } /** * Rotate the given bitmap by the given degrees.<br> * New bitmap is created and the old one is recycled. */ public static RotateBitmapResult rotateBitmapResult(Bitmap bitmap, int degrees) { return new RotateBitmapResult(rotateBitmap(bitmap, degrees), degrees); } /** * Rotate the given bitmap by the given degrees.<br> * New bitmap is created and the old one is recycled. */ public static Bitmap rotateBitmap(Bitmap bitmap, int degrees) { if (degrees > 0) { Matrix matrix = new Matrix(); matrix.setRotate(degrees); Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false); bitmap.recycle(); return newBitmap; } else { return bitmap; } } /** * Close the given closeable object (Stream) in a safe way: check if it is null and catch-log * exception thrown. * * @param closeable the closable object to close */ public static void closeSafe(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (IOException ignored) { } } } /** * Helper that does the work of the above functions. Gets the rectangular * position of a Bitmap if it were placed inside a View with scale type set * to {@link ImageView.ScaleType #CENTER_INSIDE}. * * @param bitmapWidth the Bitmap's width * @param bitmapHeight the Bitmap's height * @param viewWidth the parent View's width * @param viewHeight the parent View's height * @return the rectangular position of the Bitmap */ private static Rect getBitmapRectCenterInsideHelper(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) { double resultWidth; double resultHeight; int resultX; int resultY; double viewToBitmapWidthRatio = Double.POSITIVE_INFINITY; double viewToBitmapHeightRatio = Double.POSITIVE_INFINITY; // Checks if either width or height needs to be fixed if (viewWidth < bitmapWidth) { viewToBitmapWidthRatio = (double) viewWidth / (double) bitmapWidth; } if (viewHeight < bitmapHeight) { viewToBitmapHeightRatio = (double) viewHeight / (double) bitmapHeight; } // If either needs to be fixed, choose smallest ratio and calculate from // there if (viewToBitmapWidthRatio != Double.POSITIVE_INFINITY || viewToBitmapHeightRatio != Double.POSITIVE_INFINITY) { if (viewToBitmapWidthRatio <= viewToBitmapHeightRatio) { resultWidth = viewWidth; resultHeight = (bitmapHeight * resultWidth / bitmapWidth); } else { resultHeight = viewHeight; resultWidth = (bitmapWidth * resultHeight / bitmapHeight); } } // Otherwise, the picture is within frame layout bounds. Desired width // is simply picture size else { resultHeight = bitmapHeight; resultWidth = bitmapWidth; } // Calculate the position of the bitmap inside the ImageView. if (resultWidth == viewWidth) { resultX = 0; resultY = (int) Math.round((viewHeight - resultHeight) / 2); } else if (resultHeight == viewHeight) { resultX = (int) Math.round((viewWidth - resultWidth) / 2); resultY = 0; } else { resultX = (int) Math.round((viewWidth - resultWidth) / 2); resultY = (int) Math.round((viewHeight - resultHeight) / 2); } final Rect result = new Rect(resultX, resultY, resultX + (int) Math.ceil(resultWidth), resultY + (int) Math.ceil(resultHeight)); return result; } /** * Helper that does the work of the above functions. Gets the rectangular * position of a Bitmap if it were placed inside a View with scale type set * to {@link ImageView.ScaleType#FIT_CENTER}. * * @param bitmapWidth the Bitmap's width * @param bitmapHeight the Bitmap's height * @param viewWidth the parent View's width * @param viewHeight the parent View's height * @return the rectangular position of the Bitmap */ private static Rect getBitmapRectFitCenterHelper(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) { double resultWidth; double resultHeight; int resultX; int resultY; double viewToBitmapWidthRatio = (double) viewWidth / bitmapWidth; double viewToBitmapHeightRatio = (double) viewHeight / bitmapHeight; // If either needs to be fixed, choose smallest ratio and calculate from // there if (viewToBitmapWidthRatio <= viewToBitmapHeightRatio) { resultWidth = viewWidth; resultHeight = (bitmapHeight * resultWidth / bitmapWidth); } else { resultHeight = viewHeight; resultWidth = (bitmapWidth * resultHeight / bitmapHeight); } // Calculate the position of the bitmap inside the ImageView. if (resultWidth == viewWidth) { resultX = 0; resultY = (int) Math.round((viewHeight - resultHeight) / 2); } else if (resultHeight == viewHeight) { resultX = (int) Math.round((viewWidth - resultWidth) / 2); resultY = 0; } else { resultX = (int) Math.round((viewWidth - resultWidth) / 2); resultY = (int) Math.round((viewHeight - resultHeight) / 2); } final Rect result = new Rect(resultX, resultY, resultX + (int) Math.ceil(resultWidth), resultY + (int) Math.ceil(resultHeight)); return result; } //region: Inner class: DecodeBitmapResult /** * The result of {@link #decodeSampledBitmap(Context, Uri, int, int)}. */ public static final class DecodeBitmapResult { /** * The loaded bitmap */ public final Bitmap bitmap; /** * The sample size used to load the given bitmap */ public final int sampleSize; DecodeBitmapResult(Bitmap bitmap, int sampleSize) { this.sampleSize = sampleSize; this.bitmap = bitmap; } } //endregion //region: Inner class: RotateBitmapResult /** * The result of {@link #rotateBitmapByExif(Bitmap, ExifInterface)}. */ public static final class RotateBitmapResult { /** * The loaded bitmap */ public final Bitmap bitmap; /** * The degrees the image was rotated */ public final int degrees; RotateBitmapResult(Bitmap bitmap, int degrees) { this.bitmap = bitmap; this.degrees = degrees; } } //endregion}5)PaintUtil.java=====================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow; import android.content.Context;import android.graphics.Color;import android.graphics.Paint;import android.util.TypedValue; /** * Utility class for handling all of the Paint used to draw the CropOverlayView. */public final class PaintUtil { //region: Fields and Consts private static final int DEFAULT_CORNER_COLOR = Color.WHITE; private static final String SEMI_TRANSPARENT = "#AAFFFFFF"; private static final String DEFAULT_BACKGROUND_COLOR_ID = "#77000000"; private static final float DEFAULT_LINE_THICKNESS_DP = 3; private static final float DEFAULT_CORNER_THICKNESS_DP = 2; private static final float DEFAULT_GUIDELINE_THICKNESS_PX = 2; //endregion /** * Creates the Paint object for drawing the crop window border. * * @param context the Context * @return new Paint object */ public static Paint newBorderPaint(Context context) { // Set the line thickness for the crop window border. final float lineThicknessPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_LINE_THICKNESS_DP, context.getResources().getDisplayMetrics()); final Paint borderPaint = new Paint(); borderPaint.setColor(Color.parseColor(SEMI_TRANSPARENT)); borderPaint.setStrokeWidth(lineThicknessPx); borderPaint.setStyle(Paint.Style.STROKE); borderPaint.setAntiAlias(true); return borderPaint; } /** * Creates the Paint object for drawing the crop window guidelines. * * @return the new Paint object */ public static Paint newGuidelinePaint() { final Paint paint = new Paint(); paint.setColor(Color.parseColor(SEMI_TRANSPARENT)); paint.setStrokeWidth(DEFAULT_GUIDELINE_THICKNESS_PX); return paint; } /** * Creates the Paint object for drawing the translucent overlay outside the * crop window. * * @return the new Paint object */ public static Paint newBackgroundPaint() { Paint paint = new Paint(); paint.setColor(Color.parseColor(DEFAULT_BACKGROUND_COLOR_ID)); return paint; } /** * Creates the Paint object for drawing the corners of the border * * @param context the Context * @return the new Paint object */ public static Paint newCornerPaint(Context context) { // Set the line thickness for the crop window border. final float lineThicknessPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_THICKNESS_DP, context.getResources().getDisplayMetrics()); final Paint cornerPaint = new Paint(); cornerPaint.setColor(DEFAULT_CORNER_COLOR); cornerPaint.setStrokeWidth(lineThicknessPx); cornerPaint.setStyle(Paint.Style.STROKE); return cornerPaint; } /** * Returns the value of the corner thickness * * @return Float equivalent to the corner thickness */ public static float getCornerThickness() { return DEFAULT_CORNER_THICKNESS_DP; } /** * Returns the value of the line thickness of the border * * @return Float equivalent to the line thickness */ public static float getLineThickness() { return DEFAULT_LINE_THICKNESS_DP; } }*****************cropwondow=>handle*********************1)CenterHandleHelper.java=========================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect; import com.eppico.cropwindow.edge.Edge; //import com.credencys.goscoop.cropwindow.edge.Edge; /** * HandleHelper class to handle the center handle. */class CenterHandleHelper extends HandleHelper { // Constructor ///////////////////////////////////////////////////////////// CenterHandleHelper() { super(null, null); } // HandleHelper Methods //////////////////////////////////////////////////// @Override void updateCropWindow(float x, float y, Rect 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); } } @Override void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius) { updateCropWindow(x, y, imageRect, snapRadius); } }2)CornerHandleHelper.java==========================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect;import com.eppico.cropwindow.edge.Edge;import com.eppico.cropwindow.edge.EdgePair; //import com.credencys.goscoop.cropwindow.edge.Edge;//import com.credencys.goscoop.cropwindow.edge.EdgePair; /** * HandleHelper class to handle corner Handles (i.e. top-left, top-right, * bottom-left, and bottom-right handles). */class CornerHandleHelper extends HandleHelper { // Constructor ///////////////////////////////////////////////////////////// CornerHandleHelper(Edge horizontalEdge, Edge verticalEdge) { super(horizontalEdge, verticalEdge); } // HandleHelper Methods //////////////////////////////////////////////////// @Override void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius) { final EdgePair activeEdges = getActiveEdges(x, y, targetAspectRatio); final Edge primaryEdge = activeEdges.primary; final Edge secondaryEdge = activeEdges.secondary; primaryEdge.adjustCoordinate(x, y, imageRect, snapRadius, targetAspectRatio); secondaryEdge.adjustCoordinate(targetAspectRatio); if (secondaryEdge.isOutsideMargin(imageRect, snapRadius)) { secondaryEdge.snapToRect(imageRect); primaryEdge.adjustCoordinate(targetAspectRatio); } } }3)Handle.java===================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect; import com.eppico.cropwindow.edge.Edge; //import com.credencys.goscoop.cropwindow.edge.Edge; /** * Enum representing a pressable, draggable Handle on the crop window. */public enum Handle { TOP_LEFT(new CornerHandleHelper(Edge.TOP, Edge.LEFT)), TOP_RIGHT(new CornerHandleHelper(Edge.TOP, Edge.RIGHT)), BOTTOM_LEFT(new CornerHandleHelper(Edge.BOTTOM, Edge.LEFT)), BOTTOM_RIGHT(new CornerHandleHelper(Edge.BOTTOM, Edge.RIGHT)), LEFT(new VerticalHandleHelper(Edge.LEFT)), TOP(new HorizontalHandleHelper(Edge.TOP)), RIGHT(new VerticalHandleHelper(Edge.RIGHT)), BOTTOM(new HorizontalHandleHelper(Edge.BOTTOM)), CENTER(new CenterHandleHelper()); // Member Variables //////////////////////////////////////////////////////// private HandleHelper mHelper; // Constructors //////////////////////////////////////////////////////////// Handle(HandleHelper helper) { mHelper = helper; } // Public Methods ////////////////////////////////////////////////////////// public void updateCropWindow(float x, float y, Rect imageRect, float snapRadius) { mHelper.updateCropWindow(x, y, imageRect, snapRadius); } public void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius) { mHelper.updateCropWindow(x, y, targetAspectRatio, imageRect, snapRadius); } }4)HandleHelper.java====================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect; import com.eppico.cropwindow.AspectRatioUtil;import com.eppico.cropwindow.edge.Edge;import com.eppico.cropwindow.edge.EdgePair; //import com.credencys.goscoop.cropwindow.edge.Edge;//import com.credencys.goscoop.cropwindow.edge.EdgePair;//import com.credencys.goscoop.utils.AspectRatioUtil; /** * Abstract helper class to handle operations on a crop window Handle. */abstract class HandleHelper { // Member Variables //////////////////////////////////////////////////////// private static final float UNFIXED_ASPECT_RATIO_CONSTANT = 1; private Edge mHorizontalEdge; private Edge mVerticalEdge; // Save the Pair object as a member variable to avoid having to instantiate // a new Object every time getActiveEdges() is called. private EdgePair mActiveEdges; // Constructor ///////////////////////////////////////////////////////////// /** * Constructor. * * @param horizontalEdge the horizontal edge associated with this handle; * may be null * @param verticalEdge the vertical edge associated with this handle; may be * null */ HandleHelper(Edge horizontalEdge, Edge verticalEdge) { mHorizontalEdge = horizontalEdge; mVerticalEdge = verticalEdge; mActiveEdges = new EdgePair(mHorizontalEdge, mVerticalEdge); } // Package-Private Methods ///////////////////////////////////////////////// /** * Updates the crop window by directly setting the Edge coordinates. * * @param x the new x-coordinate of this handle * @param y the new y-coordinate of this handle * @param imageRect the bounding rectangle of the image * @param parentView the parent View containing the image * @param snapRadius the maximum distance (in pixels) at which the crop * window should snap to the image */ void updateCropWindow(float x, float y, Rect imageRect, float snapRadius) { final EdgePair activeEdges = getActiveEdges(); final Edge primaryEdge = activeEdges.primary; final Edge secondaryEdge = activeEdges.secondary; if (primaryEdge != null) primaryEdge.adjustCoordinate(x, y, imageRect, snapRadius, UNFIXED_ASPECT_RATIO_CONSTANT); if (secondaryEdge != null) secondaryEdge.adjustCoordinate(x, y, imageRect, snapRadius, UNFIXED_ASPECT_RATIO_CONSTANT); } /** * Updates the crop window by directly setting the Edge coordinates; this * method maintains a given aspect ratio. * * @param x the new x-coordinate of this handle * @param y the new y-coordinate of this handle * @param targetAspectRatio the aspect ratio to maintain * @param imageRect the bounding rectangle of the image * @param parentView the parent View containing the image * @param snapRadius the maximum distance (in pixels) at which the crop * window should snap to the image */ abstract void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius); /** * Gets the Edges associated with this handle (i.e. the Edges that should be * moved when this handle is dragged). This is used when we are not * maintaining the aspect ratio. * * @return the active edge as a pair (the pair may contain null values for * the <code>primary</code>, <code>secondary</code> or both fields) */ EdgePair getActiveEdges() { return mActiveEdges; } /** * Gets the Edges associated with this handle as an ordered Pair. The * <code>primary</code> Edge in the pair is the determining side. This * method is used when we need to maintain the aspect ratio. * * @param x the x-coordinate of the touch point * @param y the y-coordinate of the touch point * @param targetAspectRatio the aspect ratio that we are maintaining * @return the active edges as an ordered pair */ EdgePair getActiveEdges(float x, float y, float targetAspectRatio) { // Calculate the aspect ratio if this handle were dragged to the given // x-y coordinate. final float potentialAspectRatio = getAspectRatio(x, y); // If the touched point is wider than the aspect ratio, then x // is the determining side. Else, y is the determining side. if (potentialAspectRatio > targetAspectRatio) { mActiveEdges.primary = mVerticalEdge; mActiveEdges.secondary = mHorizontalEdge; } else { mActiveEdges.primary = mHorizontalEdge; mActiveEdges.secondary = mVerticalEdge; } return mActiveEdges; } // Private Methods ///////////////////////////////////////////////////////// /** * Gets the aspect ratio of the resulting crop window if this handle were * dragged to the given point. * * @param x the x-coordinate * @param y the y-coordinate * @return the aspect ratio */ private float getAspectRatio(float x, float y) { // Replace the active edge coordinate with the given touch coordinate. final float left = (mVerticalEdge == Edge.LEFT) ? x : Edge.LEFT.getCoordinate(); final float top = (mHorizontalEdge == Edge.TOP) ? y : Edge.TOP.getCoordinate(); final float right = (mVerticalEdge == Edge.RIGHT) ? x : Edge.RIGHT.getCoordinate(); final float bottom = (mHorizontalEdge == Edge.BOTTOM) ? y : Edge.BOTTOM.getCoordinate(); final float aspectRatio = AspectRatioUtil.calculateAspectRatio(left, top, right, bottom); return aspectRatio; } }5)HorizontalHandleHelper.java==============================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect; import com.eppico.cropwindow.AspectRatioUtil;import com.eppico.cropwindow.edge.Edge; //import com.credencys.goscoop.cropwindow.edge.Edge;//import com.credencys.goscoop.utils.AspectRatioUtil; /** * Handle helper class to handle horizontal handles (i.e. top and bottom * handles). */class HorizontalHandleHelper extends HandleHelper { // Member Variables //////////////////////////////////////////////////////// private Edge mEdge; // Constructor ///////////////////////////////////////////////////////////// HorizontalHandleHelper(Edge edge) { super(edge, null); mEdge = edge; } // HandleHelper Methods //////////////////////////////////////////////////// @Override void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius) { // Adjust this Edge accordingly. mEdge.adjustCoordinate(x, y, imageRect, snapRadius, targetAspectRatio); float left = Edge.LEFT.getCoordinate(); float top = Edge.TOP.getCoordinate(); float right = Edge.RIGHT.getCoordinate(); float bottom = Edge.BOTTOM.getCoordinate(); // After this Edge is moved, our crop window is now out of proportion. final float targetWidth = AspectRatioUtil.calculateWidth(top, bottom, targetAspectRatio); final float currentWidth = right - left; // Adjust the crop window so that it maintains the given aspect ratio by // moving the adjacent edges symmetrically in or out. final float difference = targetWidth - currentWidth; final float halfDifference = difference / 2; left -= halfDifference; right += halfDifference; Edge.LEFT.setCoordinate(left); Edge.RIGHT.setCoordinate(right); // Check if we have gone out of bounds on the sides, and fix. if (Edge.LEFT.isOutsideMargin(imageRect, snapRadius) && !mEdge.isNewRectangleOutOfBounds(Edge.LEFT, imageRect, targetAspectRatio)) { final float offset = Edge.LEFT.snapToRect(imageRect); Edge.RIGHT.offset(-offset); mEdge.adjustCoordinate(targetAspectRatio); } if (Edge.RIGHT.isOutsideMargin(imageRect, snapRadius) && !mEdge.isNewRectangleOutOfBounds(Edge.RIGHT, imageRect, targetAspectRatio)) { final float offset = Edge.RIGHT.snapToRect(imageRect); Edge.LEFT.offset(-offset); mEdge.adjustCoordinate(targetAspectRatio); } } }6)VerticalHandleHelper.java============================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.handle; import android.graphics.Rect; import com.eppico.cropwindow.AspectRatioUtil;import com.eppico.cropwindow.edge.Edge;////import com.credencys.goscoop.cropwindow.edge.Edge;//import com.credencys.goscoop.utils.AspectRatioUtil; /** * HandleHelper class to handle vertical handles (i.e. left and right handles). */class VerticalHandleHelper extends HandleHelper { // Member Variables //////////////////////////////////////////////////////// private Edge mEdge; // Constructor ///////////////////////////////////////////////////////////// VerticalHandleHelper(Edge edge) { super(null, edge); mEdge = edge; } // HandleHelper Methods //////////////////////////////////////////////////// @Override void updateCropWindow(float x, float y, float targetAspectRatio, Rect imageRect, float snapRadius) { // Adjust this Edge accordingly. mEdge.adjustCoordinate(x, y, imageRect, snapRadius, targetAspectRatio); float left = Edge.LEFT.getCoordinate(); float top = Edge.TOP.getCoordinate(); float right = Edge.RIGHT.getCoordinate(); float bottom = Edge.BOTTOM.getCoordinate(); // After this Edge is moved, our crop window is now out of proportion. final float targetHeight = AspectRatioUtil.calculateHeight(left, right, targetAspectRatio); final float currentHeight = bottom - top; // Adjust the crop window so that it maintains the given aspect ratio by // moving the adjacent edges symmetrically in or out. final float difference = targetHeight - currentHeight; final float halfDifference = difference / 2; top -= halfDifference; bottom += halfDifference; Edge.TOP.setCoordinate(top); Edge.BOTTOM.setCoordinate(bottom); // Check if we have gone out of bounds on the top or bottom, and fix. if (Edge.TOP.isOutsideMargin(imageRect, snapRadius) && !mEdge.isNewRectangleOutOfBounds(Edge.TOP, imageRect, targetAspectRatio)) { final float offset = Edge.TOP.snapToRect(imageRect); Edge.BOTTOM.offset(-offset); mEdge.adjustCoordinate(targetAspectRatio); } if (Edge.BOTTOM.isOutsideMargin(imageRect, snapRadius) && !mEdge.isNewRectangleOutOfBounds(Edge.BOTTOM, imageRect, targetAspectRatio)) { final float offset = Edge.BOTTOM.snapToRect(imageRect); Edge.TOP.offset(-offset); mEdge.adjustCoordinate(targetAspectRatio); } } }*********************cropwindow=>edge******************8881)Edge.java============/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.edge; import android.graphics.Rect;import android.view.View; import com.eppico.cropwindow.AspectRatioUtil; /** * Enum representing an edge in the crop window. */public enum Edge { LEFT, TOP, RIGHT, BOTTOM; // Private Constants /////////////////////////////////////////////////////// // Minimum distance in pixels that one edge can get to its opposing edge. // This is an arbitrary value that simply prevents the crop window from // becoming too small. public static final int MIN_CROP_LENGTH_PX = 40; // Member Variables //////////////////////////////////////////////////////// private float mCoordinate; // Public Methods ////////////////////////////////////////////////////////// /** * Sets the coordinate of the Edge. The coordinate will represent the * x-coordinate for LEFT and RIGHT Edges and the y-coordinate for TOP and * BOTTOM edges. * * @param coordinate the position of the edge */ public void setCoordinate(float coordinate) { mCoordinate = coordinate; } /** * Add the given number of pixels to the current coordinate position of this * Edge. * * @param distance the number of pixels to add */ public void offset(float distance) { mCoordinate += distance; } /** * Gets the coordinate of the Edge * * @return the Edge coordinate (x-coordinate for LEFT and RIGHT Edges and * the y-coordinate for TOP and BOTTOM edges) */ public float getCoordinate() { return mCoordinate; } /** * Sets the Edge to the given x-y coordinate but also adjusting for snapping * to the image bounds and parent view border constraints. * * @param x the x-coordinate * @param y the y-coordinate * @param imageRect the bounding rectangle of the image * @param imageSnapRadius the radius (in pixels) at which the edge should * snap to the image */ public void adjustCoordinate(float x, float y, Rect imageRect, float imageSnapRadius, float aspectRatio) { switch (this) { case LEFT: mCoordinate = adjustLeft(x, imageRect, imageSnapRadius, aspectRatio); break; case TOP: mCoordinate = adjustTop(y, imageRect, imageSnapRadius, aspectRatio); break; case RIGHT: mCoordinate = adjustRight(x, imageRect, imageSnapRadius, aspectRatio); break; case BOTTOM: mCoordinate = adjustBottom(y, imageRect, imageSnapRadius, aspectRatio); break; } } /** * Adjusts this Edge position such that the resulting window will have the * given aspect ratio. * * @param aspectRatio the aspect ratio to achieve */ public void adjustCoordinate(float aspectRatio) { final float left = Edge.LEFT.getCoordinate(); final float top = Edge.TOP.getCoordinate(); final float right = Edge.RIGHT.getCoordinate(); final float bottom = Edge.BOTTOM.getCoordinate(); switch (this) { case LEFT: mCoordinate = AspectRatioUtil.calculateLeft(top, right, bottom, aspectRatio); break; case TOP: mCoordinate = AspectRatioUtil.calculateTop(left, right, bottom, aspectRatio); break; case RIGHT: mCoordinate = AspectRatioUtil.calculateRight(left, top, bottom, aspectRatio); break; case BOTTOM: mCoordinate = AspectRatioUtil.calculateBottom(left, top, right, aspectRatio); break; } } /** * Returns whether or not you can re-scale the image based on whether any edge would be out of bounds. * Checks all the edges for a possibility of jumping out of bounds. * * @param edge the Edge that is about to be expanded * @param imageRect the rectangle of the picture * @param aspectRatio the desired aspectRatio of the picture. * @return whether or not the new image would be out of bounds. */ public boolean isNewRectangleOutOfBounds(Edge edge, Rect imageRect, float aspectRatio) { float offset = edge.snapOffset(imageRect); switch (this) { case LEFT: if (edge.equals(Edge.TOP)) { float top = imageRect.top; float bottom = Edge.BOTTOM.getCoordinate() - offset; float right = Edge.RIGHT.getCoordinate(); float left = AspectRatioUtil.calculateLeft(top, right, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } else if (edge.equals(Edge.BOTTOM)) { float bottom = imageRect.bottom; float top = Edge.TOP.getCoordinate() - offset; float right = Edge.RIGHT.getCoordinate(); float left = AspectRatioUtil.calculateLeft(top, right, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } break; case TOP: if (edge.equals(Edge.LEFT)) { float left = imageRect.left; float right = Edge.RIGHT.getCoordinate() - offset; float bottom = Edge.BOTTOM.getCoordinate(); float top = AspectRatioUtil.calculateTop(left, right, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } else if (edge.equals(Edge.RIGHT)) { float right = imageRect.right; float left = Edge.LEFT.getCoordinate() - offset; float bottom = Edge.BOTTOM.getCoordinate(); float top = AspectRatioUtil.calculateTop(left, right, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } break; case RIGHT: if (edge.equals(Edge.TOP)) { float top = imageRect.top; float bottom = Edge.BOTTOM.getCoordinate() - offset; float left = Edge.LEFT.getCoordinate(); float right = AspectRatioUtil.calculateRight(left, top, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } else if (edge.equals(Edge.BOTTOM)) { float bottom = imageRect.bottom; float top = Edge.TOP.getCoordinate() - offset; float left = Edge.LEFT.getCoordinate(); float right = AspectRatioUtil.calculateRight(left, top, bottom, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } break; case BOTTOM: if (edge.equals(Edge.LEFT)) { float left = imageRect.left; float right = Edge.RIGHT.getCoordinate() - offset; float top = Edge.TOP.getCoordinate(); float bottom = AspectRatioUtil.calculateBottom(left, top, right, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } else if (edge.equals(Edge.RIGHT)) { float right = imageRect.right; float left = Edge.LEFT.getCoordinate() - offset; float top = Edge.TOP.getCoordinate(); float bottom = AspectRatioUtil.calculateBottom(left, top, right, aspectRatio); return isOutOfBounds(top, left, bottom, right, imageRect); } break; } return true; } /** * Returns whether the new rectangle would be out of bounds. * * @param top * @param left * @param bottom * @param right * @param imageRect the Image to be compared with. * @return whether it would be out of bounds */ private boolean isOutOfBounds(float top, float left, float bottom, float right, Rect imageRect) { return (top < imageRect.top || left < imageRect.left || bottom > imageRect.bottom || right > imageRect.right); } /** * Snap this Edge to the given image boundaries. * * @param imageRect the bounding rectangle of the image to snap to * @return the amount (in pixels) that this coordinate was changed (i.e. the * new coordinate minus the old coordinate value) */ public float snapToRect(Rect imageRect) { final float oldCoordinate = mCoordinate; switch (this) { case LEFT: mCoordinate = imageRect.left; break; case TOP: mCoordinate = imageRect.top; break; case RIGHT: mCoordinate = imageRect.right; break; case BOTTOM: mCoordinate = imageRect.bottom; break; } final float offset = mCoordinate - oldCoordinate; return offset; } /** * Returns the potential snap offset of snaptoRect, without changing the coordinate. * * @param imageRect the bounding rectangle of the image to snap to * @return the amount (in pixels) that this coordinate was changed (i.e. the * new coordinate minus the old coordinate value) */ public float snapOffset(Rect imageRect) { final float oldCoordinate = mCoordinate; float newCoordinate = oldCoordinate; switch (this) { case LEFT: newCoordinate = imageRect.left; break; case TOP: newCoordinate = imageRect.top; break; case RIGHT: newCoordinate = imageRect.right; break; case BOTTOM: newCoordinate = imageRect.bottom; break; } final float offset = newCoordinate - oldCoordinate; return offset; } /** * Snap this Edge to the given View boundaries. * * @param view the View to snap to */ public void snapToView(View view) { switch (this) { case LEFT: mCoordinate = 0; break; case TOP: mCoordinate = 0; break; case RIGHT: mCoordinate = view.getWidth(); break; case BOTTOM: mCoordinate = view.getHeight(); break; } } /** * Gets the current width of the crop window. */ public static float getWidth() { return Edge.RIGHT.getCoordinate() - Edge.LEFT.getCoordinate(); } /** * Gets the current height of the crop window. */ public static float getHeight() { return Edge.BOTTOM.getCoordinate() - Edge.TOP.getCoordinate(); } /** * Determines if this Edge is outside the inner margins of the given bounding * rectangle. The margins come inside the actual frame by SNAPRADIUS amount; * therefore, determines if the point is outside the inner "margin" frame. */ public boolean isOutsideMargin(Rect rect, float margin) { boolean result = false; switch (this) { case LEFT: result = mCoordinate - rect.left < margin; break; case TOP: result = mCoordinate - rect.top < margin; break; case RIGHT: result = rect.right - mCoordinate < margin; break; case BOTTOM: result = rect.bottom - mCoordinate < margin; break; } return result; } /** * Determines if this Edge is outside the image frame of the given bounding * rectangle. */ public boolean isOutsideFrame(Rect rect) { double margin = 0; boolean result = false; switch (this) { case LEFT: result = mCoordinate - rect.left < margin; break; case TOP: result = mCoordinate - rect.top < margin; break; case RIGHT: result = rect.right - mCoordinate < margin; break; case BOTTOM: result = rect.bottom - mCoordinate < margin; break; } return result; } // Private Methods ///////////////////////////////////////////////////////// /** * Get the resulting x-position of the left edge of the crop window given * the handle's position and the image's bounding box and snap radius. * * @param x the x-position that the left edge is dragged to * @param imageRect the bounding box of the image that is being cropped * @param imageSnapRadius the snap distance to the image edge (in pixels) * @return the actual x-position of the left edge */ private static float adjustLeft(float x, Rect imageRect, float imageSnapRadius, float aspectRatio) { float resultX = x; if (x - imageRect.left < imageSnapRadius) resultX = imageRect.left; else { // Select the minimum of the three possible values to use float resultXHoriz = Float.POSITIVE_INFINITY; float resultXVert = Float.POSITIVE_INFINITY; // Checks if the window is too small horizontally if (x >= Edge.RIGHT.getCoordinate() - MIN_CROP_LENGTH_PX) resultXHoriz = Edge.RIGHT.getCoordinate() - MIN_CROP_LENGTH_PX; // Checks if the window is too small vertically if (((Edge.RIGHT.getCoordinate() - x) / aspectRatio) <= MIN_CROP_LENGTH_PX) resultXVert = Edge.RIGHT.getCoordinate() - (MIN_CROP_LENGTH_PX * aspectRatio); resultX = Math.min(resultX, Math.min(resultXHoriz, resultXVert)); } return resultX; } /** * Get the resulting x-position of the right edge of the crop window given * the handle's position and the image's bounding box and snap radius. * * @param x the x-position that the right edge is dragged to * @param imageRect the bounding box of the image that is being cropped * @param imageSnapRadius the snap distance to the image edge (in pixels) * @return the actual x-position of the right edge */ private static float adjustRight(float x, Rect imageRect, float imageSnapRadius, float aspectRatio) { float resultX = x; // If close to the edge if (imageRect.right - x < imageSnapRadius) resultX = imageRect.right; else { // Select the maximum of the three possible values to use float resultXHoriz = Float.NEGATIVE_INFINITY; float resultXVert = Float.NEGATIVE_INFINITY; // Checks if the window is too small horizontally if (x <= Edge.LEFT.getCoordinate() + MIN_CROP_LENGTH_PX) resultXHoriz = Edge.LEFT.getCoordinate() + MIN_CROP_LENGTH_PX; // Checks if the window is too small vertically if (((x - Edge.LEFT.getCoordinate()) / aspectRatio) <= MIN_CROP_LENGTH_PX) { resultXVert = Edge.LEFT.getCoordinate() + (MIN_CROP_LENGTH_PX * aspectRatio); } resultX = Math.max(resultX, Math.max(resultXHoriz, resultXVert)); } return resultX; } /** * Get the resulting y-position of the top edge of the crop window given the * handle's position and the image's bounding box and snap radius. * * @param y the x-position that the top edge is dragged to * @param imageRect the bounding box of the image that is being cropped * @param imageSnapRadius the snap distance to the image edge (in pixels) * @return the actual y-position of the top edge */ private static float adjustTop(float y, Rect imageRect, float imageSnapRadius, float aspectRatio) { float resultY = y; if (y - imageRect.top < imageSnapRadius) resultY = imageRect.top; else { // Select the minimum of the three possible values to use float resultYVert = Float.POSITIVE_INFINITY; float resultYHoriz = Float.POSITIVE_INFINITY; // Checks if the window is too small vertically if (y >= Edge.BOTTOM.getCoordinate() - MIN_CROP_LENGTH_PX) resultYHoriz = Edge.BOTTOM.getCoordinate() - MIN_CROP_LENGTH_PX; // Checks if the window is too small horizontally if (((Edge.BOTTOM.getCoordinate() - y) * aspectRatio) <= MIN_CROP_LENGTH_PX) resultYVert = Edge.BOTTOM.getCoordinate() - (MIN_CROP_LENGTH_PX / aspectRatio); resultY = Math.min(resultY, Math.min(resultYHoriz, resultYVert)); } return resultY; } /** * Get the resulting y-position of the bottom edge of the crop window given * the handle's position and the image's bounding box and snap radius. * * @param y the x-position that the bottom edge is dragged to * @param imageRect the bounding box of the image that is being cropped * @param imageSnapRadius the snap distance to the image edge (in pixels) * @return the actual y-position of the bottom edge */ private static float adjustBottom(float y, Rect imageRect, float imageSnapRadius, float aspectRatio) { float resultY = y; if (imageRect.bottom - y < imageSnapRadius) resultY = imageRect.bottom; else { // Select the maximum of the three possible values to use float resultYVert = Float.NEGATIVE_INFINITY; float resultYHoriz = Float.NEGATIVE_INFINITY; // Checks if the window is too small vertically if (y <= Edge.TOP.getCoordinate() + MIN_CROP_LENGTH_PX) resultYVert = Edge.TOP.getCoordinate() + MIN_CROP_LENGTH_PX; // Checks if the window is too small horizontally if (((y - Edge.TOP.getCoordinate()) * aspectRatio) <= MIN_CROP_LENGTH_PX) resultYHoriz = Edge.TOP.getCoordinate() + (MIN_CROP_LENGTH_PX / aspectRatio); resultY = Math.max(resultY, Math.max(resultYHoriz, resultYVert)); } return resultY; } }2)EdgePair.java===================/* * Copyright 2013, Edmodo, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. * You may obtain a copy of the License in the LICENSE file, or 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.eppico.cropwindow.edge; /** * Simple class to hold a pair of Edges. */public class EdgePair { // Member Variables //////////////////////////////////////////////////////// public Edge primary; public Edge secondary; // Constructor ///////////////////////////////////////////////////////////// public EdgePair(Edge edge1, Edge edge2) { primary = edge1; secondary = edge2; } }
No comments:
Post a Comment