Signal-Android/image-editor/app/src/main/java/org/signal/imageeditor/app/MainActivity.java

276 wiersze
9.5 KiB
Java

package org.signal.imageeditor.app;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import org.signal.imageeditor.app.renderers.UriRenderer;
import org.signal.imageeditor.app.renderers.UrlRenderer;
import org.signal.imageeditor.core.ImageEditorView;
import org.signal.imageeditor.core.UndoRedoStackListener;
import org.signal.imageeditor.core.model.EditorElement;
import org.signal.imageeditor.core.model.EditorModel;
import org.signal.imageeditor.core.renderers.MultiLineTextRenderer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;
public final class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private ImageEditorView imageEditorView;
private Menu menu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(R.string.app_name_short);
setSupportActionBar(toolbar);
imageEditorView = findViewById(R.id.image_editor);
imageEditorView.setUndoRedoStackListener((undoAvailable, redoAvailable) -> {
Log.d("ALAN", String.format("Undo/Redo available: %s, %s", undoAvailable ? "Y" : "N", redoAvailable ? "Y" : "N"));
if (menu == null) return;
MenuItem undo = menu.findItem(R.id.action_undo);
MenuItem redo = menu.findItem(R.id.action_redo);
if (undo != null) undo.setVisible(undoAvailable);
if (redo != null) redo.setVisible(redoAvailable);
});
EditorModel model = null;
if (savedInstanceState != null) {
model = savedInstanceState.getParcelable("MODEL");
Log.d("ALAN", "Restoring instance " + (model != null ? model.hashCode() : 0));
}
if (model == null) {
model = initialModel();
Log.d("ALAN", "New instance created " + model.hashCode());
}
imageEditorView.setModel(model);
imageEditorView.setTapListener(new ImageEditorView.TapListener() {
@Override
public void onEntityDown(@Nullable EditorElement editorElement) {
Log.d("ALAN", "Entity down " + editorElement);
}
@Override
public void onEntitySingleTap(@Nullable EditorElement editorElement) {
Log.d("ALAN", "Entity single tapped " + editorElement);
}
@Override
public void onEntityDoubleTap(@NonNull EditorElement editorElement) {
Log.d("ALAN", "Entity double tapped " + editorElement);
if (editorElement.getRenderer() instanceof MultiLineTextRenderer) {
imageEditorView.startTextEditing(editorElement);
} else {
imageEditorView.deleteElement(editorElement);
}
}
});
}
private static EditorModel initialModel() {
EditorModel model = EditorModel.create();
EditorElement image = new EditorElement(new UrlRenderer("https://cdn.aarp.net/content/dam/aarp/home-and-family/your-home/2018/06/1140-house-inheriting.imgcache.rev68c065601779c5d76b913cf9ec3a977e.jpg"));
image.getFlags().setSelectable(false).persist();
model.addElement(image);
EditorElement elementC = new EditorElement(new UrlRenderer("https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/SNice.svg/220px-SNice.svg.png"));
elementC.getLocalMatrix().postScale(0.2f, 0.2f);
//elementC.getLocalMatrix().postRotate(30);
model.addElement(elementC);
EditorElement elementE = new EditorElement(new UrlRenderer("https://www.vitalessentialsraw.com/assets/images/background-images/laying-grey-cat.png"));
elementE.getLocalMatrix().postScale(0.2f, 0.2f);
//elementE.getLocalMatrix().postRotate(60);
model.addElement(elementE);
EditorElement elementD = new EditorElement(new UrlRenderer("https://petspluslubbocktx.com/files/2016/11/DC-Cat-Weight-Management.png"));
elementD.getLocalMatrix().postScale(0.2f, 0.2f);
//elementD.getLocalMatrix().postRotate(60);
model.addElement(elementD);
EditorElement elementF = new EditorElement(new UrlRenderer("https://purepng.com/public/uploads/large/purepng.com-black-top-hathatsstandard-sizeblacktop-14215263591972x0zh.png"));
elementF.getLocalMatrix().postScale(0.2f, 0.2f);
//elementF.getLocalMatrix().postRotatF(60);
model.addElement(elementF);
EditorElement elementG = new EditorElement(new UriRenderer(Uri.parse("file:///android_asset/food/apple.png")));
elementG.getLocalMatrix().postScale(0.2f, 0.2f);
//elementG.getLocalMatrix().postRotatG(60);
model.addElement(elementG);
EditorElement elementH = new EditorElement(new MultiLineTextRenderer("Hello, World!", 0xff0000ff, MultiLineTextRenderer.Mode.REGULAR));
//elementH.getLocalMatrix().postScale(0.2f, 0.2f);
model.addElement(elementH);
EditorElement elementH2 = new EditorElement(new MultiLineTextRenderer("Hello, World 2!", 0xff0000ff, MultiLineTextRenderer.Mode.REGULAR));
//elementH.getLocalMatrix().postScale(0.2f, 0.2f);
model.addElement(elementH2);
return model;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("MODEL", imageEditorView.getModel());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_menu, menu);
this.menu = menu;
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_undo:
imageEditorView.getModel().undo();
Log.d(TAG, String.format("Model is %s", imageEditorView.getModel().isChanged() ? "changed" : "unchanged"));
return true;
case R.id.action_redo:
imageEditorView.getModel().redo();
return true;
case R.id.action_crop:
imageEditorView.setMode(ImageEditorView.Mode.MoveAndResize);
imageEditorView.getModel().startCrop();
return true;
case R.id.action_done:
imageEditorView.setMode(ImageEditorView.Mode.MoveAndResize);
imageEditorView.getModel().doneCrop();
return true;
case R.id.action_draw:
imageEditorView.setDrawingBrushColor(0xffffff00);
imageEditorView.startDrawing(0.02f, Paint.Cap.ROUND, false);
return true;
case R.id.action_rotate_right_90:
imageEditorView.getModel().rotate90clockwise();
return true;
case R.id.action_rotate_left_90:
imageEditorView.getModel().rotate90anticlockwise();
return true;
case R.id.action_flip_horizontal:
imageEditorView.getModel().flipHorizontal();
return true;
case R.id.action_flip_vertical:
imageEditorView.getModel().flipVertical();
return true;
case R.id.action_edit_text:
editText();
return true;
case R.id.action_lock_crop_aspect:
imageEditorView.getModel().setCropAspectLock(!imageEditorView.getModel().isCropAspectLocked());
return true;
case R.id.action_save:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE },
0);
} else {
Bitmap bitmap = imageEditorView.getModel().render(this);
try {
Uri uri = saveBmp(bitmap);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(uri, "image/*");
startActivity(intent);
} finally {
bitmap.recycle();
}
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void editText() {
imageEditorView.getModel().getRoot().findElement(new Matrix(), new Matrix(), (element, inverseMatrix) -> {
if (element.getRenderer() instanceof MultiLineTextRenderer) {
imageEditorView.startTextEditing(element);
return true;
}
return false;
}
);
}
private Uri saveBmp(Bitmap bitmap) {
String path = Environment.getExternalStorageDirectory().toString();
File filePath = new File(path);
File imageEditor = new File(filePath, "ImageEditor");
if (!imageEditor.exists()) {
imageEditor.mkdir();
}
int counter = 0;
File file;
do {
counter++;
file = new File(imageEditor, String.format(Locale.US, "ImageEditor_%03d.jpg", counter));
} while (file.exists());
try {
try (OutputStream stream = new FileOutputStream(file)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream);
}
return Uri.parse(MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName()));
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}