Skip to content
This repository has been archived by the owner on Jan 7, 2023. It is now read-only.

Rotation issue Fix #221

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ sudo: false

android:
components:
- build-tools-23.0.1
- build-tools-23.0.3
- android-23
- extra-android-support
- extra-android-m2repository
Expand Down
6 changes: 4 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
buildscript {
repositories {
mavenCentral()
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.1.0'
classpath 'com.android.tools.build:gradle:3.1.2'
}
}

Expand All @@ -13,5 +14,6 @@ allprojects {

repositories {
mavenCentral()
google()
}
}
9 changes: 4 additions & 5 deletions example/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ apply plugin: 'com.android.application'
archivesBaseName = 'android-crop-example'

android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
compileSdkVersion 27

defaultConfig {
minSdkVersion 10
targetSdkVersion 22
minSdkVersion 14
targetSdkVersion 27
versionCode Integer.parseInt(project.VERSION_CODE)
versionName project.VERSION
}
}

dependencies {
compile project(':lib')
implementation project(':lib')
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.soundcloud.android.crop.example;

import com.soundcloud.android.crop.Crop;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
Expand All @@ -11,6 +9,8 @@
import android.widget.ImageView;
import android.widget.Toast;

import com.soundcloud.android.crop.Crop;

import java.io.File;

public class MainActivity extends Activity {
Expand Down Expand Up @@ -51,7 +51,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result)

private void beginCrop(Uri source) {
Uri destination = Uri.fromFile(new File(getCacheDir(), "cropped"));
Crop.of(source, destination).asSquare().start(this);

Crop.of(source, destination).withMinSize(512, (512 / 16)).start(this);
}

private void handleCrop(int resultCode, Intent result) {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
26 changes: 15 additions & 11 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@ apply plugin: 'signing'
archivesBaseName = 'android-crop'

android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
compileSdkVersion 27

defaultConfig {
minSdkVersion 10
targetSdkVersion 22
minSdkVersion 14
targetSdkVersion 27
versionCode 1
versionName "1.0.1"

testApplicationId 'com.soundcloud.android.crop.test'
testInstrumentationRunner 'android.test.InstrumentationTestRunner'
}
lintOptions {
disable 'Registered', 'IconDensities'
}
}

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'
implementation 'com.android.support:support-annotations:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
androidTestImplementation 'com.squareup:fest-android:1.0.7'
androidTestImplementation 'com.android.support:support-v4:27.1.1'
androidTestImplementation 'org.mockito:mockito-core:1.9.5'
androidTestImplementation 'com.google.dexmaker:dexmaker:1.0'
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.0'
}

2 changes: 1 addition & 1 deletion lib/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<manifest package="com.soundcloud.android.crop" />
<manifest package="com.soundcloud.android.crop" />
37 changes: 37 additions & 0 deletions lib/src/main/java/com/soundcloud/android/crop/Crop.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ public class Crop {
interface Extra {
String ASPECT_X = "aspect_x";
String ASPECT_Y = "aspect_y";

String MIN_ASPECT_X = "min_aspect_x";
String MIN_ASPECT_Y = "min_aspect_y";
String MAX_ASPECT_X = "max_aspect_x";
String MAX_ASPECT_Y = "max_aspect_y";

String MAX_X = "max_x";
String MAX_Y = "max_y";
String MIN_X = "min_x";
String MIN_Y = "min_y";
String AS_PNG = "as_png";
String ERROR = "error";
String LAYOUT_ID = "layout_id";
}

private Intent cropIntent;
Expand All @@ -47,6 +56,11 @@ private Crop(Uri source, Uri destination) {
cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, destination);
}

// public Crop withLayout(int layoutId) {
// cropIntent.putExtra(Extra.LAYOUT_ID, layoutId);
// return this;
// }

/**
* Set fixed aspect ratio for crop area
*
Expand All @@ -59,6 +73,16 @@ public Crop withAspect(int x, int y) {
return this;
}

// public Crop withAspectRange(int minX, int minY, int maxX, int maxY) {
// cropIntent.putExtra(Extra.MIN_ASPECT_X, minX);
// cropIntent.putExtra(Extra.MIN_ASPECT_Y, minY);
// cropIntent.putExtra(Extra.MAX_ASPECT_X, maxX);
// cropIntent.putExtra(Extra.MAX_ASPECT_Y, maxY);
// cropIntent.putExtra(Extra.ASPECT_X, maxX);
// cropIntent.putExtra(Extra.ASPECT_Y, maxY);
// return this;
// }

/**
* Crop area with fixed 1:1 aspect ratio
*/
Expand All @@ -80,8 +104,21 @@ public Crop withMaxSize(int width, int height) {
return this;
}

/**
* Set minimum crop size
*
* @param width Min width
* @param height Min height
*/
public Crop withMinSize(int width, int height) {
cropIntent.putExtra(Extra.MIN_X, width);
cropIntent.putExtra(Extra.MIN_Y, height);
return this;
}

/**
* Set whether to save the result as a PNG or not. Helpful to preserve alpha.
*
* @param asPng whether to save the result as a PNG or not
*/
public Crop asPng(boolean asPng) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import android.view.Window;
import android.view.WindowManager;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand All @@ -52,7 +53,14 @@ public class CropImageActivity extends MonitoredActivity {
private int aspectX;
private int aspectY;

private int minAspectX;
private int minAspectY;
private int maxAspectX;
private int maxAspectY;

// Output image
private int minX;
private int minY;
private int maxX;
private int maxY;
private int exifRotation;
Expand Down Expand Up @@ -91,7 +99,14 @@ private void setupWindowFlags() {
}

private void setupViews() {
setContentView(R.layout.crop__activity_crop);
Intent intent = getIntent();
Bundle extras = intent.getExtras();

int layoutId = R.layout.crop__activity_crop;
if (extras != null) {
layoutId = extras.getInt(Crop.Extra.LAYOUT_ID, R.layout.crop__activity_crop);
}
setContentView(layoutId);

imageView = (CropImageView) findViewById(R.id.crop_image);
imageView.context = this;
Expand Down Expand Up @@ -124,10 +139,19 @@ private void loadInput() {
if (extras != null) {
aspectX = extras.getInt(Crop.Extra.ASPECT_X);
aspectY = extras.getInt(Crop.Extra.ASPECT_Y);

minAspectX = extras.getInt(Crop.Extra.MIN_ASPECT_X);
minAspectY = extras.getInt(Crop.Extra.MIN_ASPECT_Y);
maxAspectX = extras.getInt(Crop.Extra.MAX_ASPECT_X);
maxAspectX = extras.getInt(Crop.Extra.MAX_ASPECT_Y);

maxX = extras.getInt(Crop.Extra.MAX_X);
maxY = extras.getInt(Crop.Extra.MAX_Y);
saveAsPng = extras.getBoolean(Crop.Extra.AS_PNG, false);
saveUri = extras.getParcelable(MediaStore.EXTRA_OUTPUT);

minX = extras.getInt(Crop.Extra.MIN_X, 0);
minY = extras.getInt(Crop.Extra.MIN_Y, 0);
}

sourceUri = intent.getData();
Expand All @@ -141,6 +165,19 @@ private void loadInput() {
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = sampleSize;
rotateBitmap = new RotateBitmap(BitmapFactory.decodeStream(is, null, option), exifRotation);

option.inJustDecodeBounds = true;
BitmapFactory.decodeFile(new File(sourceUri.getPath()).getAbsolutePath(), option);
int imageHeight = option.outHeight;
int imageWidth = option.outWidth;

if (minX > imageHeight || minY > imageWidth) {
Intent intentError = new Intent();
intentError.putExtra(Crop.Extra.ERROR, new Throwable("Image is less then minimum size specified.\nRequired size:" + minX + "x" + minY));
setResult(Crop.RESULT_ERROR, intentError);
finish();
}

} catch (IOException e) {
Log.e("Error reading image: " + e.getMessage(), e);
setResultException(e);
Expand Down Expand Up @@ -246,7 +283,10 @@ private void makeDefault() {
int y = (height - cropHeight) / 2;

RectF cropRect = new RectF(x, y, x + cropWidth, y + cropHeight);
hv.setup(imageView.getUnrotatedMatrix(), imageRect, cropRect, aspectX != 0 && aspectY != 0);

boolean maintainAspectRatio = !(minAspectX != 0 && minAspectY != 0 && maxAspectX != 0 && maxAspectY != 0) && (aspectX != 0 && aspectY != 0);

hv.setup(imageView.getUnrotatedMatrix(), imageRect, cropRect, maintainAspectRatio, minX, minY);
imageView.add(hv);
}

Expand Down Expand Up @@ -290,14 +330,20 @@ private void onSaveClicked() {

try {
croppedImage = decodeRegionCrop(r, outWidth, outHeight);

if (exifRotation != 0) {
Matrix m = new Matrix();
m.postRotate(exifRotation);
croppedImage = Bitmap.createBitmap(croppedImage, 0, 0, croppedImage.getWidth(), croppedImage.getHeight(), m, true);
}
} catch (IllegalArgumentException e) {
setResultException(e);
finish();
return;
}

if (croppedImage != null) {
imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true);
// imageView.setImageRotateBitmapResetBase(new RotateBitmap(croppedImage, exifRotation), true);
imageView.center();
imageView.highlightViews.clear();
}
Expand Down Expand Up @@ -394,11 +440,6 @@ private void saveOutput(Bitmap croppedImage) {
CropUtil.closeSilently(outputStream);
}

CropUtil.copyExifRotation(
CropUtil.getFromMediaUri(this, getContentResolver(), sourceUri),
CropUtil.getFromMediaUri(this, getContentResolver(), saveUri)
);

setResultUri(saveUri);
}

Expand Down
24 changes: 20 additions & 4 deletions lib/src/main/java/com/soundcloud/android/crop/HighlightView.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ enum HandleMode { Changing, Always, Never }
private float outlineWidth;
private boolean isFocused;

private float minWidth = 0f;
private float minHeight = 0f;

public HighlightView(View context) {
viewContext = context;
initStyles(context.getContext());
Expand All @@ -97,6 +100,13 @@ private void initStyles(Context context) {
}
}

public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean maintainAspectRatio, int minWidth, int minHeight)
{
this.minWidth = minWidth;
this.minHeight = minHeight;
setup(m, imageRect, cropRect, maintainAspectRatio);
}

public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean maintainAspectRatio) {
matrix = new Matrix(m);

Expand Down Expand Up @@ -209,10 +219,8 @@ private void drawThirds(Canvas canvas) {
drawRect.left + xThird, drawRect.bottom, outlinePaint);
canvas.drawLine(drawRect.left + xThird * 2, drawRect.top,
drawRect.left + xThird * 2, drawRect.bottom, outlinePaint);
canvas.drawLine(drawRect.left, drawRect.top + yThird,
drawRect.right, drawRect.top + yThird, outlinePaint);
canvas.drawLine(drawRect.left, drawRect.top + yThird * 2,
drawRect.right, drawRect.top + yThird * 2, outlinePaint);
canvas.drawLine(drawRect.left, drawRect.top + yThird, drawRect.right, drawRect.top + yThird, outlinePaint);
canvas.drawLine(drawRect.left, drawRect.top + yThird * 2, drawRect.right, drawRect.top + yThird * 2, outlinePaint);
}

private void drawCircle(Canvas canvas) {
Expand Down Expand Up @@ -348,6 +356,14 @@ void growBy(float dx, float dy) {
r.inset(0F, -(heightCap - r.height()) / 2F);
}

// Limits the size of the image to the given minimum amount
if (minWidth > 0f || minHeight > 0f)
{
float widthDiff = (Math.abs((r.right-r.left)) < minWidth) ? minWidth - Math.abs((r.right-r.left)) : 0f;
float heightDiff = (Math.abs((r.bottom-r.top)) < minHeight) ? minHeight - Math.abs((r.bottom-r.top)) : 0f;
r.inset((widthDiff/2)*-1, (heightDiff / 2) * -1);
}

// Put the cropping rectangle inside the image rectangle
if (r.left < imageRect.left) {
r.offset(imageRect.left - r.left, 0F);
Expand Down
Binary file added lib/src/main/res/drawable-hdpi/crop__tile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed lib/src/main/res/drawable-mdpi/crop__divider.9.png
Binary file not shown.
Binary file added lib/src/main/res/drawable-mdpi/crop__tile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas.android.com/apk/res/android"
android:exitFadeDuration="@android:integer/config_mediumAnimTime">
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_pressed="true">
<shape>
Expand Down
Loading