Skip to content

Commit

Permalink
#15: Define crop box size or aspect ratio
Browse files Browse the repository at this point in the history
  • Loading branch information
k3b committed Jan 25, 2023
1 parent d86f668 commit 996546b
Show file tree
Hide file tree
Showing 7 changed files with 410 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
/*
Copyright (C) 2019-2023 by k3b
This file is part of de.k3b.android.lossless_jpg_crop (https://github.com/k3b/losslessJpgCrop/)
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>
*/
package de.k3b.android.lossless_jpg_crop;

import android.Manifest;
Expand Down Expand Up @@ -44,14 +62,15 @@
* * Displays the cropping gui
* * Contains Protected helpers for common functionalities
*/
abstract class CropAreasChooseBaseActivity extends BaseActivity {
abstract class CropAreasChooseBaseActivity extends BaseActivity implements DefineAspectRatioFragment.AspectRatioHandler {
protected static final String TAG = "LLCrop";

private static final String STATE_CURRENT_CROP_AREA = "CURRENT_CROP_AREA";
private static final String STATE_CURRENT_ASPECT_RATIO = "KEY_ASPECT_RATIO";

protected static final boolean LOAD_ASYNC = false;
private static final boolean ENABLE_ASPECT_RATIO = false;
private static final boolean ENABLE_ASPECT_RATIO = true;
public static final String ASPECT_RATIO_SQUARE = "8x8";

private static int lastInstanceNo4Debug = 0;
private int instanceNo4Debug = 0;
Expand All @@ -64,7 +83,9 @@ abstract class CropAreasChooseBaseActivity extends BaseActivity {
protected CropImageView uCropView = null;
protected TextView txtStatus = null;
private ImageProcessor mSpectrum;
private String aspectRatio = null;

/** Same as last selected menu item text i.e. 9x13 */
private String currentAspectRatioString = null;

// #7: workaround rotation change while picker is open causes Activity re-create without
// uCropView recreation completed.
Expand Down Expand Up @@ -164,12 +185,10 @@ protected void onGetEditPictureResult(int resultCode, Intent data) {
Toast.makeText(getBaseContext(), R.string.toast_cannot_retrieve_selected_image, Toast.LENGTH_SHORT).show();
finishIfMainMethod(R.id.menu_save);
}
protected void onSaveEditPictureAsOutputUriPickerResult(Uri _outUri) {
protected void onSaveEditPictureAsOutputUriPickerResult(Uri outUri) {

// use to provoke an error to test error handling
// Uri outUri = Uri.parse(_outUri + "-err");

Uri outUri = _outUri;
// Uri outUri = Uri.parse(outUri + "-err");

final Uri inUri = getSourceImageUri(getIntent());

Expand Down Expand Up @@ -200,7 +219,7 @@ protected void onSaveEditPictureAsOutputUriPickerResult(Uri _outUri) {

try {
// #14: delete affected file as it is useless
DocumentsContract.deleteDocument(getContentResolver(), _outUri);
DocumentsContract.deleteDocument(getContentResolver(), outUri);
} catch (Exception exDelete) {
// ignore if useless file cannot be deleted
}
Expand Down Expand Up @@ -293,7 +312,7 @@ protected void onCreate(Bundle savedInstanceState) {
txtStatus = findViewById(R.id.status);

if (savedInstanceState != null) {
aspectRatio = savedInstanceState.getString(STATE_CURRENT_ASPECT_RATIO, aspectRatio);
currentAspectRatioString = savedInstanceState.getString(STATE_CURRENT_ASPECT_RATIO, currentAspectRatioString);
}
mSpectrum = new ImageProcessor();

Expand All @@ -304,10 +323,11 @@ public void onCropOverlayMoved(Rect rect) {
}
});

setAspectRatio(aspectRatio);
setAspectRatio(currentAspectRatioString);
}

private void setAspectRatio(String aspectRatio) {
this.currentAspectRatioString = aspectRatio;
String[] xy = (aspectRatio == null) ? null : aspectRatio.split("x");

if (xy == null) {
Expand All @@ -321,8 +341,8 @@ private void setAspectRatio(String aspectRatio) {
uCropView.setMinCropResultSize(x,y);
uCropView.setMaxCropResultSize(x,y);
} else {
uCropView.setMinCropResultSize(40,99999);
uCropView.setMaxCropResultSize(40,99999);
uCropView.setMinCropResultSize(40,40);
uCropView.setMaxCropResultSize(99999,99999);
}
} catch (Exception ex) {
String message = "setAspectRatio('" + aspectRatio + "') . Valid example '7x13'";
Expand Down Expand Up @@ -465,7 +485,7 @@ protected void onSaveInstanceState(Bundle outState) {
Rect crop = getCropRect();
Log.d(TAG, getInstanceNo4Debug() + "onSaveInstanceState : crop=" + crop);
outState.putParcelable(STATE_CURRENT_CROP_AREA, crop);
outState.putString(STATE_CURRENT_ASPECT_RATIO, aspectRatio);
outState.putString(STATE_CURRENT_ASPECT_RATIO, currentAspectRatioString);

}

Expand Down Expand Up @@ -497,7 +517,7 @@ protected String asString(Uri outUri) {
try {
return URLDecoder.decode(outUri.toString(), StandardCharsets.UTF_8.toString());
} catch (Exception e) {
//!!! UnsupportedEncodingException, IllegalCharsetNameException
// UnsupportedEncodingException, IllegalCharsetNameException
Log.e(TAG, getInstanceNo4Debug() + "err cannot convert imageUri to string('" + outUri.toString() + "').", e);
return outUri.toString();
}
Expand Down Expand Up @@ -688,21 +708,40 @@ public boolean onPrepareOptionsMenu(Menu menu) {
}
}
if (ENABLE_ASPECT_RATIO) {
SubMenu menuCrop = menu.findItem(R.menu.menu_aspect_ratio).getSubMenu();
for (int i = menuCrop.size() - 1; i >= 0; i--) {
MenuItem item = menuCrop.getItem(i);
item.setCheckable(true);
item.setChecked(isCheckedAspectRatio(item));
MenuItem menuAspectRatio = menu.findItem(R.id.menu_aspect_ratio);
if (menuAspectRatio != null) {
SubMenu menuCrop = menuAspectRatio.getSubMenu();
for (int i = menuCrop.size() - 1; i >= 0; i--) {
MenuItem item = menuCrop.getItem(i);
item.setCheckable(true);
item.setChecked(isCurrentAspectRatio(item));
}
}
}
return super.onPrepareOptionsMenu(menu);
}

private boolean isCheckedAspectRatio(MenuItem item) {
// !!! ENABLE_ASPECT_RATIO
return item.getItemId() == Menu.NONE && item.getTitle() != null;
/**
* @return true if Menu.NONE with ratio in title
*/
private boolean isAspectRatio(MenuItem item) {
return item.getItemId() == Menu.NONE
&& item.getTitle() != null;
}

/**
* @return true if item is the current selected ratio
*/
private boolean isCurrentAspectRatio(MenuItem item) {
if (currentAspectRatioString == null) {
return item.getItemId() == R.id.menu_ratio_free;
} else if (currentAspectRatioString.equals(ASPECT_RATIO_SQUARE)) {
return item.getItemId() == R.id.menu_ratio_square;
} else {
return isAspectRatio(item)
&& currentAspectRatioString.equalsIgnoreCase(item.getTitle().toString());
}
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
Expand All @@ -719,8 +758,30 @@ public boolean onOptionsItemSelected(MenuItem item) {
return send.sendPrivateCroppedImage();
} else if (menuItemId == R.id.menu_get_content) {
return content.returnPrivateCroppedImage();
} else if (isAspectRatio(item)) {
// Menu.NONE with ratio in title
setAspectRatio(item.getTitle().toString());
return true;
} else if (menuItemId == R.id.menu_ratio_square) {
setAspectRatio(ASPECT_RATIO_SQUARE);
return true;
} else if (menuItemId == R.id.menu_ratio_free) {
setAspectRatio(null);
return true;
} else if (menuItemId == R.id.menu_ratio_userdefined) {
/* !!! todo
R.id.menu_ratio_free
R.id.menu_ratio_square
R.id.menu_ratio_userdefined
*/
return false;
} else {
return super.onOptionsItemSelected(item);
}
}

public void onDefineAspectRatio(String width, String height) {
setAspectRatio(width + "x" + height);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
Copyright (C) 2022-2023 by k3b
This file is part of de.k3b.android.lossless_jpg_crop (https://github.com/k3b/losslessJpgCrop/)
This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>
*/
package de.k3b.android.lossless_jpg_crop;

import android.app.DialogFragment;
import android.os.Bundle;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

/**
* Define the aspect ratio of the result. (i.e 10x15).
*
* Use the {@link DefineAspectRatioFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class DefineAspectRatioFragment extends DialogFragment {

private static final String PARAM_WIDTH = "paramWidth";
private static final String PARAM_HEIGHT = "paramHeight";

private String mParamWidth;
private String mParamHeight;

private EditText editWidth;
private EditText editHeight;

/** must be implemented by calling activity to receive change in AspectRatio */
public interface AspectRatioHandler {
void onDefineAspectRatio(String width, String height);
}

public DefineAspectRatioFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param paramWidth aspect ratio width
* @param paramHeight aspect ratio height
* @return A new instance of fragment DefineAspectRatioFragment.
*/
public static DefineAspectRatioFragment newInstance(String paramWidth, String paramHeight) {
DefineAspectRatioFragment fragment = new DefineAspectRatioFragment();
Bundle args = new Bundle();
args.putString(PARAM_WIDTH, paramWidth);
args.putString(PARAM_HEIGHT, paramHeight);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParamWidth = getArguments().getString(PARAM_WIDTH);
mParamHeight = getArguments().getString(PARAM_HEIGHT);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_define_aspect_ratio, container, false);
if (getShowsDialog()) {
onCreateViewDialog(view);
}

return view;
}

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveDialog();
outState.putString(PARAM_WIDTH, mParamWidth);
outState.putString(PARAM_HEIGHT, mParamHeight);
}

/** handle init for dialog-only controlls: cmdOk, cmdCancel, status */
private void onCreateViewDialog(View view) {
view.<Button>findViewById(R.id.cmd_ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onOk();
onCancel(getDialog());
}
});
view.<Button>findViewById(R.id.cmd_cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onCancel(getDialog());
}
});
view.<Button>findViewById(R.id.cmd_swap).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveDialog();
String temp = mParamHeight;
mParamHeight = mParamWidth;
mParamWidth = temp;
loadDialog();
}
});

editWidth = view.findViewById(R.id.editWidth);
editHeight = view.findViewById(R.id.editHeight);
loadDialog();
}

private void loadDialog() {
editWidth.setText(this.mParamWidth);
editHeight.setText(this.mParamHeight);
}
private void saveDialog() {
this.mParamWidth = editWidth.getText().toString();
this.mParamHeight = editHeight.getText().toString();
}

private void onOk() {
saveDialog();
((AspectRatioHandler) getActivity()).onDefineAspectRatio(mParamWidth, mParamHeight);
}

}
Loading

0 comments on commit 996546b

Please sign in to comment.