Compare commits

..

3 Commits

Author SHA1 Message Date
Ilia Kurtov dc7fbe916c samsung fix 2016-02-25 18:27:15 +03:00
Gavriil Sitnikov 7020bcfe74 tests removed 2016-02-24 15:11:31 +03:00
Gavriil Sitnikov f7ad4594fd specific dbo fixes 2015-12-24 00:52:59 +03:00
25 changed files with 202 additions and 261 deletions

View File

@ -1,30 +1,17 @@
apply plugin: 'com.android.library'
apply plugin: 'maven'
apply plugin: 'signing'
//apply from: '../.publishing/sonatype.gradle'
archivesBaseName = 'android-crop'
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
buildToolsVersion '23.0.2'
defaultConfig {
minSdkVersion 10
targetSdkVersion 22
testApplicationId 'com.soundcloud.android.crop.test'
testInstrumentationRunner 'android.test.InstrumentationTestRunner'
targetSdkVersion 23
}
}
dependencies {
compile 'com.android.support:support-annotations:23.0.1'
compile 'com.android.support:support-v4:23.0.1'
androidTestCompile 'com.squareup:fest-android:1.0.7'
androidTestCompile 'com.android.support:support-v4:23.0.1'
androidTestCompile 'org.mockito:mockito-core:1.9.5'
androidTestCompile 'com.google.dexmaker:dexmaker:1.0'
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.0'
compile 'com.android.support:support-annotations:23.1.1'
compile 'com.android.support:support-v4:23.1.1'
}

View File

@ -1,15 +0,0 @@
package com.soundcloud.android.crop;
import android.test.InstrumentationTestCase;
public class BaseTestCase extends InstrumentationTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
// Work around dexmaker issue when running tests on Android 4.3
System.setProperty("dexmaker.dexcache",
getInstrumentation().getTargetContext().getCacheDir().getPath());
}
}

View File

@ -1,77 +0,0 @@
package com.soundcloud.android.crop;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import org.fest.assertions.api.ANDROID;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.provider.MediaStore;
public class CropBuilderTest extends BaseTestCase {
private Activity activity;
private Crop builder;
@Override
public void setUp() throws Exception {
super.setUp();
activity = mock(Activity.class);
when(activity.getPackageName()).thenReturn("com.example");
builder = Crop.of(Uri.parse("image:input"), Uri.parse("image:output"));
}
public void testInputUriSetAsData() {
ANDROID.assertThat(builder.getIntent(activity)).hasData("image:input");
}
public void testOutputUriSetAsExtra() {
Intent intent = builder.getIntent(activity);
Uri output = intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
assertThat(output.toString()).isEqualTo("image:output");
}
public void testAspectRatioSetAsExtras() {
builder.withAspect(16, 10);
Intent intent = builder.getIntent(activity);
assertThat(intent.getIntExtra("aspect_x", 0)).isEqualTo(16);
assertThat(intent.getIntExtra("aspect_y", 0)).isEqualTo(10);
}
public void testFixedAspectRatioSetAsExtras() {
builder.asSquare();
Intent intent = builder.getIntent(activity);
assertThat(intent.getIntExtra("aspect_x", 0)).isEqualTo(1);
assertThat(intent.getIntExtra("aspect_y", 0)).isEqualTo(1);
}
public void testMaxSizeSetAsExtras() {
builder.withMaxSize(400, 300);
Intent intent = builder.getIntent(activity);
assertThat(intent.getIntExtra("max_x", 0)).isEqualTo(400);
assertThat(intent.getIntExtra("max_y", 0)).isEqualTo(300);
}
public void testBuildsIntentWithMultipleOptions() {
builder.asSquare().withMaxSize(200, 200);
Intent intent = builder.getIntent(activity);
assertThat(intent.getIntExtra("aspect_x", 0)).isEqualTo(1);
assertThat(intent.getIntExtra("aspect_y", 0)).isEqualTo(1);
assertThat(intent.getIntExtra("max_x", 0)).isEqualTo(200);
assertThat(intent.getIntExtra("max_y", 0)).isEqualTo(200);
}
}

View File

@ -30,6 +30,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Pair;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@ -56,6 +57,7 @@ public class CropImageActivity extends MonitoredActivity {
private int maxX;
private int maxY;
private int exifRotation;
private int exifScale;
private Uri sourceUri;
private Uri saveUri;
@ -63,7 +65,7 @@ public class CropImageActivity extends MonitoredActivity {
private boolean isSaving;
private int sampleSize;
private RotateBitmap rotateBitmap;
private Bitmap srcBitmap;
private CropImageView imageView;
private HighlightView cropView;
@ -74,7 +76,7 @@ public class CropImageActivity extends MonitoredActivity {
setupViews();
loadInput();
if (rotateBitmap == null) {
if (srcBitmap == null) {
finish();
return;
}
@ -119,6 +121,7 @@ public class CropImageActivity extends MonitoredActivity {
private void loadInput() {
Intent intent = getIntent();
Bundle extras = intent.getExtras();
Bitmap initialBitmap ;
if (extras != null) {
aspectX = extras.getInt(Crop.Extra.ASPECT_X);
@ -130,15 +133,32 @@ public class CropImageActivity extends MonitoredActivity {
sourceUri = intent.getData();
if (sourceUri != null) {
exifRotation = CropUtil.getExifRotation(CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri));
Pair<Integer,Integer> exifRotationTrans =
CropUtil.getExifRotationTranslation(
CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri));
exifRotation = exifRotationTrans.first;
exifScale = exifRotationTrans.second;
InputStream is = null;
try {
sampleSize = calculateBitmapSampleSize(sourceUri);
is = getContentResolver().openInputStream(sourceUri);
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = sampleSize;
rotateBitmap = new RotateBitmap(BitmapFactory.decodeStream(is, null, option), exifRotation);
initialBitmap = BitmapFactory.decodeStream(is, null, option);
int drawHeight = initialBitmap.getHeight();
int drawWidth = initialBitmap.getWidth();
if ((exifRotation != 0) || (exifScale != 1)) {
Matrix matrix = new Matrix() ;
if (exifRotation != 0) {
matrix.preRotate(exifRotation);
}
if (exifScale != 1) {
matrix.postScale(exifScale, 1);
}
srcBitmap = Bitmap.createBitmap(initialBitmap, 0, 0, drawWidth, drawHeight, matrix, true);
} else {
srcBitmap = initialBitmap ;
}
} catch (IOException e) {
Log.e("Error reading image: " + e.getMessage(), e);
setResultException(e);
@ -149,6 +169,9 @@ public class CropImageActivity extends MonitoredActivity {
CropUtil.closeSilently(is);
}
}
else {
Log.e("Source URI is null");
}
}
private int calculateBitmapSampleSize(Uri bitmapUri) throws IOException {
@ -190,7 +213,7 @@ public class CropImageActivity extends MonitoredActivity {
if (isFinishing()) {
return;
}
imageView.setImageRotateBitmapResetBase(rotateBitmap, true);
imageView.setImageBitmapResetBase(srcBitmap, true);
CropUtil.startBackgroundJob(this, null, getResources().getString(R.string.crop__wait),
new Runnable() {
public void run() {
@ -217,13 +240,13 @@ public class CropImageActivity extends MonitoredActivity {
private class Cropper {
private void makeDefault() {
if (rotateBitmap == null) {
if (srcBitmap == null) {
return;
}
HighlightView hv = new HighlightView(imageView);
final int width = rotateBitmap.getWidth();
final int height = rotateBitmap.getHeight();
final int width = srcBitmap.getWidth();
final int height = srcBitmap.getHeight();
Rect imageRect = new Rect(0, 0, width, height);
@ -275,6 +298,8 @@ public class CropImageActivity extends MonitoredActivity {
int outWidth = width;
int outHeight = height;
Log.e("Crop Width = " + width);
Log.e("Crop Height = " + height);
if (maxX > 0 && maxY > 0 && (width > maxX || height > maxY)) {
float ratio = (float) width / (float) height;
if ((float) maxX / (float) maxY > ratio) {
@ -295,7 +320,7 @@ public class CropImageActivity extends MonitoredActivity {
}
if (croppedImage != null) {
imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true);
imageView.setImageBitmapResetBase(croppedImage, true);
imageView.center();
imageView.highlightViews.clear();
}
@ -318,22 +343,20 @@ public class CropImageActivity extends MonitoredActivity {
}
private Bitmap decodeRegionCrop(Rect rect, int outWidth, int outHeight) {
// Release memory now
clearImageView();
Matrix matrix = new Matrix();
InputStream is = null;
Bitmap croppedImage = null;
boolean transformed = false ;
try {
is = getContentResolver().openInputStream(sourceUri);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
final int width = decoder.getWidth();
final int height = decoder.getHeight();
if (exifRotation != 0) {
// Adjust crop area to account for image rotation
Matrix matrix = new Matrix();
matrix.setRotate(-exifRotation);
if ((exifRotation != 0) || (exifScale != 1)) {
// Adjust crop area to account for EXIF transformation so what you crop is what you get
matrix.preRotate(-exifRotation);
matrix.postScale(exifScale, 1);
RectF adjusted = new RectF();
matrix.mapRect(adjusted, new RectF(rect));
@ -343,10 +366,19 @@ public class CropImageActivity extends MonitoredActivity {
}
try {
matrix.reset();
croppedImage = decoder.decodeRegion(rect, new BitmapFactory.Options());
if (croppedImage != null && (rect.width() > outWidth || rect.height() > outHeight)) {
Matrix matrix = new Matrix();
matrix.postScale((float) outWidth / rect.width(), (float) outHeight / rect.height());
if ((exifRotation != 0) || (exifScale != 1)) {
transformed = true;
// Remove the EXIF transformation from the cropped image so we can dispense with it altogether
matrix.preRotate(exifRotation);
matrix.postScale(exifScale, 1);
}
if (rect.width() > outWidth || rect.height() > outHeight) {
transformed = true ;
matrix.postScale(((float)outWidth)/((float)rect.width()), ((float)outHeight)/((float)rect.height()));
}
if (transformed) {
croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), matrix, true);
}
} catch (IllegalArgumentException e) {
@ -363,14 +395,16 @@ public class CropImageActivity extends MonitoredActivity {
setResultException(e);
} finally {
CropUtil.closeSilently(is);
// Release memory now
clearImageView();
}
return croppedImage;
}
private void clearImageView() {
imageView.clear();
if (rotateBitmap != null) {
rotateBitmap.recycle();
if (srcBitmap != null) {
srcBitmap.recycle();
}
System.gc();
}
@ -389,12 +423,6 @@ public class CropImageActivity extends MonitoredActivity {
} finally {
CropUtil.closeSilently(outputStream);
}
CropUtil.copyExifRotation(
CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri),
CropUtil.getFromMediaUri(this, getContentResolver(), saveUri)
);
setResultUri(saveUri);
}
@ -412,8 +440,8 @@ public class CropImageActivity extends MonitoredActivity {
@Override
protected void onDestroy() {
super.onDestroy();
if (rotateBitmap != null) {
rotateBitmap.recycle();
if (srcBitmap != null) {
srcBitmap.recycle();
}
}

View File

@ -27,6 +27,7 @@ import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Pair;
import java.io.Closeable;
import java.io.File;
@ -52,25 +53,43 @@ class CropUtil {
}
}
public static int getExifRotation(File imageFile) {
if (imageFile == null) return 0;
public static Pair<Integer,Integer> getExifRotationTranslation(File imageFile) {
int exifRotation = 0, exifScale = 1;
if (imageFile == null) return new Pair<Integer,Integer>(0,1);
try {
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
// We only recognize a subset of orientation tag values
switch (exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
default:
return ExifInterface.ORIENTATION_UNDEFINED;
case ExifInterface.ORIENTATION_UNDEFINED:
case ExifInterface.ORIENTATION_NORMAL:
break ;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
exifScale=-1;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
exifRotation = 180;
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
exifRotation = 180;
exifScale=-1;
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
exifRotation = 90;
exifScale=-1;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
exifRotation = 90;
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
exifRotation = 270;
exifScale=-1;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
exifRotation = 270;
}
} catch (IOException e) {
Log.e("Error getting Exif data", e);
return 0;
}
return new Pair<Integer,Integer>(exifRotation,exifScale);
}
public static boolean copyExifRotation(File sourceFile, File destFile) {

View File

@ -24,6 +24,8 @@ import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
@ -41,19 +43,20 @@ import android.view.View;
*/
class HighlightView {
public static final int GROW_NONE = (1 << 0);
public static final int GROW_LEFT_EDGE = (1 << 1);
public static final int GROW_RIGHT_EDGE = (1 << 2);
public static final int GROW_TOP_EDGE = (1 << 3);
public static final int GROW_NONE = (1 << 0);
public static final int GROW_LEFT_EDGE = (1 << 1);
public static final int GROW_RIGHT_EDGE = (1 << 2);
public static final int GROW_TOP_EDGE = (1 << 3);
public static final int GROW_BOTTOM_EDGE = (1 << 4);
public static final int MOVE = (1 << 5);
public static final int MOVE = (1 << 5);
private static final int DEFAULT_HIGHLIGHT_COLOR = 0xFF33B5E5;
private static final float HANDLE_RADIUS_DP = 12f;
private static final float OUTLINE_DP = 2f;
private static final int DEFAULT_HIGHLIGHT_COLOR = 0xFF00985F;
private static final float HANDLE_RADIUS_DP = 8f;
private static final float OUTLINE_DP = 1f;
enum ModifyMode { None, Move, Grow }
enum HandleMode { Changing, Always, Never }
enum ModifyMode {None, Move, Grow}
enum HandleMode {Changing, Always, Never}
RectF cropRect; // Image space
Rect drawRect; // Screen space
@ -69,6 +72,7 @@ class HighlightView {
private boolean showCircle;
private int highlightColor;
private ModifyMode modifyMode = ModifyMode.None;
private HandleMode handleMode = HandleMode.Changing;
private boolean maintainAspectRatio;
@ -76,6 +80,7 @@ class HighlightView {
private float handleRadius;
private float outlineWidth;
private boolean isFocused;
private float hysteresis;
public HighlightView(View context) {
viewContext = context;
@ -85,10 +90,11 @@ class HighlightView {
private void initStyles(Context context) {
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(R.attr.cropImageStyle, outValue, true);
hysteresis = dpToPx(16);
TypedArray attributes = context.obtainStyledAttributes(outValue.resourceId, R.styleable.CropImageView);
try {
showThirds = attributes.getBoolean(R.styleable.CropImageView_showThirds, false);
showCircle = attributes.getBoolean(R.styleable.CropImageView_showCircle, false);
showCircle = attributes.getBoolean(R.styleable.CropImageView_showCircle, true);
highlightColor = attributes.getColor(R.styleable.CropImageView_highlightColor,
DEFAULT_HIGHLIGHT_COLOR);
handleMode = HandleMode.values()[attributes.getInt(R.styleable.CropImageView_showHandles, 0)];
@ -107,7 +113,7 @@ class HighlightView {
initialAspectRatio = this.cropRect.width() / this.cropRect.height();
drawRect = computeLayout();
outsidePaint.setARGB(125, 50, 50, 50);
outsidePaint.setARGB(153, 0, 0, 0);
outlinePaint.setStyle(Paint.Style.STROKE);
outlinePaint.setAntiAlias(true);
outlineWidth = dpToPx(OUTLINE_DP);
@ -135,7 +141,11 @@ class HighlightView {
Rect viewDrawingRect = new Rect();
viewContext.getDrawingRect(viewDrawingRect);
path.addRect(new RectF(drawRect), Path.Direction.CW);
if (showCircle) {
path.addOval(new RectF(drawRect), Path.Direction.CW);
} else {
path.addRect(new RectF(drawRect), Path.Direction.CW);
}
outlinePaint.setColor(highlightColor);
if (isClipPathSupported(canvas)) {
@ -152,10 +162,6 @@ class HighlightView {
drawThirds(canvas);
}
if (showCircle) {
drawCircle(canvas);
}
if (handleMode == HandleMode.Always ||
(handleMode == HandleMode.Changing && modifyMode == ModifyMode.Grow)) {
drawHandles(canvas);
@ -167,10 +173,20 @@ class HighlightView {
* Fall back to naive method for darkening outside crop area
*/
private void drawOutsideFallback(Canvas canvas) {
canvas.drawRect(0, 0, canvas.getWidth(), drawRect.top, outsidePaint);
canvas.drawRect(0, drawRect.bottom, canvas.getWidth(), canvas.getHeight(), outsidePaint);
canvas.drawRect(0, drawRect.top, drawRect.left, drawRect.bottom, outsidePaint);
canvas.drawRect(drawRect.right, drawRect.top, canvas.getWidth(), drawRect.bottom, outsidePaint);
int layer = canvas.saveLayer(0, 0, canvas.getWidth(), canvas.getHeight(), null,
Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setXfermode(null);
paint.setColor(outsidePaint.getColor());
if (showCircle) {
canvas.drawOval(new RectF(drawRect), paint);
} else {
canvas.drawRect(new RectF(drawRect), paint);
}
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
paint.setColor(outsidePaint.getColor());
canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
canvas.restoreToCount(layer);
}
/*
@ -183,7 +199,7 @@ class HighlightView {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
return false;
} else if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|| Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
|| Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
return true;
} else {
return !canvas.isHardwareAccelerated();
@ -191,7 +207,7 @@ class HighlightView {
}
private void drawHandles(Canvas canvas) {
int xMiddle = drawRect.left + ((drawRect.right - drawRect.left) / 2);
int xMiddle = drawRect.left + ((drawRect.right - drawRect.left) / 2);
int yMiddle = drawRect.top + ((drawRect.bottom - drawRect.top) / 2);
canvas.drawCircle(drawRect.left, yMiddle, handleRadius, handlePaint);
@ -204,7 +220,7 @@ class HighlightView {
outlinePaint.setStrokeWidth(1);
float xThird = (drawRect.right - drawRect.left) / 3;
float yThird = (drawRect.bottom - drawRect.top) / 3;
canvas.drawLine(drawRect.left + xThird, drawRect.top,
drawRect.left + xThird, drawRect.bottom, outlinePaint);
canvas.drawLine(drawRect.left + xThird * 2, drawRect.top,
@ -215,11 +231,6 @@ class HighlightView {
drawRect.right, drawRect.top + yThird * 2, outlinePaint);
}
private void drawCircle(Canvas canvas) {
outlinePaint.setStrokeWidth(1);
canvas.drawOval(new RectF(drawRect), outlinePaint);
}
public void setMode(ModifyMode mode) {
if (mode != modifyMode) {
modifyMode = mode;
@ -229,8 +240,43 @@ class HighlightView {
// Determines which edges are hit by touching at (x, y)
public int getHit(float x, float y) {
if (showCircle) {
return getCircleHit(x, y);
} else {
return getRectangleHit(x, y);
}
}
private int getCircleHit(float x, float y) {
Rect r = computeLayout();
int retval = GROW_NONE;
double radius = r.height() / (double) 2;
double distanceToCenter = Math.sqrt(Math.pow(r.top + radius - y, 2)
+ Math.pow(r.left + radius - x, 2));
if (Math.abs(distanceToCenter - radius) < hysteresis) {
if (y < r.top + radius / 2) {
retval |= GROW_TOP_EDGE;
}
if (y > r.top + radius * 1.5) {
retval |= GROW_BOTTOM_EDGE;
}
if (x < r.left + radius / 2) {
retval |= GROW_LEFT_EDGE;
}
if (x > r.left + radius * 1.5) {
retval |= GROW_RIGHT_EDGE;
}
}
if (retval == GROW_NONE && r.contains((int) x, (int) y)) {
retval = MOVE;
}
return retval;
}
private int getRectangleHit(float x, float y) {
Rect r = computeLayout();
final float hysteresis = 20F;
int retval = GROW_NONE;
// verticalCheck makes sure the position is between the top and
@ -241,16 +287,16 @@ class HighlightView {
&& (x < r.right + hysteresis);
// Check whether the position is near some edge(s)
if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) {
if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) {
retval |= GROW_LEFT_EDGE;
}
if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) {
if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) {
retval |= GROW_RIGHT_EDGE;
}
if ((Math.abs(r.top - y) < hysteresis) && horizCheck) {
if ((Math.abs(r.top - y) < hysteresis) && horizCheck) {
retval |= GROW_TOP_EDGE;
}
if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) {
if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) {
retval |= GROW_BOTTOM_EDGE;
}
@ -268,7 +314,7 @@ class HighlightView {
if (edge == MOVE) {
// Convert to image space before sending to moveBy()
moveBy(dx * (cropRect.width() / r.width()),
dy * (cropRect.height() / r.height()));
dy * (cropRect.height() / r.height()));
} else {
if (((GROW_LEFT_EDGE | GROW_RIGHT_EDGE) & edge) == 0) {
dx = 0;
@ -295,10 +341,10 @@ class HighlightView {
// Put the cropping rectangle inside image rectangle
cropRect.offset(
Math.max(0, imageRect.left - cropRect.left),
Math.max(0, imageRect.top - cropRect.top));
Math.max(0, imageRect.top - cropRect.top));
cropRect.offset(
Math.min(0, imageRect.right - cropRect.right),
Math.min(0, imageRect.right - cropRect.right),
Math.min(0, imageRect.bottom - cropRect.bottom));
drawRect = computeLayout();
@ -374,10 +420,10 @@ class HighlightView {
// Maps the cropping rectangle from image space to screen space
private Rect computeLayout() {
RectF r = new RectF(cropRect.left, cropRect.top,
cropRect.right, cropRect.bottom);
cropRect.right, cropRect.bottom);
matrix.mapRect(r);
return new Rect(Math.round(r.left), Math.round(r.top),
Math.round(r.right), Math.round(r.bottom));
Math.round(r.right), Math.round(r.bottom));
}
public void invalidate() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/crop__selector_pressed">
<item android:drawable="@color/crop__button_bar" />
</ripple>
android:color="@color/crop__selector_pressed"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

View File

@ -9,12 +9,4 @@
</shape>
</item>
<item android:state_focused="true">
<shape>
<solid android:color="@color/crop__selector_focused" />
</shape>
</item>
<item android:drawable="@android:color/transparent" />
</selector>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/crop__tile"
android:tileMode="repeat" />

View File

@ -2,8 +2,10 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@android:color/black">
<include
android:id="@+id/done_cancel_bar"
@ -13,7 +15,6 @@
android:id="@+id/crop_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/crop__texture"
android:layout_below="@id/done_cancel_bar" />
</RelativeLayout>

View File

@ -1,16 +1,18 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Crop.DoneCancelBar">
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#00985f">
<FrameLayout
<ImageView
android:id="@+id/btn_cancel"
style="@style/Crop.ActionButton">
<TextView style="@style/Crop.ActionButtonText.Cancel" />
</FrameLayout>
style="@style/Crop.ActionButton"
android:layout_gravity="left"
android:src="@drawable/crop__ic_cancel"/>
<FrameLayout
<ImageView
android:id="@+id/btn_done"
style="@style/Crop.ActionButton">
<TextView style="@style/Crop.ActionButtonText.Done" />
</FrameLayout>
style="@style/Crop.ActionButton"
android:layout_gravity="right"
android:src="@drawable/crop__ic_done"/>
</LinearLayout>
</FrameLayout>

View File

@ -1,8 +1,5 @@
<resources>
<color name="crop__button_bar">#f3f3f3</color>
<color name="crop__button_text">#666666</color>
<color name="crop__selector_pressed">#1a000000</color>
<color name="crop__selector_focused">#77000000</color>
<color name="crop__selector_pressed">#40FFFFFF</color>
</resources>

View File

@ -1,44 +1,12 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<resources>
<style name="Crop"></style>
<style name="Crop.DoneCancelBar">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">@dimen/crop__bar_height</item>
<item name="android:orientation">horizontal</item>
<item name="android:divider">@drawable/crop__divider</item>
<item name="android:showDividers" tools:ignore="NewApi">middle</item>
<item name="android:dividerPadding" tools:ignore="NewApi">12dp</item>
<item name="android:background">@color/crop__button_bar</item>
</style>
<style name="Crop"/>
<style name="Crop.ActionButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">@dimen/crop__bar_height</item>
<item name="android:layout_height">@dimen/crop__bar_height</item>
<item name="android:background">@drawable/crop__selectable_background</item>
</style>
<style name="Crop.ActionButtonText">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center</item>
<item name="android:gravity">center_vertical</item>
<item name="android:paddingRight">20dp</item> <!-- Offsets left drawable -->
<item name="android:drawablePadding">8dp</item>
<item name="android:textColor">@color/crop__button_text</item>
<item name="android:textStyle">bold</item>
<item name="android:textSize">13sp</item>
</style>
<style name="Crop.ActionButtonText.Done">
<item name="android:drawableLeft">@drawable/crop__ic_done</item>
<item name="android:text">@string/crop__done</item>
</style>
<style name="Crop.ActionButtonText.Cancel">
<item name="android:drawableLeft">@drawable/crop__ic_cancel</item>
<item name="android:text">@string/crop__cancel</item>
<item name="android:scaleType">center</item>
</style>
</resources>