*API CLASS
==========
package com.eppico.api; import com.eppico.models.AddPostModel; import com.eppico.models.AppUserModel; import com.eppico.models.CategoryModel; import com.eppico.models.CheckInUserModel; import com.eppico.models.CheckedInSpotModel; import com.eppico.models.CommentListModel; import com.eppico.models.EditProfileModel; import com.eppico.models.DeletePostModel; import com.eppico.models.EditSpotModel; import com.eppico.models.FollowSpotModel; import com.eppico.models.FollowUserModel; import com.eppico.models.FollowersListModel; import com.eppico.models.FollowingListModel; import com.eppico.models.InviteFriendModel; import com.eppico.models.CreateSpotModel; import com.eppico.models.InviteSpotDetailModel; import com.eppico.models.InviteSpotListModel; import com.eppico.models.LeadershipBoardModel; import com.eppico.models.LikeModel; import com.eppico.models.LoginModel; import com.eppico.models.LogoutModel; import com.eppico.models.PostDetailModel; import com.eppico.models.ProfileDetailModel; import com.eppico.models.RadiusModel; import com.eppico.models.ReportAbuseModel; import com.eppico.models.SearchSpotModel; import com.eppico.models.SearchUserListModel; import com.eppico.models.SpotModel; import com.eppico.models.UserLeaderShipListModel; import com.eppico.models.deleteCommentModel; import org.json.JSONArray; import java.util.List; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Call; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.Multipart; import retrofit2.http.POST; import retrofit2.http.PUT; import retrofit2.http.Part; import retrofit2.http.Query; public interface EppicoAPI { @Multipart @POST("user/login") Call<LoginModel> loginUser(@Part("facebookId") RequestBody facebookId,@Part("firstName") RequestBody firstName,@Part("lastName") RequestBody lastName,@Part("email") RequestBody email, @Part("curLat") RequestBody curLat,@Part("curLong") RequestBody curLong,@Part("deviceToken") RequestBody deviceToken, @Part("userType") RequestBody userType,@Part("deviceType") RequestBody deviceType, @Part MultipartBody.Part file); @GET("spotradius") Call<List<RadiusModel>> getSpotRadius(); @GET("spot") Call<List<SpotModel>> getSpotList(); @FormUrlEncoded @PUT("spotradius/1") Call<RadiusModel> updateRadius(@Field("desc") String desc); @GET("category") Call<List<CategoryModel>> getCategory(); /*@Multipart @POST("spot") Call<LoginModel> createSpot(@Part("catId") RequestBody catId,@Part("userId") RequestBody userId, @Part("radiusId") RequestBody radiusId,@Part("spotName") RequestBody spotName, @Part("spotDetailDesc") RequestBody spotDetailDesc, @Part("spotLocation") RequestBody spotLocation, @Part("spotLatLong") RequestBody spotLatLong, @Part MultipartBody.Part file);*/ @GET("user") Call<AppUserModel> getAppUserList(@Query("page") int page,@Query("userId") int userId,@Query("spotId") int spotId); @FormUrlEncoded @POST("user/user-search") Call<AppUserModel> searchAppUser(@Field("search") String search,@Field("page") String page,@Field("spotId") int spotId); @FormUrlEncoded @POST("spotinvitation") // Call<List<InviteFriendModel>> inviteFriends(@Field("userId") String usersJsonArray); Call<List<InviteFriendModel>> inviteFriends(@Field("spotId") String spotId,/*@Field("userId") String userId,*/@Field("invitationType") String invitationType, @Field("spInviteType") String spInviteType,@Field("intivite") String intiviteJsonArray); @Multipart @POST("spot") Call<CreateSpotModel> createSpot(@Part("catId") RequestBody catId, /*@Part("userId") RequestBody userId,*/ @Part("radiusId") RequestBody radiusId, @Part("spotName") RequestBody spotName, @Part("spotDetailDesc") RequestBody spotDetailDesc, @Part("spotLocation") RequestBody spotLocation, @Part("spotLatLong") RequestBody spotLatLong, @Part MultipartBody.Part file); @FormUrlEncoded @POST("spotinvitation/spot-invite-list") Call<InviteSpotListModel> inviteSpotList(/*@Field("userId") String userId,*/@Field("search") String search, @Field("page") String page); @FormUrlEncoded @POST("spot/my-spot-list") Call<InviteSpotListModel> mySpotList(/*@Field("userId") String userId,*/ @Field("search") String search, @Field("page") String page); @FormUrlEncoded @POST("spot/spot-edit") // Call<EditSpotModel> editSpot(@Field("spotId") String spotId, @Field(value = "spotName", encoded = true) String spotName, @Field("spotDetailDesc") String spotDetailDesc, @Field("isActive") String isActive); Call<EditSpotModel> editSpot(@Field("spotId") String spotId, @Field("spotName") String spotName, @Field("spotDetailDesc") String spotDetailDesc, @Field("isActive") String isActive); @FormUrlEncoded @POST("spot/spot-details") Call<InviteSpotDetailModel> inviteSpotDetail(/*@Field("userId") String userId,*/@Field("spotId") String spotId,@Field("page") String page); @FormUrlEncoded @POST("checkin/checkin-user-list") Call<CheckInUserModel> checkInUserList(@Field("spotId") String spotId, @Field("page") String page,@Field("search") String search); @FormUrlEncoded @POST("spot-followers/spot-followers-list") Call<FollowersListModel> getSpotFollowersList(/*@Field("userId") String userId,*/@Field("spotId") String spotId, @Field("page") String page, @Field("search") String search); @FormUrlEncoded @POST("user-followers/user-followers-list") Call<FollowersListModel> getUserFollowersList(@Field("userId") String userId,@Field("page") String page, @Field("search") String search, @Field("type") String type); @Multipart @POST("post") Call<AddPostModel> addPost(@Part("spotId") RequestBody spotId, /*@Part("userId") RequestBody userId,*/ @Part("postDesc") RequestBody postDesc, @Part("mediaType") RequestBody mediaType, @Part MultipartBody.Part file); @FormUrlEncoded @POST("spot/spot-check-in") Call<CheckedInSpotModel> checkedInSpot(@Field("spotId") String spotId, /*@Field("userId") String userId,*/ @Field("currentLat") String currentLat, @Field("currentLong") String currentLong); //@FormUrlEncoded @POST("user/logout") Call<LogoutModel> logout(/*@Field("userId") String userId*/); @FormUrlEncoded @POST("post/post-details") Call<PostDetailModel> postDetail(@Field("postId") String postId, @Field("page") String page); @FormUrlEncoded @POST("post/post-delete") Call<DeletePostModel> deletePost(/*@Field("userId") int userId,*/ @Field("spotId") int spotId, @Field("postId") int postId,@Field("mediaId") int mediaId); @FormUrlEncoded @POST("reportabuse") Call<ReportAbuseModel> reportAbuse(@Field("userId") String userId, @Field("spotId") String spotId, @Field("postId") String postId,@Field("mediaid") String mediaid, @Field("desc") String desc); @FormUrlEncoded @POST("user/profile-view") Call<ProfileDetailModel> getProfileDetail(@Field("userId") String userId, @Field("page") String page); @FormUrlEncoded @POST("comment") Call<PostDetailModel.PostComments> writeComment(/*@Field("userId") String userId,*/ @Field("spotId") String spotId, @Field("postId") String postId, @Field("commentDesc") String desc); @Multipart @POST("user/edit-profile") Call<EditProfileModel> editProfile(/*@Part("userId") RequestBody userId,*/ @Part("firstName") RequestBody firstName, @Part("lastName") RequestBody lastName,@Part MultipartBody.Part file); @FormUrlEncoded @POST("comment/comment-list") Call<CommentListModel> commentList(@Field("postId") String postId, @Field("page") String page); @FormUrlEncoded @POST("spot-followers") Call<FollowSpotModel> followSpot(@Field("spotId") String spotId, /*@Field("userId") String userId,*/@Field("spotFollowerId") String spotFollowerId, @Field("spotIsFollowing") String spotIsFollowing); @FormUrlEncoded @POST("spot-followers/follow-unfollow-user") Call<FollowUserModel> followUser(/*@Field("userId") String userId,*/ @Field("userFollowerId") String userFollowerId, @Field("userIsFollowing") String userIsFollowing); @FormUrlEncoded @POST("comment/comment-delete") Call<deleteCommentModel> deleteComment(@Field("postId") String postId, @Field("commentId") String commentId); @FormUrlEncoded @POST("spot-followers/spot-following-list") Call<FollowingListModel> followingSpotList(/*@Field("userId") String userId, */@Field("search") String search, @Field("page") String page); @FormUrlEncoded @POST("post/like-post") Call<LikeModel> likeComment(@Field("spotId") String spotId, @Field("postId") String postId, @Field("mediaID") String mediaID); @FormUrlEncoded @POST("post/leadership-board") Call<List<LeadershipBoardModel>> leadershipBoard(@Field("spotId") String spotId); @POST("post/view-leadership-board") Call<List<UserLeaderShipListModel>> userLeadershipBoard(); @FormUrlEncoded @POST("spot/spot-search") Call<SearchSpotModel> searchSpot(@Field("search") String search,@Field("page") int page); @FormUrlEncoded @POST("user/user-global-search") Call<SearchUserListModel> searchUser(@Field("search") String search, @Field("page") int page); }
=============================================================================* cropwindow
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.credencys.myapplication.cropwindow; import android.graphics.Rect; /** * Utility class for handling calculations involving a fixed aspect ratio. */@SuppressWarnings({"ALL", "UnnecessaryLocalVariable"}) 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)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.credencys.myapplication.cropwindow; import android.content.Context; import android.util.Pair; import android.util.TypedValue; import com.credencys.myapplication.cropwindow.handle.Handle; import com.credencys.myapplication.widgets.CropImageView; import com.credencys.myapplication.widgets.CropOverlayView; /** * Utility class to perform basic operations with Handles. */@SuppressWarnings("ALL") public class HandleUtil { // 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<>(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) { //noinspection RedundantIfStatement,RedundantIfStatement,RedundantIfStatement,RedundantIfStatement 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 */ @SuppressWarnings("RedundantIfStatement") private static boolean isInVerticalTargetZone(float x, float y, float handleX, float handleYStart, float handleYEnd, float targetRadius) { //noinspection RedundantIfStatement 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 */ @SuppressWarnings("RedundantIfStatement") private static boolean isInCenterTargetZone(float x, float y, float left, float top, float right, float bottom) { //noinspection RedundantIfStatement 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()); } }3)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.credencys.myapplication.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. */@SuppressWarnings("ALL") 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 { resultX = (int) Math.round((viewWidth - resultWidth) / 2); resultY = 0; } 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}4)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.credencys.myapplication.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; } }
*cropwindow=>edge=>
1)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.credencys.myapplication.cropwindow.edge; import android.graphics.Rect; import android.view.View; import com.credencys.myapplication.cropwindow.AspectRatioUtil; /** * Enum representing an edge in the crop window. */@SuppressWarnings("ALL") public enum Edge { LEFT, TOP, RIGHT, BOTTOM; // 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. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") 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 imageRect the Image to be compared with. * @return whether it would be out of bounds */ @SuppressWarnings("JavaDoc") 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.credencys.myapplication.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; } }*cropwindow=>handle1)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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.cropwindow.edge.Edge; import com.credencys.myapplication.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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.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 final 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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.cropwindow.AspectRatioUtil; import com.credencys.myapplication.cropwindow.edge.Edge; import com.credencys.myapplication.cropwindow.edge.EdgePair; /** * Abstract helper class to handle operations on a crop window Handle. */@SuppressWarnings("ALL") 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 ///////////////////////////////////////////////// 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. * 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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.cropwindow.AspectRatioUtil; import com.credencys.myapplication.cropwindow.edge.Edge; /** * Handle helper class to handle horizontal handles (i.e. top and bottom * handles). */class HorizontalHandleHelper extends HandleHelper { // Member Variables //////////////////////////////////////////////////////// private final 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.credencys.myapplication.cropwindow.handle; import android.graphics.Rect; import com.credencys.myapplication.cropwindow.AspectRatioUtil; import com.credencys.myapplication.cropwindow.edge.Edge; /** * HandleHelper class to handle vertical handles (i.e. left and right handles). */class VerticalHandleHelper extends HandleHelper { // Member Variables //////////////////////////////////////////////////////// private final 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); } } }===========================================================================
No comments:
Post a Comment