├── .gitignore
├── .idea
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── sticker.json
│ ├── java
│ └── com
│ │ └── march
│ │ ├── picedit
│ │ ├── MainActivity.java
│ │ ├── MyApplication.java
│ │ ├── PicEditActivity.java
│ │ ├── SelectImageActivity.java
│ │ ├── edit
│ │ │ └── EditCropRotateActivity.java
│ │ ├── graffiti
│ │ │ └── GraffitiActivity.java
│ │ ├── sticker
│ │ │ ├── ResourceFactory.java
│ │ │ ├── StickerImageActivity.java
│ │ │ ├── StickerSourceActivity.java
│ │ │ └── model
│ │ │ │ └── StickerSource.java
│ │ └── test
│ │ │ ├── PorterDuffXfermodeView.java
│ │ │ ├── TestCompressImageActivity.java
│ │ │ └── TestPorterDuffXfermodeActivity.java
│ │ └── turbojpeg
│ │ └── TurboJpegUtils.java
│ ├── jniLibs
│ ├── armeabi-v7a
│ │ └── libcompress.so
│ └── armeabi
│ │ └── libcompress.so
│ └── res
│ ├── drawable
│ ├── common_btn_close.png
│ ├── common_btn_ok.png
│ ├── edit_cut_crop_16_9_a.png
│ ├── edit_cut_crop_16_9_b.png
│ ├── edit_cut_crop_1_1_a.png
│ ├── edit_cut_crop_1_1_b.png
│ ├── edit_cut_crop_2_3_a.png
│ ├── edit_cut_crop_2_3_b.png
│ ├── edit_cut_crop_3_2_a.png
│ ├── edit_cut_crop_3_2_b.png
│ ├── edit_cut_crop_3_4_a.png
│ ├── edit_cut_crop_3_4_b.png
│ ├── edit_cut_crop_4_3_a.png
│ ├── edit_cut_crop_4_3_b.png
│ ├── edit_cut_crop_9_16_a.png
│ ├── edit_cut_crop_9_16_b.png
│ ├── edit_cut_crop_freedom_a.png
│ ├── edit_cut_crop_freedom_b.png
│ ├── edit_rotate_flipx_pressed.png
│ ├── edit_rotate_flipx_released.png
│ ├── edit_rotate_flipy_pressed.png
│ ├── edit_rotate_flipy_released.png
│ ├── edit_rotate_left_pressed.png
│ ├── edit_rotate_left_released.png
│ ├── edit_rotate_right_pressed.png
│ ├── edit_rotate_right_released.png
│ ├── ic_launcher.png
│ ├── icon_repeat_bitmap.xml
│ ├── img_edit_tab_clip_a.png
│ ├── img_edit_tab_clip_b.png
│ ├── img_edit_tab_rotate_a.png
│ ├── img_edit_tab_rotate_b.png
│ ├── sticker_edit_color_black.png
│ ├── sticker_edit_color_white.png
│ ├── sticker_edit_control.png
│ ├── sticker_edit_del.png
│ ├── sticker_edit_drop_down.png
│ ├── sticker_edit_set_top.png
│ └── sticker_edit_symmetry.png
│ ├── layout
│ ├── edit_activity.xml
│ ├── edit_crop_mode_item.xml
│ ├── eidt_rotate_mode_item.xml
│ ├── graffiti_activity.xml
│ ├── home_activity.xml
│ ├── sticker_image_activity.xml
│ ├── sticker_item.xml
│ ├── sticker_source_activity.xml
│ ├── test_compress_activity.xml
│ ├── xfermode_activity.xml
│ └── xfermode_item.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── freeline.py
├── freeline_project_description.json
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── lowpoly
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── uniquestudio
│ │ └── lowpoly
│ │ └── LowPoly.java
│ ├── jniLibs
│ ├── armeabi-v7a
│ │ └── liblowpoly.so
│ ├── armeabi
│ │ └── liblowpoly.so
│ └── x86
│ │ └── liblowpoly.so
│ └── res
│ └── values
│ └── strings.xml
├── piceditor
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── march
│ │ └── piceditor
│ │ ├── common
│ │ ├── ClickChecker.java
│ │ ├── IDrawable.java
│ │ └── TouchHandler.java
│ │ ├── functions
│ │ ├── crop
│ │ │ ├── CropOverlayView.java
│ │ │ └── gesture
│ │ │ │ ├── CropBaseHandler.java
│ │ │ │ └── impl
│ │ │ │ ├── AspectRatioCropHandler.java
│ │ │ │ ├── MoveHandler.java
│ │ │ │ ├── NoAspectRatioCropHandler.java
│ │ │ │ └── TwoFingerHandler.java
│ │ ├── graffiti
│ │ │ ├── GraffitiLayerConfig.java
│ │ │ ├── GraffitiOverlayView.java
│ │ │ └── model
│ │ │ │ └── TouchPartHolder.java
│ │ ├── rotate
│ │ │ └── RotateFrameLayout.java
│ │ └── sticker
│ │ │ ├── EasyMenuHandler.java
│ │ │ ├── StickerDrawOverlay.java
│ │ │ ├── gesture
│ │ │ ├── StickerBaseTouchHandler.java
│ │ │ └── impl
│ │ │ │ ├── BottomRightCornerHandler.java
│ │ │ │ ├── MoveHandler.java
│ │ │ │ └── TwoFingersHandler.java
│ │ │ ├── listener
│ │ │ ├── OnStickerEventListener.java
│ │ │ └── StickerMenuHandler.java
│ │ │ └── model
│ │ │ ├── Position.java
│ │ │ ├── Sticker.java
│ │ │ └── StickerMenu.java
│ │ ├── model
│ │ └── PointF.java
│ │ └── utils
│ │ ├── BitmapUtils.java
│ │ ├── Blur.java
│ │ ├── CalculateUtils.java
│ │ ├── DrawUtils.java
│ │ ├── GraffitiUtils.java
│ │ ├── LogUtils.java
│ │ ├── Utils.java
│ │ └── ViewUtils.java
│ └── res
│ └── values
│ └── strings.xml
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
11 | # Local configuration file (sdk path, etc)
12 | local.properties
13 |
14 | # Proguard folder generated by Eclipse
15 | proguard/
16 |
17 | # Intellij project files
18 | *.iml
19 | *.ipr
20 | *.iws
21 | .idea/
22 |
23 | # Gradle files
24 | .gradle/
25 | gradle/
26 | build/
27 | gradle.properties
28 | gradlew
29 | gradlew.bat
30 |
31 | #Android Studio
32 | build/
33 | */build/
34 | captures/
35 |
36 | # built application files
37 | *.apk
38 | *.ap_
39 |
40 | # files for the dex VM
41 | *.dex
42 |
43 | # Java class files
44 | *.class
45 |
46 | # Eclipse generated files
47 | */bin/
48 | */gen/
49 | */out/
50 | .classpath
51 | .project
52 | .settings/
53 |
54 | # OSX files
55 | .DS_Store
56 |
57 | # Log Files
58 | *.log
59 |
60 | # Other
61 | .svn
62 | *.properties
63 |
64 | #freeline
65 | freeline.*
66 | freeline.zip
67 | freeline/
68 | freeline.zip.tmp
69 | freeline_project_description.json
70 | *.zip
71 | .flowconfig
72 |
73 | node_modules/
74 |
75 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 图片编辑
2 |
3 | 实现图片处理的主流功能,涉及图片处理、手势事件处理、自定义控件等。
4 |
5 | 目前还在陆续的开发完善阶段,旨在完成相应功能和优化性能,未来封装抽象想做成友好的可扩展的图片处理类库。
6 |
7 | ### 裁剪
8 |
9 | 仿美图秀秀
10 |
11 | 1. 自由裁剪 done
12 | 2. 比例裁剪 done
13 | 3. 自定义控件裁剪框,支持角、边拖动 done
14 | 4. 自定义控件裁剪框,支持双指缩放 done
15 | 5. 仿美图秀秀 UI done
16 |
17 | ### 旋转
18 |
19 | 仿美图秀秀
20 |
21 | 1. 90度旋转 done
22 | 2. 镜像反转 done
23 | 3. 手指滑动任意角度旋转 todo
24 |
25 | ### 贴纸
26 |
27 | 仿 in
28 |
29 | 1. 自定义控件,贴纸浮层 done
30 | 1. 右下角触控,贴纸放大,旋转 done
31 | 2. 双指触控,贴纸放大,旋转 done
32 | 3. 单指触控,贴纸移动 done
33 | 4. 支持自定义贴纸 menu done
34 | 5. 内置贴纸 menu,镜像垂直反转,镜像水平反转,镜像双向,反转,删除 done
35 | 6. 自动提升功能,贴纸覆盖在一起时可以上下循环切换,可配置开启 done
36 | 7. 贴纸位置,缩放比例,最大最小缩放可配置 done
37 | 8. 贴纸变色,支持变为纯色 done
38 | 9. 支持贴纸真删,假删,回收资源等 done
39 | 10. 贴纸贴上之后波动一下动画,部分完成,现在支持设置 initScale = 1 时 done
40 | 11. 仿 in UI todo
41 |
42 | ### 涂鸦
43 |
44 | 我们常见的马赛克是涂鸦的一种类型,这里不仅仅是马赛克。
45 |
46 | 1. 支持手势路径绘制 done
47 | 2. 支持拖动矩形区域绘制 done
48 | 3. 马赛克模式 done
49 | 4. 高斯模糊模式 done
50 | 5. 纯色模式 done
51 | 6. 图片模式 done
52 | 7. poly 模式 done
53 | 8. 支持多层涂鸦 done
54 |
55 |
56 | ### 滤镜
57 |
58 |
59 | ### 虚化
60 |
61 |
62 | ### 大头
63 |
64 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def version = rootProject.ext.version
4 | def libs = rootProject.ext.libs
5 |
6 | android {
7 | compileSdkVersion version.compileSdkVersion
8 |
9 | defaultConfig {
10 | applicationId "com.march.picedit"
11 | minSdkVersion 15
12 | targetSdkVersion 25
13 | versionCode 1
14 | versionName "1.0"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 |
24 | sourceSets {
25 | //定义编译时编译文件的路径
26 | main {
27 | res.srcDirs = ['src/main/res']
28 | jniLibs.srcDirs = ['src/main/jniLibs']
29 | }
30 | }
31 | }
32 |
33 | dependencies {
34 |
35 | compile fileTree(include: ['*.jar'], dir: 'libs')
36 | implementation project(':piceditor', )
37 | implementation project(':common', )
38 | implementation project(':uikit', )
39 | implementation project(':gallery', )
40 |
41 | implementation libs.design
42 | implementation libs.appcompat_v7
43 | implementation libs.eventbus
44 | implementation libs.glide
45 | implementation libs.rxjava2
46 | implementation libs.rxandroid
47 | implementation libs.gson
48 |
49 | annotationProcessor libs.butterknife840_processor
50 | implementation libs.butterknife840
51 | }
52 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/march/AndroidRes/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.blur.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
31 |
34 |
37 |
40 |
43 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.os.Build;
6 | import android.view.View;
7 |
8 | import com.march.common.model.ImageInfo;
9 | import com.march.picedit.edit.EditCropRotateActivity;
10 | import com.march.picedit.graffiti.GraffitiActivity;
11 | import com.march.picedit.sticker.StickerImageActivity;
12 | import com.march.picedit.test.TestCompressImageActivity;
13 | import com.march.picedit.test.TestPorterDuffXfermodeActivity;
14 | import com.march.uikit.annotation.UILayout;
15 | import com.march.uikit.annotation.UITitle;
16 |
17 | import java.util.ArrayList;
18 |
19 | import butterknife.OnClick;
20 |
21 | @UILayout(R.layout.home_activity)
22 | @UITitle(titleText = "首页")
23 | public class MainActivity extends PicEditActivity {
24 |
25 | @Override
26 | public void initBeforeViewCreated() {
27 | super.initBeforeViewCreated();
28 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
29 | requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
30 | }
31 | }
32 |
33 | private int launchViewId = -1;
34 |
35 | @OnClick({R.id.btn_xfermode, R.id.btn_choose_pic, R.id.btn_test, R.id.btn_sticker_test, R.id.btn_graffiti})
36 | public void clickView(View view) {
37 | launchViewId = view.getId();
38 | switch (view.getId()) {
39 | case R.id.btn_choose_pic:
40 | SelectImageActivity.startActivity(getActivity());
41 | break;
42 | case R.id.btn_test:
43 | startActivity(TestCompressImageActivity.class);
44 | break;
45 | case R.id.btn_sticker_test:
46 | SelectImageActivity.startActivity(getActivity());
47 | break;
48 | case R.id.btn_graffiti:
49 | GraffitiActivity.start(getActivity());
50 | break;
51 | case R.id.btn_xfermode:
52 | startActivity(TestPorterDuffXfermodeActivity.class);
53 | break;
54 | }
55 | }
56 |
57 | @Override
58 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
59 | super.onActivityResult(requestCode, resultCode, data);
60 | if(data == null){
61 | return;
62 | }
63 | if (launchViewId == -1) {
64 | return;
65 | }
66 | ArrayList extra = data.getParcelableArrayListExtra(SelectImageActivity.KEY_DATA);
67 | if (extra.size() != 1) {
68 | return;
69 | }
70 | switch (launchViewId) {
71 | case R.id.btn_choose_pic:
72 | EditCropRotateActivity.start(getActivity(), extra.get(0).getPath());
73 | break;
74 | case R.id.btn_sticker_test:
75 | StickerImageActivity.start(getActivity(), extra.get(0).getPath());
76 | break;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/MyApplication.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit;
2 |
3 | import com.march.common.Common;
4 | import com.march.common.utils.CrashUtils;
5 | import com.march.uikit.UIKit;
6 | import com.march.uikit.app.BaseApplication;
7 | import com.march.uikit.common.JsonParseAdapterImpl;
8 |
9 | /**
10 | * CreateAt : 7/17/17
11 | * Describe :
12 | *
13 | * @author chendong
14 | */
15 | public class MyApplication extends BaseApplication {
16 |
17 | @Override
18 | public void onCreate() {
19 | super.onCreate();
20 |
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/PicEditActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit;
2 |
3 | import android.graphics.BitmapFactory;
4 |
5 | import com.bumptech.glide.Glide;
6 | import com.bumptech.glide.request.animation.GlideAnimation;
7 | import com.bumptech.glide.request.target.SimpleTarget;
8 | import com.march.picedit.sticker.StickerSourceActivity;
9 | import com.march.uikit.app.BaseActivity;
10 |
11 | import org.greenrobot.eventbus.EventBus;
12 | import org.greenrobot.eventbus.Subscribe;
13 | import org.greenrobot.eventbus.ThreadMode;
14 |
15 | import java.io.File;
16 |
17 | import butterknife.ButterKnife;
18 |
19 | /**
20 | * CreateAt : 2018/5/23
21 | * Describe :
22 | *
23 | * @author chendong
24 | */
25 |
26 | public class PicEditActivity extends BaseActivity{
27 |
28 | @Override
29 | public void initAfterViewCreated() {
30 | super.initAfterViewCreated();
31 | ButterKnife.bind(this);
32 | EventBus.getDefault().register(this);
33 |
34 | }
35 |
36 |
37 | @Override
38 | public void onDestroy() {
39 | super.onDestroy();
40 | EventBus.getDefault().unregister(this);
41 | }
42 |
43 | @Subscribe(threadMode = ThreadMode.MAIN)
44 | public void onEvent(PicEditActivity event) {
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/SelectImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.widget.ImageView;
7 |
8 | import com.bumptech.glide.DrawableTypeRequest;
9 | import com.bumptech.glide.Glide;
10 | import com.march.common.model.ImageInfo;
11 | import com.march.gallery.GalleryActivity;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * CreateAt : 2018/5/24
18 | * Describe :
19 | *
20 | * @author chendong
21 | */
22 | public class SelectImageActivity extends GalleryActivity {
23 |
24 | public static final String KEY_DATA = "KEY_DATA";
25 |
26 | public static void startActivity(Activity context) {
27 | Intent intent = new Intent(context, SelectImageActivity.class);
28 | context.startActivityForResult(intent,100);
29 | }
30 |
31 | @Override
32 | protected void loadImg(Context context, String path, int width, int height, ImageView imageView) {
33 | if (path.endsWith("gif")) {
34 | Glide.with(context).load(path).into(imageView);
35 | } else {
36 | DrawableTypeRequest load = Glide.with(context).load(path);
37 | if (width > 0 && height > 0) {
38 | load.override(width, height).into(imageView);
39 | } else {
40 | load.into(imageView);
41 | }
42 | }
43 | }
44 |
45 | @Override
46 | protected void onResult(List list) {
47 | Intent data = new Intent();
48 | ArrayList imageInfos = new ArrayList<>(list);
49 | data.putParcelableArrayListExtra(KEY_DATA, imageInfos);
50 | setResult(100, data);
51 | SelectImageActivity.this.finish();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/graffiti/GraffitiActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.graffiti;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Color;
8 | import android.os.Bundle;
9 | import android.view.View;
10 |
11 | import com.march.common.utils.ActivityAnimUtils;
12 | import com.march.common.utils.FileUtils;
13 | import com.march.picedit.PicEditActivity;
14 | import com.march.picedit.R;
15 | import com.march.piceditor.functions.graffiti.GraffitiLayerConfig;
16 | import com.march.piceditor.functions.graffiti.GraffitiOverlayView;
17 | import com.march.turbojpeg.TurboJpegUtils;
18 | import com.march.uikit.annotation.UILayout;
19 | import com.march.uikit.annotation.UITitle;
20 |
21 | import butterknife.BindView;
22 | import butterknife.OnClick;
23 |
24 | /**
25 | * CreateAt : 7/25/17
26 | * Describe :
27 | *
28 | * @author chendong
29 | */
30 | @UILayout(R.layout.graffiti_activity)
31 | @UITitle(titleText = "涂鸦")
32 | public class GraffitiActivity extends PicEditActivity {
33 |
34 | @BindView(R.id.graffiti_overlay) GraffitiOverlayView mGraffitiOverlay;
35 |
36 | public static void start(Activity activity) {
37 | Intent intent = new Intent(activity, GraffitiActivity.class);
38 | activity.startActivity(intent);
39 | ActivityAnimUtils.translateStart(activity);
40 |
41 | }
42 |
43 |
44 | @Override
45 | public void initAfterViewCreated() {
46 | super.initAfterViewCreated();
47 | mGraffitiOverlay.setSrc(FileUtils.newRootFile("2.jpg").getAbsolutePath());
48 | }
49 |
50 | @OnClick({R.id.tv_path, R.id.tv_rect, R.id.tv_erase, R.id.tv_draw, R.id.tv_save})
51 | public void clickView(View view) {
52 | switch (view.getId()) {
53 | case R.id.tv_path:
54 | mGraffitiOverlay.setTouchMode(GraffitiOverlayView.TouchMode.PATH);
55 | break;
56 | case R.id.tv_rect:
57 | mGraffitiOverlay.setTouchMode(GraffitiOverlayView.TouchMode.RECT);
58 | break;
59 | case R.id.tv_erase:
60 | mGraffitiOverlay.setErase(true);
61 | break;
62 | case R.id.tv_draw:
63 | mGraffitiOverlay.setErase(false);
64 | break;
65 | case R.id.tv_save:
66 | Bitmap save = mGraffitiOverlay.save();
67 | TurboJpegUtils.compressBitmap(save, 100, FileUtils.newRootFile(System.currentTimeMillis() + ".jpg").getAbsolutePath(), true);
68 | break;
69 | }
70 | }
71 |
72 |
73 | @OnClick({R.id.tv_effect_blur,
74 | R.id.tv_effect_color,
75 | R.id.tv_effect_poly,
76 | R.id.tv_effect_mosaic,
77 | R.id.tv_effect_image})
78 | public void clickView2(View view) {
79 | switch (view.getId()) {
80 | case R.id.tv_effect_blur:
81 | mGraffitiOverlay.addGraffitiLayer(GraffitiLayerConfig.newBlurLayer(GraffitiLayerConfig.DEF_VALUE));
82 | break;
83 | case R.id.tv_effect_color:
84 | mGraffitiOverlay.addGraffitiLayer(GraffitiLayerConfig.newColorLayer(Color.parseColor("#ff60ead5")));
85 | break;
86 | case R.id.tv_effect_poly:
87 | mGraffitiOverlay.addGraffitiLayer(GraffitiLayerConfig.newLowPolyLayer(GraffitiLayerConfig.DEF_VALUE));
88 | break;
89 | case R.id.tv_effect_mosaic:
90 | mGraffitiOverlay.addGraffitiLayer(GraffitiLayerConfig.newMosaicLayer(40));
91 | break;
92 | case R.id.tv_effect_image:
93 | Bitmap bitmap = BitmapFactory.decodeFile(FileUtils.newRootFile("bg.jpg").getAbsolutePath());
94 | mGraffitiOverlay.addGraffitiLayer(GraffitiLayerConfig.newImageLayer(bitmap));
95 | break;
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/sticker/ResourceFactory.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.sticker;
2 |
3 | import android.content.Context;
4 | import android.graphics.BitmapFactory;
5 | import android.graphics.drawable.BitmapDrawable;
6 | import android.graphics.drawable.Drawable;
7 | import android.support.v4.util.SparseArrayCompat;
8 |
9 | /**
10 | * CreateAt : 7/21/17
11 | * Describe :
12 | *
13 | * @author chendong
14 | */
15 | public class ResourceFactory {
16 |
17 | private SparseArrayCompat mMenuIconMap;
18 | private Context mContext;
19 |
20 | public ResourceFactory(Context context) {
21 | mContext = context;
22 | mMenuIconMap = new SparseArrayCompat<>();
23 | }
24 |
25 |
26 | public Drawable decodeDrawable(int res) {
27 | Drawable drawable = mMenuIconMap.get(res);
28 | if (drawable == null) {
29 | drawable = new BitmapDrawable(mContext.getResources(), BitmapFactory.decodeResource(mContext.getResources(), res));
30 | mMenuIconMap.put(res, drawable);
31 | } else {
32 | // LogUtils.e(TAG, "使用已有图片");
33 | }
34 | return drawable;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/sticker/StickerImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.sticker;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.view.View;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.bumptech.glide.request.animation.GlideAnimation;
12 | import com.bumptech.glide.request.target.SimpleTarget;
13 | import com.march.common.utils.ActivityAnimUtils;
14 | import com.march.picedit.PicEditActivity;
15 | import com.march.picedit.R;
16 | import com.march.piceditor.functions.sticker.EasyMenuHandler;
17 | import com.march.piceditor.functions.sticker.StickerDrawOverlay;
18 | import com.march.piceditor.functions.sticker.model.Position;
19 | import com.march.piceditor.functions.sticker.model.Sticker;
20 | import com.march.piceditor.functions.sticker.model.StickerMenu;
21 | import com.march.uikit.annotation.UILayout;
22 | import com.march.uikit.annotation.UITitle;
23 |
24 | import org.greenrobot.eventbus.Subscribe;
25 | import org.greenrobot.eventbus.ThreadMode;
26 |
27 | import java.io.File;
28 | import java.util.Random;
29 |
30 | import butterknife.BindView;
31 | import butterknife.OnClick;
32 |
33 | /**
34 | * CreateAt : 7/22/17
35 | * Describe :
36 | *
37 | * @author chendong
38 | */
39 | @UILayout(R.layout.sticker_image_activity)
40 | @UITitle(titleText = "贴纸")
41 | public class StickerImageActivity extends PicEditActivity {
42 |
43 | public static final String KEY_PATH = "KEY_PATH";
44 |
45 | @BindView(R.id.iv_image) ImageView mImageView;
46 | @BindView(R.id.sdo) StickerDrawOverlay mStickerDrawOverlay;
47 |
48 | private String mImagePath;
49 | private ResourceFactory mResourceFactory;
50 |
51 | public static void start(Activity activity, String path) {
52 | Intent intent = new Intent(activity, StickerImageActivity.class);
53 | intent.putExtra(KEY_PATH, path);
54 | activity.startActivity(intent);
55 | ActivityAnimUtils.translateStart(activity);
56 | }
57 |
58 |
59 | @Subscribe(threadMode = ThreadMode.MAIN)
60 | public void onEvent(StickerSourceActivity.StickerSourceEvent event) {
61 | Glide.with(getContext()).load(event.mStickerSource.getSourceUrl())
62 | .downloadOnly(new SimpleTarget() {
63 | @Override
64 | public void onResourceReady(File resource, GlideAnimation super File> glideAnimation) {
65 | addSticker(BitmapFactory.decodeFile(resource.getAbsolutePath()));
66 | }
67 | });
68 | }
69 |
70 | @OnClick({R.id.tv_sticker, R.id.tv_sticker_big, R.id.tv_sticker_small})
71 | public void clickView(View view) {
72 | switch (view.getId()) {
73 | case R.id.tv_sticker:
74 | StickerSourceActivity.start(getActivity());
75 | break;
76 | case R.id.tv_sticker_big:
77 | mStickerDrawOverlay.getActiveSticker().postMatrixScale(1.1f, 1.1f);
78 | mStickerDrawOverlay.invalidate();
79 | break;
80 | case R.id.tv_sticker_small:
81 | mStickerDrawOverlay.getActiveSticker().postMatrixScale(1f, 1f);
82 | mStickerDrawOverlay.invalidate();
83 | break;
84 | }
85 | }
86 |
87 | @Override
88 | public void initBeforeViewCreated() {
89 | super.initBeforeViewCreated();
90 | mImagePath = getIntent().getStringExtra(KEY_PATH);
91 |
92 |
93 | }
94 |
95 | @Override
96 | public void initAfterViewCreated() {
97 | super.initAfterViewCreated();
98 | mResourceFactory = new ResourceFactory(getContext());
99 | Glide.with(getContext()).load(mImagePath).into(mImageView);
100 | }
101 |
102 | private void addSticker(Bitmap bitmap) {
103 | Sticker sticker = new Sticker(bitmap);
104 |
105 | // delete handler & tag
106 | StickerMenu topLeftMenu = new StickerMenu(Position.TOP_LEFT, mResourceFactory.decodeDrawable(R.drawable.sticker_edit_del));
107 | topLeftMenu.setTag(100);
108 | topLeftMenu.setStickerMenuHandler(EasyMenuHandler.DELETE_STICKER);
109 |
110 | // flip vertical handler
111 | StickerMenu topRightMenu = new StickerMenu(Position.TOP_RIGHT, mResourceFactory.decodeDrawable(R.drawable.sticker_edit_symmetry));
112 | topRightMenu.setStickerMenuHandler(EasyMenuHandler.FLIP_HORIZONTAL);
113 |
114 | StickerMenu bottomLeftMenu = new StickerMenu(Position.BOTTOM_LEFT, mResourceFactory.decodeDrawable(R.drawable.sticker_edit_color_white));
115 | StickerMenu bottomRightMenu = new StickerMenu(Position.BOTTOM_RIGHT, mResourceFactory.decodeDrawable(R.drawable.sticker_edit_control));
116 |
117 | // add menu
118 | sticker.addStickerMenu(topLeftMenu, topRightMenu, bottomLeftMenu, bottomRightMenu);
119 |
120 | // sticker color filter
121 | // sticker.setColorFilter(new Random().nextInt(225), new Random().nextInt(225), new Random().nextInt(225));
122 | // init position & init scale
123 | sticker.setInitTranslate(250 + new Random().nextInt(350), 250 + new Random().nextInt(350));
124 | sticker.setInitScale(1f);
125 | // min size & max size
126 | sticker.setMinSize(100);
127 | // sticker.setMaxSize(1000);
128 |
129 | sticker.setAutoLifting(true);
130 | mStickerDrawOverlay.addSticker(sticker, true);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/sticker/StickerSourceActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.sticker;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.support.v7.widget.GridLayoutManager;
6 | import android.support.v7.widget.LinearLayoutManager;
7 | import android.support.v7.widget.RecyclerView;
8 | import android.widget.ImageView;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.google.gson.Gson;
12 | import com.google.gson.reflect.TypeToken;
13 | import com.march.common.utils.ActivityAnimUtils;
14 | import com.march.common.utils.DimensUtils;
15 | import com.march.common.utils.LogUtils;
16 | import com.march.lightadapter.LightAdapter;
17 | import com.march.lightadapter.LightHolder;
18 | import com.march.lightadapter.LightInjector;
19 | import com.march.lightadapter.helper.LightManager;
20 | import com.march.lightadapter.inject.AdapterLayout;
21 | import com.march.lightadapter.listener.SimpleItemListener;
22 | import com.march.picedit.PicEditActivity;
23 | import com.march.picedit.R;
24 | import com.march.picedit.sticker.model.StickerSource;
25 | import com.march.uikit.annotation.UILayout;
26 | import com.march.uikit.annotation.UITitle;
27 | import com.march.uikit.widget.TitleView;
28 |
29 | import org.greenrobot.eventbus.EventBus;
30 |
31 | import java.io.BufferedReader;
32 | import java.io.IOException;
33 | import java.io.InputStreamReader;
34 | import java.lang.reflect.Type;
35 | import java.util.List;
36 |
37 | import butterknife.BindView;
38 | /**
39 | * CreateAt : 7/22/17
40 | * Describe :
41 | *
42 | * @author chendong
43 | */
44 | @UILayout(R.layout.sticker_source_activity)
45 | @UITitle(titleText = "贴纸一览")
46 | public class StickerSourceActivity extends PicEditActivity {
47 |
48 | public static final String TAG = StickerSourceActivity.class.getSimpleName();
49 |
50 |
51 | @BindView(R.id.rv_sticker) RecyclerView mStickerRv;
52 |
53 | @AdapterLayout(R.layout.sticker_item)
54 | private LightAdapter mAdapter;
55 |
56 | public static void start(Activity activity) {
57 | Intent intent = new Intent(activity, StickerSourceActivity.class);
58 | activity.startActivity(intent);
59 | ActivityAnimUtils.translateStart(activity);
60 | }
61 |
62 |
63 | public static class StickerSourceEvent {
64 | public StickerSource mStickerSource;
65 |
66 | public StickerSourceEvent(StickerSource stickerSource) {
67 | mStickerSource = stickerSource;
68 | }
69 |
70 | public void post() {
71 | EventBus.getDefault().post(this);
72 | }
73 | }
74 |
75 | @Override
76 | public void initAfterViewCreated() {
77 | super.initAfterViewCreated();
78 | mViewDelegate.setTitleText(TitleView.LEFT, "返回");
79 | mViewDelegate.getTitleView().setLeftBackListener(getActivity());
80 | try {
81 | BufferedReader reader = new BufferedReader(new InputStreamReader(getAssets().open("sticker.json")));
82 | Type type = new TypeToken>() {
83 | }.getType();
84 | List mStickerSources = new Gson().fromJson(reader, type);
85 | createAdapter(mStickerSources);
86 | } catch (IOException e) {
87 | e.printStackTrace();
88 | }
89 | }
90 |
91 |
92 | private void createAdapter(List list) {
93 | LogUtils.e(TAG, Thread.currentThread().getName());
94 | mAdapter = new LightAdapter(getContext(), list) {
95 | int spanCount = 3;
96 | int size = (int) (DimensUtils.WIDTH * 1f / spanCount);
97 |
98 | @Override
99 | public void onBindView(LightHolder holder, final StickerSource data, int pos, int type) {
100 | holder
101 | .setLayoutParams(size, size)
102 | .setCallback(R.id.iv_image, new LightHolder.Callback() {
103 | @Override
104 | public void bind(LightHolder holder, ImageView view, int pos) {
105 | Glide.with(getContext()).load(data.getSourceUrl()).into(view);
106 | }
107 | });
108 | }
109 | };
110 | mAdapter.setOnItemListener(new SimpleItemListener() {
111 | @Override
112 | public void onClick(int pos, LightHolder holder, StickerSource data) {
113 | new StickerSourceEvent(data).post();
114 | onBackPressed();
115 | }
116 | });
117 | LightInjector.initAdapter(mAdapter,this,mStickerRv, LightManager.vGrid(getContext(),3));
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/sticker/model/StickerSource.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.sticker.model;
2 |
3 | /**
4 | * CreateAt : 7/22/17
5 | * Describe :
6 | *
7 | * @author chendong
8 | */
9 | public class StickerSource {
10 |
11 | private String sourceUrl;
12 | private boolean withColor;
13 |
14 | public String getSourceUrl() {
15 | return sourceUrl;
16 | }
17 |
18 | public void setSourceUrl(String sourceUrl) {
19 | this.sourceUrl = sourceUrl;
20 | }
21 |
22 | public boolean isWithColor() {
23 | return withColor;
24 | }
25 |
26 | public void setWithColor(boolean withColor) {
27 | this.withColor = withColor;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/test/PorterDuffXfermodeView.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.test;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.PorterDuff;
8 | import android.graphics.PorterDuffXfermode;
9 | import android.support.annotation.Nullable;
10 | import android.util.AttributeSet;
11 | import android.view.View;
12 |
13 | /**
14 | * CreateAt : 2017/12/6
15 | * Describe :
16 | *
17 | * @author chendong
18 | */
19 | public class PorterDuffXfermodeView extends View {
20 | public PorterDuffXfermodeView(Context context) {
21 | this(context, null);
22 | }
23 |
24 | public PorterDuffXfermodeView(Context context, @Nullable AttributeSet attrs) {
25 | this(context, attrs, 0);
26 | }
27 |
28 | public PorterDuffXfermodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
29 | super(context, attrs, defStyleAttr);
30 | init();
31 | }
32 |
33 |
34 | private PorterDuffXfermode mPorterDuffXfermode;
35 | private Paint mSrcPaint, mDstPaint;
36 |
37 | private void init() {
38 | mSrcPaint = new Paint();
39 | mSrcPaint.setAntiAlias(true);
40 | mSrcPaint.setColor(Color.BLUE);
41 | mSrcPaint.setStyle(Paint.Style.FILL_AND_STROKE);
42 |
43 |
44 | mDstPaint = new Paint();
45 | mDstPaint.setAntiAlias(true);
46 | mDstPaint.setColor(Color.YELLOW);
47 | mDstPaint.setStyle(Paint.Style.FILL_AND_STROKE);
48 |
49 | setPorterDuffXfermodeIndex(1);
50 | }
51 |
52 | public static PorterDuff.Mode[] mPorterDuffXfermodeArray = new PorterDuff.Mode[]{
53 | PorterDuff.Mode.CLEAR,
54 | PorterDuff.Mode.SRC,
55 | PorterDuff.Mode.DST,
56 | PorterDuff.Mode.SRC_OVER,
57 | PorterDuff.Mode.DST_OVER,
58 | PorterDuff.Mode.SRC_IN,
59 | PorterDuff.Mode.DST_IN,
60 | PorterDuff.Mode.SRC_OUT,
61 | PorterDuff.Mode.DST_OUT,
62 | PorterDuff.Mode.SRC_ATOP,
63 | PorterDuff.Mode.DST_ATOP,
64 | PorterDuff.Mode.XOR,
65 | PorterDuff.Mode.DARKEN,
66 | PorterDuff.Mode.LIGHTEN,
67 | PorterDuff.Mode.MULTIPLY,
68 | PorterDuff.Mode.SCREEN,
69 | };
70 |
71 | public void setPorterDuffXfermodeIndex(int index) {
72 | mPorterDuffXfermode = new PorterDuffXfermode(mPorterDuffXfermodeArray[index]);
73 | }
74 |
75 | private float width;
76 | private float height;
77 |
78 | @Override
79 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
80 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
81 | if (width == 0 || height == 0) {
82 | width = getMeasuredWidth();
83 | height = getMeasuredHeight();
84 | setMeasuredDimension((int) width, (int) width);
85 | }
86 | }
87 |
88 | public void reset() {
89 | width = 0;
90 | height = 0;
91 | postInvalidate();
92 | }
93 |
94 | @Override
95 | protected void onDraw(Canvas canvas) {
96 | super.onDraw(canvas);
97 | if (width == 0 || height == 0)
98 | return;
99 | int sc = canvas.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);
100 | {
101 | canvas.drawCircle(width / 3, width / 3, width / 3, mDstPaint);
102 | mSrcPaint.setXfermode(mPorterDuffXfermode);
103 | canvas.drawRect(width / 3f, width / 3f, width, width, mSrcPaint);
104 | canvas.restore();
105 | mDstPaint.setXfermode(null);
106 | }
107 |
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/test/TestCompressImageActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.test;
2 |
3 | import android.Manifest;
4 | import android.content.Intent;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.os.Build;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 |
11 | import com.bumptech.glide.Glide;
12 | import com.march.common.model.ImageInfo;
13 | import com.march.common.utils.BitmapUtils;
14 | import com.march.common.utils.FileUtils;
15 | import com.march.picedit.PicEditActivity;
16 | import com.march.picedit.R;
17 | import com.march.picedit.SelectImageActivity;
18 | import com.march.picedit.sticker.ResourceFactory;
19 | import com.march.piceditor.functions.graffiti.GraffitiOverlayView;
20 | import com.march.turbojpeg.TurboJpegUtils;
21 | import com.march.uikit.annotation.UILayout;
22 |
23 | import java.io.File;
24 | import java.util.ArrayList;
25 |
26 | import butterknife.BindView;
27 | import butterknife.OnClick;
28 | import io.reactivex.Observable;
29 | import io.reactivex.ObservableEmitter;
30 | import io.reactivex.ObservableOnSubscribe;
31 | import io.reactivex.android.schedulers.AndroidSchedulers;
32 | import io.reactivex.annotations.NonNull;
33 | import io.reactivex.functions.Consumer;
34 | import io.reactivex.schedulers.Schedulers;
35 |
36 | /**
37 | * CreateAt : 7/19/17
38 | * Describe :
39 | *
40 | * @author chendong
41 | */
42 | @UILayout(R.layout.test_compress_activity)
43 | public class TestCompressImageActivity extends PicEditActivity {
44 |
45 | private String mPath;
46 | private String mPath2;
47 |
48 | @BindView(R.id.iv_image) ImageView mImageView;
49 | @BindView(R.id.iv_image2) ImageView mImageView2;
50 | @BindView(R.id.mosaic_overlay) GraffitiOverlayView mMosaicOverlay;
51 |
52 | private ResourceFactory mResourceFactory;
53 |
54 | @Override
55 | public void initBeforeViewCreated() {
56 | super.initBeforeViewCreated();
57 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
58 | requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);
59 | }
60 | }
61 |
62 | @OnClick({R.id.btn_action, R.id.btn_choose_pic})
63 | public void clickView(View view) {
64 | switch (view.getId()) {
65 | case R.id.btn_action:
66 | if (mPath == null) return;
67 | Observable.create(new ObservableOnSubscribe() {
68 | @Override
69 | public void subscribe(@NonNull ObservableEmitter e) throws Exception {
70 |
71 | FileUtils.newRootFile("/ztemp1/").mkdirs();
72 | FileUtils.newRootFile("/ztemp2/").mkdirs();
73 |
74 | Bitmap bitmap = BitmapFactory.decodeFile(mPath);
75 |
76 | // so保存
77 | File file = FileUtils.newRootFile("/ztemp1/" + System.currentTimeMillis() + ".jpg");
78 | if (!file.exists()) {
79 | file.createNewFile();
80 | }
81 | TurboJpegUtils.compressBitmap(bitmap, 100, file.getAbsolutePath(), true);
82 | mPath = file.getAbsolutePath();
83 |
84 | // android 算法
85 | Bitmap bitmap2 = BitmapFactory.decodeFile(mPath2);
86 | File file2 = FileUtils.newRootFile("/ztemp2/" + System.currentTimeMillis() + ".jpg");
87 | BitmapUtils.compressImage(bitmap2, file2, Bitmap.CompressFormat.JPEG, 100, true);
88 | mPath2 = file2.getAbsolutePath();
89 | e.onNext(mPath);
90 | }
91 | }).subscribeOn(Schedulers.io())
92 | .observeOn(AndroidSchedulers.mainThread())
93 | .subscribe(new Consumer() {
94 | @Override
95 | public void accept(@NonNull String s) throws Exception {
96 | Glide.with(getContext()).load(mPath).into(mImageView);
97 | Glide.with(getContext()).load(mPath2).into(mImageView2);
98 | }
99 | }, new Consumer() {
100 | @Override
101 | public void accept(@NonNull Throwable throwable) throws Exception {
102 | throwable.printStackTrace();
103 | }
104 | });
105 | break;
106 | case R.id.btn_choose_pic:
107 | SelectImageActivity.startActivity(getActivity());
108 | break;
109 | }
110 | }
111 |
112 | @Override
113 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
114 | super.onActivityResult(requestCode, resultCode, data);
115 | ArrayList extra = data.getParcelableArrayListExtra(SelectImageActivity.KEY_DATA);
116 | if (extra.size() != 1) {
117 | return;
118 | }
119 | ImageInfo imageInfo = extra.get(0);
120 | mMosaicOverlay.setSrc(imageInfo.getPath());
121 | }
122 |
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/picedit/test/TestPorterDuffXfermodeActivity.java:
--------------------------------------------------------------------------------
1 | package com.march.picedit.test;
2 |
3 | import android.support.v7.widget.RecyclerView;
4 | import android.view.ViewGroup;
5 |
6 | import com.march.lightadapter.LightAdapter;
7 | import com.march.lightadapter.LightHolder;
8 | import com.march.lightadapter.LightInjector;
9 | import com.march.lightadapter.helper.LightManager;
10 | import com.march.picedit.R;
11 | import com.march.uikit.annotation.UILayout;
12 | import com.march.uikit.app.BaseActivity;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | import butterknife.BindView;
18 |
19 | /**
20 | * CreateAt : 2017/12/6
21 | * Describe :
22 | *
23 | * @author chendong
24 | */
25 | @UILayout(R.layout.xfermode_activity)
26 | public class TestPorterDuffXfermodeActivity extends BaseActivity {
27 |
28 |
29 | @BindView(R.id.rv)
30 | RecyclerView mRecyclerView;
31 |
32 | private List mIntegers;
33 |
34 | @Override
35 | public void initBeforeViewCreated() {
36 | super.initBeforeViewCreated();
37 | mIntegers = new ArrayList<>();
38 | for (int i = 0; i < PorterDuffXfermodeView.mPorterDuffXfermodeArray.length; i++) {
39 | mIntegers.add(i);
40 | }
41 | }
42 |
43 | @Override
44 | public void initAfterViewCreated() {
45 | super.initAfterViewCreated();
46 | LightAdapter adapter = new LightAdapter(getActivity(), mIntegers, R.layout.xfermode_item) {
47 | @Override
48 | public void onBindView(LightHolder holder, Integer data, int pos, int type) {
49 | PorterDuffXfermodeView porterDuffXfermodeView = holder.getView(R.id.pdxv);
50 | holder.setText(R.id.name_tv, PorterDuffXfermodeView.mPorterDuffXfermodeArray[data].name());
51 | porterDuffXfermodeView.setPorterDuffXfermodeIndex(data);
52 | holder.setLayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
53 | }
54 | };
55 | LightInjector.initAdapter(adapter, this, mRecyclerView, LightManager.vGrid(getContext(), 3));
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/march/turbojpeg/TurboJpegUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.turbojpeg;
2 |
3 | import android.graphics.Bitmap;
4 | import android.os.Build;
5 |
6 |
7 | import com.march.common.utils.BitmapUtils;
8 |
9 | import java.io.File;
10 |
11 | /**
12 | * CreateAt : 7/19/17
13 | * Describe :
14 | *
15 | * @author chendong
16 | */
17 | public class TurboJpegUtils {
18 |
19 |
20 | private static boolean isSupportArmeabi = true;
21 |
22 | static {
23 | try {
24 | System.loadLibrary("compress");
25 | } catch (Exception e) {
26 | e.printStackTrace();
27 | isSupportArmeabi = false;
28 | }
29 | }
30 |
31 |
32 | public static void checkSupportArmeabi() {
33 | String[] abis;
34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
35 | abis = Build.SUPPORTED_ABIS;
36 | } else {
37 | abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2};
38 | }
39 | StringBuilder abiStr = new StringBuilder();
40 | for (String abi : abis) {
41 | abiStr.append(abi).append(",");
42 | }
43 | isSupportArmeabi = abiStr.toString().contains("armeabi") || abiStr.toString().contains("armeabi-v7a");
44 | }
45 |
46 | public static int compressBitmap(Bitmap bit, int quality, String fileName, boolean isRecycle) {
47 | checkSupportArmeabi();
48 | Bitmap result = null;
49 | if (isSupportArmeabi) {
50 | try {
51 | File file = new File(fileName);
52 | if (!file.getParentFile().exists()) {
53 | file.getParentFile().mkdirs();
54 | }
55 | if (!file.exists()) {
56 | file.createNewFile();
57 | }
58 | result = bit.copy(Bitmap.Config.ARGB_8888, true);
59 | return compress(result, quality, fileName, true);
60 | } catch (Exception e) {
61 | e.printStackTrace();
62 | BitmapUtils.compressImage(bit, new File(fileName), Bitmap.CompressFormat.JPEG, 100, isRecycle);
63 | return 1;
64 | } finally {
65 | BitmapUtils.recycleBitmaps(result);
66 | if (isRecycle) {
67 | BitmapUtils.recycleBitmaps(bit);
68 | }
69 | }
70 | } else {
71 | BitmapUtils.compressImage(bit, new File(fileName), Bitmap.CompressFormat.JPEG, 100, isRecycle);
72 | return 1;
73 | }
74 | }
75 |
76 | /**
77 | * 使用native方法进行图片压缩。
78 | * Bitmap的格式必须是ARGB_8888 {@link Bitmap.Config}。
79 | *
80 | * @param bitmap 图片数据
81 | * @param quality 压缩质量
82 | * @param dstFile 压缩后存放的路径
83 | * @param optimize 是否使用哈夫曼算法
84 | * @return 结果
85 | */
86 | public static native int compress(Bitmap bitmap, int quality, String dstFile, boolean optimize);
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libcompress.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/jniLibs/armeabi-v7a/libcompress.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libcompress.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/jniLibs/armeabi/libcompress.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable/common_btn_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/common_btn_close.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/common_btn_ok.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/common_btn_ok.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_16_9_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_16_9_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_16_9_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_16_9_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_1_1_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_1_1_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_1_1_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_1_1_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_2_3_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_2_3_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_2_3_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_2_3_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_3_2_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_3_2_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_3_2_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_3_2_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_3_4_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_3_4_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_3_4_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_3_4_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_4_3_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_4_3_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_4_3_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_4_3_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_9_16_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_9_16_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_9_16_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_9_16_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_freedom_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_freedom_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_cut_crop_freedom_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_cut_crop_freedom_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_flipx_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_flipx_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_flipx_released.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_flipx_released.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_flipy_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_flipy_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_flipy_released.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_flipy_released.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_left_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_left_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_left_released.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_left_released.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_right_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_right_pressed.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/edit_rotate_right_released.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/edit_rotate_right_released.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_repeat_bitmap.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_edit_tab_clip_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/img_edit_tab_clip_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_edit_tab_clip_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/img_edit_tab_clip_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_edit_tab_rotate_a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/img_edit_tab_rotate_a.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/img_edit_tab_rotate_b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/img_edit_tab_rotate_b.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_color_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_color_black.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_color_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_color_white.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_control.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_control.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_del.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_del.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_drop_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_drop_down.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_set_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_set_top.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/sticker_edit_symmetry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/drawable/sticker_edit_symmetry.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
24 |
25 |
32 |
33 |
34 |
38 |
39 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
63 |
64 |
70 |
71 |
76 |
77 |
78 |
84 |
85 |
89 |
90 |
95 |
96 |
97 |
98 |
99 |
105 |
106 |
107 |
108 |
109 |
110 |
114 |
115 |
121 |
122 |
129 |
130 |
134 |
135 |
142 |
143 |
144 |
145 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_crop_mode_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
20 |
21 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/eidt_rotate_mode_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/graffiti_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
15 |
20 |
21 |
25 |
26 |
30 |
31 |
32 |
36 |
37 |
41 |
42 |
46 |
47 |
48 |
49 |
52 |
53 |
58 |
59 |
63 |
64 |
68 |
69 |
70 |
74 |
75 |
79 |
80 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/home_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
19 |
20 |
25 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sticker_image_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
20 |
21 |
25 |
26 |
27 |
28 |
29 |
33 |
34 |
43 |
44 |
53 |
54 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sticker_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/sticker_source_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/test_compress_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
12 |
17 |
18 |
23 |
24 |
28 |
29 |
33 |
34 |
39 |
40 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/xfermode_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/xfermode_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
20 |
21 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #4677FF
4 | #4677FF
5 | #4677FF
6 |
7 | #4677FF
8 | #595D61
9 | #999
10 | #5000
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PictureEditor
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
24 |
25 |
35 |
36 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply from: 'https://coding.net/u/devlab/p/Resource/git/raw/master/android/project.gradle'
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | google()
7 | }
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.0.1'
10 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | jcenter()
17 | google()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/freeline.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # -*- coding:utf-8 -*-
3 | from __future__ import print_function
4 | import sys
5 | from argparse import ArgumentParser
6 |
7 | from freeline_core.dispatcher import Dispatcher
8 | from freeline_core.init import init
9 |
10 |
11 | class Freeline(object):
12 | def __init__(self):
13 | self.dispatcher = Dispatcher()
14 |
15 | def call(self, args=None):
16 | if 'init' in args and args.init:
17 | print('init freeline project...')
18 | init()
19 | exit()
20 |
21 | self.dispatcher.call_command(args)
22 |
23 |
24 | def get_parser():
25 | parser = ArgumentParser()
26 | parser.add_argument('-v', '--version', action='store_true', help='show version')
27 | parser.add_argument('-f', '--cleanBuild', action='store_true', help='force to execute a clean build')
28 | parser.add_argument('-w', '--wait', action='store_true', help='make application wait for debugger')
29 | parser.add_argument('-a', '--all', action='store_true',
30 | help="together with '-f', freeline will force to clean build all projects.")
31 | parser.add_argument('-c', '--clean', action='store_true', help='clean cache directory and workspace')
32 | parser.add_argument('-d', '--debug', action='store_true', help='show freeline debug output (NOT DEBUG APPLICATION)')
33 | # parser.add_argument('-i', '--init', action='store_true', help='init freeline project')
34 | parser.parse_args()
35 | return parser
36 |
37 |
38 | def main():
39 | if sys.version_info > (3, 0):
40 | print('Freeline only support Python 2.7+ now. Please use the correct version of Python for freeline.')
41 | exit()
42 |
43 | parser = get_parser()
44 | args = parser.parse_args()
45 | freeline = Freeline()
46 | freeline.call(args=args)
47 |
48 |
49 | if __name__ == '__main__':
50 | main()
51 |
--------------------------------------------------------------------------------
/freeline_project_description.json:
--------------------------------------------------------------------------------
1 | {
2 | "android_gradle_plugin_version": "2.3.2",
3 | "apk_path": "/Users/march/AndroidPro/PictureEditor/app/build/outputs/apk/app-debug.apk",
4 | "apt": {
5 | "app": {
6 | "aptArgs": [
7 |
8 | ],
9 | "aptOutput": "/Users/march/AndroidPro/PictureEditor/app/build/generated/source/apt/debug",
10 | "disableDiscovery": false,
11 | "enabled": true,
12 | "processor": null,
13 | "processorPath": "/Users/march/AndroidPro/PictureEditor/piceditor/build/intermediates/bundles/default/classes.jar:/Users/march/.android/build-cache/5150678634f6d791fce25c6b5bb70920dfa2546b/output/jars/classes.jar:/Users/march/.android/build-cache/0924ec50a12bdba23626fb127a060c8514db39f9/output/jars/classes.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife-annotations/8.4.0/ea392375cf9ff59234a82e7928a204215ccc98cd/butterknife-annotations-8.4.0.jar:/Users/march/.gradle/caches/modules-2/files-2.1/org.greenrobot/eventbus/3.0.0/ddd99896e9569eaababbe81b35d80e1b91c4ad85/eventbus-3.0.0.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.github.bumptech.glide/glide/3.7.0/9e9eeaf9948ee4d6c3ab354e8dc14368f16994a4/glide-3.7.0.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.google.code.gson/gson/2.4/695b63d702f505b9b916e02272e3b6381bade7f/gson-2.4.jar:/Users/march/.android/build-cache/6308b03f08b74faac27d27678ebe2f51e8b8966b/output/jars/classes.jar:/Users/march/.android/build-cache/0140e4f66449084687b976372f645c670ef2238c/output/jars/classes.jar:/Users/march/.android/build-cache/70607efa52fdb6f890053106abf0eaecf57c9f83/output/jars/classes.jar:/Users/march/.android/build-cache/a633643419dbaaef592078e9e124bdc1c9cc5bc5/output/jars/classes.jar:/Users/march/.gradle/caches/modules-2/files-2.1/io.reactivex.rxjava2/rxjava/2.1.0/2fdf84dedcaaeabb9d70cde9dbb8aad4eccb80a1/rxjava-2.1.0.jar:/Users/march/.gradle/caches/modules-2/files-2.1/org.reactivestreams/reactive-streams/1.0.0/14b8c877d98005ba3941c9257cfe09f6ed0e0d74/reactive-streams-1.0.0.jar:/Users/march/AndroidPro/PictureEditor/lowpoly/build/intermediates/bundles/default/classes.jar:/Users/march/.android/build-cache/b6cc6fc5f3ea993357ca5f5b8369834a3a52b6a9/output/jars/classes.jar:/Users/march/.android/build-cache/53e92ff6b102889c1b5bf1945aad7e2cea39fe09/output/jars/classes.jar:/Users/march/.android/build-cache/9f299bf1ea50c9cef60a463cdfc8d57f021a31fb/output/jars/classes.jar:/Users/march/.android/build-cache/83c9c963d783db053c208c48465554c89c6a2e58/output/jars/classes.jar:/Users/march/.android/build-cache/f8b7cfdaeb67d8289d33984359f84a0dd9297566/output/jars/classes.jar:/Users/march/.android/build-cache/f8b7cfdaeb67d8289d33984359f84a0dd9297566/output/jars/libs/internal_impl-24.2.0.jar:/Users/march/.android/build-cache/117b27f4f6074322b9c90759c411d4ab21a04201/output/jars/classes.jar:/Users/march/.android/build-cache/117b27f4f6074322b9c90759c411d4ab21a04201/output/jars/libs/internal_impl-24.2.0.jar:/Users/march/.android/build-cache/c79bc2b8046fa79e76f718341ca1949a361c0b6e/output/jars/classes.jar:/Users/march/.android/build-cache/c79bc2b8046fa79e76f718341ca1949a361c0b6e/output/jars/libs/internal_impl-24.2.0.jar:/Users/march/.android/build-cache/9e4474b8eabae3114d13832e4607c1146f424391/output/jars/classes.jar:/Users/march/.android/build-cache/9e4474b8eabae3114d13832e4607c1146f424391/output/jars/libs/internal_impl-24.2.0.jar:/Users/march/.android/build-cache/39d556e3af7f0a7fd1eb9f36d4715a66337a382b/output/jars/classes.jar:/Users/march/.android/build-cache/39d556e3af7f0a7fd1eb9f36d4715a66337a382b/output/jars/libs/internal_impl-24.2.0.jar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-annotations/24.2.0/support-annotations-24.2.0.jar:/Users/march/.android/build-cache/19c02da4ca4d34f50710f3976879b12dba83ae15/output/jars/classes.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife-compiler/8.4.0/22f40cd3f01849c6deeab0a755d2082b2624581/butterknife-compiler-8.4.0.jar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/design/24.2.0/design-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/appcompat-v7/24.2.0/appcompat-v7-24.2.0.aar:/Users/march/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife/8.4.0/6c39334929311ff90a06c67ca310db1342fe2b6a/butterknife-8.4.0.aar:/Users/march/AndroidPro/PictureEditor/piceditor/build/outputs/aar/piceditor-release.aar:/Users/march/.gradle/caches/modules-2/files-2.1/com.google.auto/auto-common/0.6/cf7212b0f8bfef12657b942df8f4f2cf032d3f41/auto-common-0.6.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.google.auto.service/auto-service/1.0-rc2/51033a5b8fcf7039159e35b6878f106ccd5fb35f/auto-service-1.0-rc2.jar:/Users/march/.gradle/caches/modules-2/files-2.1/com.squareup/javapoet/1.7.0/4fdcf1fc27c1a8f55d1109df986c923152f07759/javapoet-1.7.0.jar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-v4/24.2.0/support-v4-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/recyclerview-v7/24.2.0/recyclerview-v7-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-vector-drawable/24.2.0/support-vector-drawable-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/animated-vector-drawable/24.2.0/animated-vector-drawable-24.2.0.aar:/Users/march/.m2/repository/com/github/chendongMarch/devKit/0.0.4-beta1/devKit-0.0.4-beta1.aar:/Users/march/AndroidPro/PictureEditor/lowpoly/build/outputs/aar/lowpoly-release.aar:/Users/march/.gradle/caches/modules-2/files-2.1/com.google.guava/guava/18.0/cce0823396aa693798f8882e64213b1772032b09/guava-18.0.jar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-compat/24.2.0/support-compat-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-core-utils/24.2.0/support-core-utils-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-media-compat/24.2.0/support-media-compat-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-core-ui/24.2.0/support-core-ui-24.2.0.aar:/Users/march/AndroidRes/sdk/extras/android/m2repository/com/android/support/support-fragment/24.2.0/support-fragment-24.2.0.aar:/Users/march/.m2/repository/com/github/chendongMarch/lightadapter/0.0.1-beta5/lightadapter-0.0.1-beta5.aar:/Users/march/.gradle/caches/modules-2/files-2.1/io.reactivex.rxjava2/rxandroid/2.0.1/c192035f52624f35143cadfc9d5832cd621319eb/rxandroid-2.0.1.aar"
14 | }
15 | },
16 | "apt_libraries": {
17 | "dagger": false,
18 | "butterknife": true
19 | },
20 | "auto_dependency": true,
21 | "build_cache_dir": "/Users/march/AndroidPro/PictureEditor/app/build/freeline",
22 | "build_directory": "/Users/march/AndroidPro/PictureEditor/app/build",
23 | "build_script": "./gradlew :app:assembleDebug",
24 | "build_script_work_directory": "",
25 | "build_tools_directory": "/Users/march/AndroidRes/sdk/build-tools/25.0.3",
26 | "build_tools_version": "25.0.3",
27 | "check_sources_md5": [
28 |
29 | ],
30 | "compile_sdk_directory": "/Users/march/AndroidRes/sdk/platforms/android-25",
31 | "compile_sdk_version": "android-25",
32 | "databinding": [
33 |
34 | ],
35 | "databinding_compiler_jar": "",
36 | "databinding_modules": [
37 |
38 | ],
39 | "debug_package": "com.march.picedit",
40 | "exclude_dep_res_paths": [
41 |
42 | ],
43 | "extra_dep_res_paths": [
44 |
45 | ],
46 | "freeline_cache_dir": "/Users/march/AndroidPro/PictureEditor",
47 | "freeline_gradle_plugin_version": "0.8.7",
48 | "ignore_resource_ids": [
49 | "avd_hide_password_1",
50 | "avd_hide_password_2",
51 | "avd_hide_password_3",
52 | "avd_show_password_1",
53 | "avd_show_password_2",
54 | "avd_show_password_3"
55 | ],
56 | "java_home": "/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home",
57 | "launcher": "com.march.picedit.MainActivity",
58 | "main_assets_directory": [
59 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/assets",
60 | "/Users/march/AndroidPro/PictureEditor/app/src/main/assets"
61 | ],
62 | "main_jniLibs_directory": [
63 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/jniLibs",
64 | "/Users/march/AndroidPro/PictureEditor/app/src/main/jniLibs"
65 | ],
66 | "main_jni_directory": [
67 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/jni",
68 | "/Users/march/AndroidPro/PictureEditor/app/src/main/jni"
69 | ],
70 | "main_manifest_path": "/Users/march/AndroidPro/PictureEditor/app/src/main/AndroidManifest.xml",
71 | "main_project_dir": "app",
72 | "main_project_name": "app",
73 | "main_r_path": "/Users/march/AndroidPro/PictureEditor/app/build/generated/source/r/debug/R.java",
74 | "main_res_directory": [
75 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/res",
76 | "/Users/march/AndroidPro/PictureEditor/app/src/main/res"
77 | ],
78 | "main_src_directory": [
79 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/java",
80 | "/Users/march/AndroidPro/PictureEditor/app/src/main/java"
81 | ],
82 | "module_dependencies": {
83 | "app": [
84 | "piceditor"
85 | ],
86 | "lowpoly": [
87 |
88 | ],
89 | "piceditor": [
90 | "lowpoly"
91 | ]
92 | },
93 | "modules": [
94 | {
95 | "name": "app",
96 | "path": "/Users/march/AndroidPro/PictureEditor/app"
97 | },
98 | {
99 | "name": "piceditor",
100 | "path": "/Users/march/AndroidPro/PictureEditor/piceditor"
101 | },
102 | {
103 | "name": "lowpoly",
104 | "path": "/Users/march/AndroidPro/PictureEditor/lowpoly"
105 | }
106 | ],
107 | "package": "com.march.picedit",
108 | "product_flavor": "",
109 | "project_source_sets": {
110 | "app": {
111 | "main_assets_directory": [
112 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/assets",
113 | "/Users/march/AndroidPro/PictureEditor/app/src/main/assets"
114 | ],
115 | "main_jniLibs_directory": [
116 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/jniLibs",
117 | "/Users/march/AndroidPro/PictureEditor/app/src/main/jniLibs"
118 | ],
119 | "main_jni_directory": [
120 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/jni",
121 | "/Users/march/AndroidPro/PictureEditor/app/src/main/jni"
122 | ],
123 | "main_manifest_path": "/Users/march/AndroidPro/PictureEditor/app/src/main/AndroidManifest.xml",
124 | "main_res_directory": [
125 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/res",
126 | "/Users/march/AndroidPro/PictureEditor/app/src/main/res"
127 | ],
128 | "main_src_directory": [
129 | "/Users/march/AndroidPro/PictureEditor/app/src/debug/java",
130 | "/Users/march/AndroidPro/PictureEditor/app/src/main/java"
131 | ]
132 | },
133 | "lowpoly": {
134 | "main_assets_directory": [
135 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/release/assets",
136 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/assets"
137 | ],
138 | "main_jniLibs_directory": [
139 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/release/jniLibs",
140 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/jniLibs"
141 | ],
142 | "main_jni_directory": [
143 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/release/jni",
144 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/jni"
145 | ],
146 | "main_manifest_path": "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/AndroidManifest.xml",
147 | "main_res_directory": [
148 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/release/res",
149 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/res"
150 | ],
151 | "main_src_directory": [
152 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/release/java",
153 | "/Users/march/AndroidPro/PictureEditor/lowpoly/src/main/java"
154 | ]
155 | },
156 | "piceditor": {
157 | "main_assets_directory": [
158 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/release/assets",
159 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/assets"
160 | ],
161 | "main_jniLibs_directory": [
162 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/release/jniLibs",
163 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/jniLibs"
164 | ],
165 | "main_jni_directory": [
166 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/release/jni",
167 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/jni"
168 | ],
169 | "main_manifest_path": "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/AndroidManifest.xml",
170 | "main_res_directory": [
171 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/release/res",
172 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/res"
173 | ],
174 | "main_src_directory": [
175 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/release/java",
176 | "/Users/march/AndroidPro/PictureEditor/piceditor/src/main/java"
177 | ]
178 | }
179 | },
180 | "project_type": "gradle",
181 | "retrolambda": {
182 |
183 | },
184 | "root_dir": "/Users/march/AndroidPro/PictureEditor",
185 | "sdk_directory": "/Users/march/AndroidRes/sdk",
186 | "use_jdk8": true,
187 | "use_system_gradle": false
188 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 23 17:30:09 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/lowpoly/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lowpoly/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def version = rootProject.ext.version
4 |
5 | android {
6 | compileSdkVersion version.compileSdkVersion
7 | sourceSets {
8 | //定义编译时编译文件的路径
9 | main {
10 | res.srcDirs = ['src/main/res']
11 | jniLibs.srcDirs = ['src/main/jniLibs']
12 | }
13 | }
14 | }
15 |
16 | dependencies {
17 | }
--------------------------------------------------------------------------------
/lowpoly/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in E:\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/lowpoly/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lowpoly/src/main/java/com/uniquestudio/lowpoly/LowPoly.java:
--------------------------------------------------------------------------------
1 | package com.uniquestudio.lowpoly;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Path;
7 | import android.util.Log;
8 |
9 | /**
10 | * Created by CoXier on 2016/9/14.
11 | */
12 | public class LowPoly {
13 | static {
14 | System.loadLibrary("lowpoly");
15 | }
16 |
17 | public static native int[] getTriangles(int[] pixels, int width, int height, int pointNum);
18 |
19 |
20 | /**
21 | * @param input
22 | * @param gradientThresh
23 | * @return low poly bitmap
24 | */
25 | public static Bitmap generate(Bitmap input, int gradientThresh) {
26 | int width = input.getWidth();
27 | int height = input.getHeight();
28 | Bitmap newImage = Bitmap.createBitmap(input.getWidth(), input.getHeight(), Bitmap.Config.ARGB_8888);
29 | Canvas canvas = new Canvas(newImage);
30 | Paint paint = new Paint();
31 | paint.setAntiAlias(false);
32 | paint.setStyle(Paint.Style.FILL);
33 | int x1, x2, x3, y1, y2, y3;
34 | int pixels[] = new int[width * height];
35 | input.getPixels(pixels,0,width,0,0,width,height);
36 | int[] triangles = getTriangles(pixels, width, height,gradientThresh);
37 | for (int i = 0; i < triangles.length; i = i + 6) {
38 | x1 = triangles[i];
39 | y1 = triangles[i + 1];
40 | x2 = triangles[i + 2];
41 | y2 = triangles[i + 3];
42 | x3 = triangles[i + 4];
43 | y3 = triangles[i + 5];
44 |
45 | int color = input.getPixel((x1 + x2 + x3) / 3, (y1 + y2 + y3) / 3);
46 | Path path = new Path();
47 | path.moveTo(x1, y1);
48 | path.lineTo(x2, y2);
49 | path.lineTo(x3, y3);
50 | path.close();
51 | paint.setColor(color);
52 | canvas.drawPath(path, paint);
53 | }
54 | return newImage;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lowpoly/src/main/jniLibs/armeabi-v7a/liblowpoly.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/lowpoly/src/main/jniLibs/armeabi-v7a/liblowpoly.so
--------------------------------------------------------------------------------
/lowpoly/src/main/jniLibs/armeabi/liblowpoly.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/lowpoly/src/main/jniLibs/armeabi/liblowpoly.so
--------------------------------------------------------------------------------
/lowpoly/src/main/jniLibs/x86/liblowpoly.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chendongMarch/ImageEditor/59a80fd78aa8fc03a38d8bc5e84d24a5d2bbcac5/lowpoly/src/main/jniLibs/x86/liblowpoly.so
--------------------------------------------------------------------------------
/lowpoly/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | LowPoly
3 |
4 |
--------------------------------------------------------------------------------
/piceditor/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/piceditor/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | def version = rootProject.ext.version
4 |
5 | android {
6 | compileSdkVersion version.compileSdkVersion
7 | }
8 |
9 | dependencies {
10 | compile project(':lowpoly')
11 | }
12 |
--------------------------------------------------------------------------------
/piceditor/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/march/AndroidRes/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.blur.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/piceditor/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/common/ClickChecker.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.common;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.model.PointF;
6 |
7 | /**
8 | * CreateAt : 7/22/17
9 | * Describe :
10 | * 对 touch event 进行是不是点击的检测
11 | *
12 | * @author chendong
13 | */
14 | public class ClickChecker {
15 |
16 | private long mLastDownTime;
17 | private PointF mLastDownPoint;
18 |
19 | public void onTouchDown(MotionEvent event) {
20 | mLastDownTime = System.currentTimeMillis();
21 | mLastDownPoint = new PointF(event.getX(), event.getY());
22 | }
23 |
24 |
25 | public boolean checkIsClickOnTouchUp(MotionEvent event) {
26 | long diffTime = System.currentTimeMillis() - mLastDownTime;
27 | float diffX = event.getX() - mLastDownPoint.x;
28 | float diffY = event.getY() - mLastDownPoint.y;
29 | return diffTime < 400 && Math.abs(diffX) < 50 && Math.abs(diffY) < 50;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/common/IDrawable.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.common;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 |
6 | /**
7 | * CreateAt : 7/21/17
8 | * Describe :
9 | *
10 | * @author chendong
11 | */
12 | public interface IDrawable {
13 | void onDraw(Canvas canvas, Paint paint);
14 | }
15 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/common/TouchHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.common;
2 |
3 | import android.view.MotionEvent;
4 |
5 | /**
6 | * CreateAt : 7/20/17
7 | * Describe : 触摸事件处理
8 | *
9 | * @author chendong
10 | */
11 | public interface TouchHandler {
12 |
13 | void onTouchDown(MotionEvent event);
14 |
15 | void onTouchMove(MotionEvent event);
16 | }
17 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/crop/gesture/CropBaseHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.crop.gesture;
2 |
3 | import android.graphics.RectF;
4 | import android.view.MotionEvent;
5 |
6 | /**
7 | * CreateAt : 7/18/17
8 | * Describe : 事件处理基类
9 | *
10 | * @author chendong
11 | */
12 | public abstract class CropBaseHandler {
13 |
14 | public static final int LEFT = 0;
15 | public static final int TOP = 1;
16 | public static final int RIGHT = 2;
17 | public static final int BOTTOM = 3;
18 | public static final int CENTER = 4;
19 |
20 | public static final int LEFT_TOP = 5;
21 | public static final int LEFT_BOTTOM = 6;
22 | public static final int RIGHT_TOP = 7;
23 | public static final int RIGHT_BOTTOM = 8;
24 |
25 | public static final int TWO_FINGER = 9;
26 |
27 | protected int mTouchRegion;
28 | protected int mWidth, mHeight;
29 | protected int mMinWidth, mMinHeight;
30 | protected RectF mCenterRectF;
31 | protected float mAspectRatio;
32 |
33 | public CropBaseHandler() {
34 | }
35 |
36 | public void init(int touchRegion, RectF centerRectF,
37 | int width, int height,
38 | int minWidth, int minHeight,
39 | float aspectRatio) {
40 | mTouchRegion = touchRegion;
41 | mCenterRectF = centerRectF;
42 | mWidth = width;
43 | mHeight = height;
44 | mMinWidth = minWidth;
45 | mMinHeight = minHeight;
46 | mAspectRatio = aspectRatio;
47 | }
48 |
49 | public abstract void onTouchDown(MotionEvent event);
50 |
51 | public abstract void onTouchMove(MotionEvent event);
52 | }
53 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/crop/gesture/impl/AspectRatioCropHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.crop.gesture.impl;
2 |
3 | import android.graphics.RectF;
4 | import android.view.MotionEvent;
5 |
6 | import com.march.piceditor.functions.crop.CropOverlayView;
7 | import com.march.piceditor.functions.crop.gesture.CropBaseHandler;
8 |
9 | /**
10 | * CreateAt : 7/18/17
11 | * Describe : 指定比例缩放处理
12 | *
13 | * @author chendong
14 | */
15 | // 触摸处理器的实现
16 | public class AspectRatioCropHandler extends CropBaseHandler {
17 |
18 | private float mLastX, mLastY;
19 |
20 |
21 | // 没有强制比例时的处理,此时会触发 edge trigger
22 | private void handleNoAspectRatioTriggerScale(float diffX, float diffY) {
23 | float newLeft = Math.min(mCenterRectF.right - mMinWidth, Math.max(0, mCenterRectF.left + diffX));
24 | float newTop = Math.min(mCenterRectF.bottom - mMinHeight, Math.max(0, mCenterRectF.top + diffY));
25 | float newRight = Math.max(mCenterRectF.left + mMinWidth, Math.min(mWidth, mCenterRectF.right + diffX));
26 | float newBottom = Math.max(mCenterRectF.top + mMinHeight, Math.min(mHeight, mCenterRectF.bottom + diffY));
27 |
28 | switch (mTouchRegion) {
29 | case LEFT:
30 | mCenterRectF.left = newLeft;
31 | break;
32 | case RIGHT:
33 | mCenterRectF.right = newRight;
34 | break;
35 | case TOP:
36 | mCenterRectF.top = newTop;
37 | break;
38 | case BOTTOM:
39 | mCenterRectF.bottom = newBottom;
40 | break;
41 | case LEFT_TOP:
42 | mCenterRectF.top = newTop;
43 | mCenterRectF.left = newLeft;
44 | break;
45 | case LEFT_BOTTOM:
46 | mCenterRectF.left = newLeft;
47 | mCenterRectF.bottom = newBottom;
48 | break;
49 | case RIGHT_TOP:
50 | mCenterRectF.right = newRight;
51 | mCenterRectF.top = newTop;
52 | break;
53 | case RIGHT_BOTTOM:
54 | mCenterRectF.right = newRight;
55 | mCenterRectF.bottom = newBottom;
56 | break;
57 | }
58 | }
59 |
60 | // 强制比例时的处理,此时不会触发 edge trigger
61 | private void handleAspectRatioTriggerScale(float diffX, float diffY) {
62 |
63 | float aspectNewTop;
64 | float aspectNewLeft;
65 | float aspectNewRight;
66 | float aspectNewBottom;
67 |
68 | switch (mTouchRegion) {
69 | case LEFT_TOP:
70 | aspectNewTop = mCenterRectF.top + ((diffX + diffY) / 2);
71 | aspectNewLeft = mCenterRectF.left + ((diffX + diffY) / 2) * mAspectRatio;
72 | if (aspectNewTop <= (mCenterRectF.bottom - mMinHeight)
73 | && aspectNewLeft <= (mCenterRectF.right - mMinWidth)) {
74 | if (aspectNewTop >= 0 && aspectNewLeft >= 0) {
75 | mCenterRectF.top = aspectNewTop;
76 | mCenterRectF.left = aspectNewLeft;
77 | }
78 | }
79 | break;
80 | case LEFT_BOTTOM:
81 | aspectNewLeft = mCenterRectF.left + ((diffX - diffY) / 2) * mAspectRatio;
82 | aspectNewBottom = mCenterRectF.bottom + (-diffX + diffY) / 2;
83 | if (aspectNewLeft <= (mCenterRectF.right - mMinWidth)
84 | && aspectNewBottom >= mCenterRectF.top + mMinHeight) {
85 | if (aspectNewLeft >= 0 && aspectNewBottom <= mHeight) {
86 | mCenterRectF.left = aspectNewLeft;
87 | mCenterRectF.bottom = aspectNewBottom;
88 | }
89 | }
90 | break;
91 | case RIGHT_TOP:
92 | aspectNewRight = mCenterRectF.right + ((diffX - diffY) / 2) * mAspectRatio;
93 | aspectNewTop = mCenterRectF.top + (-diffX + diffY) / 2;
94 | if (aspectNewRight >= mCenterRectF.left + mMinWidth
95 | && aspectNewTop <= mCenterRectF.bottom - mMinHeight) {
96 | if (aspectNewRight <= mWidth && aspectNewTop >= 0) {
97 | mCenterRectF.right = aspectNewRight;
98 | mCenterRectF.top = aspectNewTop;
99 | }
100 | }
101 | break;
102 | case RIGHT_BOTTOM:
103 | aspectNewRight = mCenterRectF.right + ((diffX + diffY) / 2) * mAspectRatio;
104 | aspectNewBottom = mCenterRectF.bottom + (diffX + diffY) / 2;
105 | if (aspectNewRight >= mCenterRectF.left + mMinWidth
106 | && aspectNewBottom >= (mCenterRectF.top + mMinHeight)) {
107 | if (aspectNewRight <= mWidth && aspectNewBottom <= mHeight) {
108 | mCenterRectF.right = aspectNewRight;
109 | mCenterRectF.bottom = aspectNewBottom;
110 | }
111 | }
112 | break;
113 | }
114 | }
115 |
116 | // 中间移动处理
117 | private void handleCenterTouchMove(float diffX, float diffY) {
118 | if (mTouchRegion == CENTER) {
119 | float newLeft = Math.max(0, mCenterRectF.left + diffX);
120 | float newTop = Math.max(0, mCenterRectF.top + diffY);
121 |
122 | if (newLeft + mCenterRectF.width() >= mWidth) {
123 | newLeft = mCenterRectF.left;
124 | }
125 | if (newTop + mCenterRectF.height() >= mHeight) {
126 | newTop = mCenterRectF.top;
127 | }
128 | RectF temp = new RectF(newLeft, newTop, newLeft + mCenterRectF.width(), newTop + mCenterRectF.height());
129 | mCenterRectF.set(temp);
130 | }
131 | }
132 |
133 | @Override
134 | public void onTouchDown(MotionEvent event) {
135 | mLastX = event.getX();
136 | mLastY = event.getY();
137 | }
138 |
139 | @Override
140 | public void onTouchMove(MotionEvent event) {
141 |
142 | float diffX = event.getX() - mLastX;
143 | float diffY = event.getY() - mLastY;
144 | mLastX = event.getX();
145 | mLastY = event.getY();
146 |
147 | if (mTouchRegion == CENTER) {
148 | handleCenterTouchMove(diffX, diffY);
149 | } else if (mAspectRatio == CropOverlayView.NO_ASPECT_RATIO) {
150 | handleNoAspectRatioTriggerScale(diffX, diffY);
151 | } else {
152 | handleAspectRatioTriggerScale(diffX, diffY);
153 | }
154 | }
155 | }
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/crop/gesture/impl/MoveHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.crop.gesture.impl;
2 |
3 | import android.graphics.RectF;
4 | import android.view.MotionEvent;
5 |
6 | import com.march.piceditor.functions.crop.gesture.CropBaseHandler;
7 |
8 | /**
9 | * CreateAt : 7/18/17
10 | * Describe :
11 | *
12 | * @author chendong
13 | */
14 | // 触摸处理器的实现
15 | public class MoveHandler extends CropBaseHandler {
16 |
17 | private float mLastX, mLastY;
18 |
19 | // 中间移动处理
20 | private void handleCenterTouchMove(float diffX, float diffY) {
21 | if (mTouchRegion == CENTER) {
22 | float newLeft = Math.max(0, mCenterRectF.left + diffX);
23 | float newTop = Math.max(0, mCenterRectF.top + diffY);
24 |
25 | if (newLeft + mCenterRectF.width() >= mWidth) {
26 | newLeft = mCenterRectF.left;
27 | }
28 | if (newTop + mCenterRectF.height() >= mHeight) {
29 | newTop = mCenterRectF.top;
30 | }
31 | RectF temp = new RectF(newLeft, newTop, newLeft + mCenterRectF.width(), newTop + mCenterRectF.height());
32 | mCenterRectF.set(temp);
33 | }
34 | }
35 |
36 | @Override
37 | public void onTouchDown(MotionEvent event) {
38 | mLastX = event.getX();
39 | mLastY = event.getY();
40 | }
41 |
42 | @Override
43 | public void onTouchMove(MotionEvent event) {
44 | float diffX = event.getX() - mLastX;
45 | float diffY = event.getY() - mLastY;
46 | mLastX = event.getX();
47 | mLastY = event.getY();
48 | handleCenterTouchMove(diffX, diffY);
49 | }
50 | }
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/crop/gesture/impl/NoAspectRatioCropHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.crop.gesture.impl;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.functions.crop.gesture.CropBaseHandler;
6 |
7 | /**
8 | * CreateAt : 7/18/17
9 | * Describe : 不指定比例缩放
10 | *
11 | * @author chendong
12 | */
13 | // 触摸处理器的实现
14 | public class NoAspectRatioCropHandler extends CropBaseHandler {
15 |
16 | private float mLastX, mLastY;
17 |
18 | // 没有强制比例时的处理,此时会触发 edge trigger
19 | private void handleNoAspectRatioTriggerScale(float diffX, float diffY) {
20 |
21 | float newLeft = Math.min(mCenterRectF.right - mMinWidth, Math.max(0, mCenterRectF.left + diffX));
22 | float newTop = Math.min(mCenterRectF.bottom - mMinHeight, Math.max(0, mCenterRectF.top + diffY));
23 | float newRight = Math.max(mCenterRectF.left + mMinWidth, Math.min(mWidth, mCenterRectF.right + diffX));
24 | float newBottom = Math.max(mCenterRectF.top + mMinHeight, Math.min(mHeight, mCenterRectF.bottom + diffY));
25 |
26 | switch (mTouchRegion) {
27 | case LEFT:
28 | mCenterRectF.left = newLeft;
29 | break;
30 | case RIGHT:
31 | mCenterRectF.right = newRight;
32 | break;
33 | case TOP:
34 | mCenterRectF.top = newTop;
35 | break;
36 | case BOTTOM:
37 | mCenterRectF.bottom = newBottom;
38 | break;
39 | case LEFT_TOP:
40 | mCenterRectF.top = newTop;
41 | mCenterRectF.left = newLeft;
42 | break;
43 | case LEFT_BOTTOM:
44 | mCenterRectF.left = newLeft;
45 | mCenterRectF.bottom = newBottom;
46 | break;
47 | case RIGHT_TOP:
48 | mCenterRectF.right = newRight;
49 | mCenterRectF.top = newTop;
50 | break;
51 | case RIGHT_BOTTOM:
52 | mCenterRectF.right = newRight;
53 | mCenterRectF.bottom = newBottom;
54 | break;
55 | }
56 | }
57 |
58 |
59 | @Override
60 | public void onTouchDown(MotionEvent event) {
61 | mLastX = event.getX();
62 | mLastY = event.getY();
63 | }
64 |
65 | @Override
66 | public void onTouchMove(MotionEvent event) {
67 | float diffX = event.getX() - mLastX;
68 | float diffY = event.getY() - mLastY;
69 | mLastX = event.getX();
70 | mLastY = event.getY();
71 | handleNoAspectRatioTriggerScale(diffX, diffY);
72 | }
73 |
74 |
75 | }
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/crop/gesture/impl/TwoFingerHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.crop.gesture.impl;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.functions.crop.gesture.CropBaseHandler;
6 | import com.march.piceditor.utils.CalculateUtils;
7 |
8 | /**
9 | * CreateAt : 7/18/17
10 | * Describe : 双指缩放事件处理
11 | *
12 | * @author chendong
13 | */
14 | public class TwoFingerHandler extends CropBaseHandler {
15 |
16 | private float mLastFingersDistance;
17 |
18 | @Override
19 | public void onTouchDown(MotionEvent event) {
20 | if (event.getPointerCount() == 2) {
21 | mLastFingersDistance = CalculateUtils.calculateDistance(event);
22 | }
23 | }
24 |
25 | @Override
26 | public void onTouchMove(MotionEvent event) {
27 | if (event.getPointerCount() == 2 && mLastFingersDistance > 0) {
28 | float distance = CalculateUtils.calculateDistance(event);
29 | if (mLastFingersDistance != 0) {
30 | float scale = distance * 1f / mLastFingersDistance;
31 | scaleRect(scale);
32 | }
33 | mLastFingersDistance = distance;
34 | }
35 | }
36 |
37 | private void scaleRect(float scale) {
38 |
39 | float centerX = mCenterRectF.left + mCenterRectF.width() / 2;
40 | float centerY = mCenterRectF.top + mCenterRectF.height() / 2;
41 |
42 | float newWidth = mCenterRectF.width() * scale;
43 | float newHeight = mCenterRectF.height() * scale;
44 |
45 | float left = centerX - newWidth / 2;
46 | float top = centerY - newHeight / 2;
47 | float right = left + newWidth;
48 | float bottom = top + newHeight;
49 |
50 | if (left >= 0 && top >= 0 && right <= mWidth && bottom <= mHeight) {
51 | if (newWidth >= mMinWidth && newHeight >= mMinHeight) {
52 | mCenterRectF.set(left, top, left + newWidth, top + newHeight);
53 | }
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/graffiti/GraffitiLayerConfig.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.graffiti;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Color;
6 |
7 | import com.march.piceditor.utils.Blur;
8 | import com.march.piceditor.utils.GraffitiUtils;
9 | import com.uniquestudio.lowpoly.LowPoly;
10 |
11 | import static com.march.piceditor.functions.graffiti.GraffitiLayerConfig.GraffitiEffect.BLUR;
12 | import static com.march.piceditor.functions.graffiti.GraffitiLayerConfig.GraffitiEffect.COLOR;
13 | import static com.march.piceditor.functions.graffiti.GraffitiLayerConfig.GraffitiEffect.IMAGE;
14 | import static com.march.piceditor.functions.graffiti.GraffitiLayerConfig.GraffitiEffect.LOW_POLY;
15 | import static com.march.piceditor.functions.graffiti.GraffitiLayerConfig.GraffitiEffect.MOSAIC;
16 |
17 | /**
18 | * CreateAt : 7/25/17
19 | * Describe : 绘制涂层样式
20 | * 纯色/颜色
21 | * 方形马赛克/方格大小
22 | * 图片/bitmap
23 | * 高斯模糊/模糊半径
24 | * poly/
25 | * @author chendong
26 | */
27 | public class GraffitiLayerConfig {
28 |
29 | enum GraffitiEffect {
30 | COLOR, MOSAIC, IMAGE, BLUR, LOW_POLY
31 | }
32 |
33 | public static final int DEF_VALUE = -1;
34 |
35 | private GraffitiEffect mGraffitiEffect = MOSAIC;
36 | private int mColor = Color.TRANSPARENT;
37 | private int mMosaicGridWidth = 10;
38 | private int mGradientThresh = 40;
39 | private Bitmap mImageBitmap = null;
40 | private int mBlurRadius = Blur.BlurFactor.DEFAULT_RADIUS;
41 |
42 | private GraffitiLayerConfig(GraffitiEffect graffitiEffect) {
43 | mGraffitiEffect = graffitiEffect;
44 | }
45 |
46 | public static GraffitiLayerConfig newColorLayer(int color) {
47 | // 7s cost
48 | GraffitiLayerConfig graffitiLayer = new GraffitiLayerConfig(COLOR);
49 | graffitiLayer.setColor(color);
50 | return graffitiLayer;
51 | }
52 |
53 | public static GraffitiLayerConfig newMosaicLayer(int mosaicGridWidth) {
54 | GraffitiLayerConfig graffitiLayer = new GraffitiLayerConfig(MOSAIC);
55 | graffitiLayer.setMosaicGridWidth(mosaicGridWidth);
56 | return graffitiLayer;
57 | }
58 |
59 | public static GraffitiLayerConfig newBlurLayer(int blurRadius) {
60 | GraffitiLayerConfig graffitiLayer = new GraffitiLayerConfig(BLUR);
61 | graffitiLayer.setBlurRadius(blurRadius);
62 | return graffitiLayer;
63 | }
64 |
65 | public static GraffitiLayerConfig newImageLayer(Bitmap bitmap) {
66 | GraffitiLayerConfig graffitiLayer = new GraffitiLayerConfig(IMAGE);
67 | graffitiLayer.setImageBitmap(bitmap);
68 | return graffitiLayer;
69 | }
70 |
71 | public static GraffitiLayerConfig newLowPolyLayer(int gradientThresh) {
72 | GraffitiLayerConfig graffitiLayer = new GraffitiLayerConfig(LOW_POLY);
73 | graffitiLayer.setMosaicGridWidth(gradientThresh);
74 | return graffitiLayer;
75 | }
76 |
77 |
78 | Bitmap buildLayer(Context context, Bitmap srcBitmap) {
79 |
80 | if (srcBitmap == null || srcBitmap.getWidth() == 0 || srcBitmap.getHeight() == 0)
81 | return null;
82 |
83 | if (mGraffitiEffect == MOSAIC) {
84 | // mosaic 15s cost
85 | return GraffitiUtils.getMosaicBitmap(srcBitmap, mMosaicGridWidth);
86 | } else if (mGraffitiEffect == GraffitiEffect.BLUR) {
87 | // blur 45s cost
88 | return GraffitiUtils.getBlurBitmap(context, srcBitmap, mBlurRadius);
89 | } else if (mGraffitiEffect == GraffitiEffect.COLOR) {
90 | // pure color
91 | return GraffitiUtils.getColorBitmap(srcBitmap, mColor);
92 | } else if (mGraffitiEffect == GraffitiEffect.IMAGE) {
93 | // image 0s cost
94 | return GraffitiUtils.getCenterCropBitmap(srcBitmap, mImageBitmap);
95 | } else if (mGraffitiEffect == GraffitiEffect.LOW_POLY) {
96 | // low poly 480s cost
97 | return LowPoly.generate(srcBitmap, mGradientThresh);
98 | }
99 | return null;
100 | }
101 |
102 |
103 | private void setColor(int color) {
104 | if (color != DEF_VALUE)
105 | mColor = color;
106 | }
107 |
108 | private void setMosaicGridWidth(int mosaicGridWidth) {
109 | if (mosaicGridWidth != DEF_VALUE)
110 | mMosaicGridWidth = mosaicGridWidth;
111 | }
112 |
113 | private void setImageBitmap(Bitmap imageBitmap) {
114 | mImageBitmap = imageBitmap;
115 | }
116 |
117 | private void setBlurRadius(int blurRadius) {
118 | if (blurRadius != DEF_VALUE)
119 | mBlurRadius = blurRadius;
120 | }
121 |
122 | public void setGradientThresh(int gradientThresh) {
123 | if (gradientThresh != DEF_VALUE)
124 | mGradientThresh = gradientThresh;
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/graffiti/GraffitiOverlayView.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.graffiti;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.CornerPathEffect;
9 | import android.graphics.Paint;
10 | import android.graphics.PorterDuff;
11 | import android.graphics.PorterDuffXfermode;
12 | import android.graphics.RectF;
13 |
14 | import android.util.AttributeSet;
15 | import android.view.MotionEvent;
16 | import android.view.View;
17 |
18 | import com.march.piceditor.utils.BitmapUtils;
19 | import com.march.piceditor.utils.DrawUtils;
20 | import com.march.piceditor.model.PointF;
21 | import com.march.piceditor.functions.graffiti.model.TouchPartHolder;
22 |
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | /**
27 | * CreateAt : 7/25/17
28 | * Describe :
29 | * 涂鸦控件
30 | * 1. 支持 矩形选中、手指滑动选中 区域
31 | * 2. 支持涂抹和擦除
32 | * 3. 支持多层涂鸦相互覆盖
33 | * 4. 支持 纯色,高斯模糊,马赛克,图片,poly 等涂鸦样式,可扩展
34 | *
35 | * @author chendong
36 | */
37 | public class GraffitiOverlayView extends View {
38 |
39 | public static final String TAG = GraffitiOverlayView.class.getSimpleName();
40 |
41 | public GraffitiOverlayView(Context context) {
42 | this(context, null);
43 | }
44 |
45 | public GraffitiOverlayView(Context context, AttributeSet attrs) {
46 | this(context, attrs, 0);
47 | }
48 |
49 | public GraffitiOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
50 | super(context, attrs, defStyleAttr);
51 | init();
52 | }
53 |
54 | // 触摸的效果,矩形区域和路径
55 | public enum TouchMode {
56 | /**
57 | * 当前触摸绘制方式为矩形
58 | */
59 | RECT,
60 | /**
61 | * 当前触摸绘制方式为路径
62 | */
63 | PATH
64 | }
65 |
66 | private PorterDuffXfermode mSrcInXfermode;
67 | private PorterDuffXfermode mClearXfermode;
68 | private PorterDuffXfermode mSrcOverXfermode;
69 |
70 | private Paint mGraffitiLayerPaint;
71 | private Paint mTouchGraffitiPaint;
72 | private Paint mTouchPointPaint;
73 |
74 | private RectF mImageRect;
75 | private int mPathWidth;
76 | private float mImageWidth;
77 | private float mImageHeight;
78 | private boolean mIsTouching;
79 | private boolean mIsErase;
80 |
81 | private Bitmap mSourceImage;
82 |
83 | private TouchPartHolder mTouchPartHolder;
84 | private PointF mTouchPoint;
85 |
86 | private int mEraseColor = Color.WHITE;
87 | private int mDrawColor = Color.GRAY;
88 |
89 | private List mGraffitiLayers;
90 | private GraffitiLayer mGraffitiLayer;
91 |
92 | private TouchMode mTouchMode = TouchMode.PATH;
93 |
94 |
95 | // 每一层涂层
96 | private class GraffitiLayer {
97 |
98 | List mTouchPartHolders;
99 | Bitmap mGraffitiImage;
100 |
101 | GraffitiLayer(Bitmap bitmap) {
102 | mGraffitiImage = bitmap;
103 | mTouchPartHolders = new ArrayList<>();
104 | }
105 | }
106 |
107 |
108 | private void init() {
109 | // current touch paint
110 | mTouchGraffitiPaint = DrawUtils.newPaint(Color.WHITE, 10, Paint.Style.STROKE);
111 | mTouchGraffitiPaint.setPathEffect(new CornerPathEffect(10));
112 | DrawUtils.initRoundPaint(mTouchGraffitiPaint);
113 |
114 | // current touch paint
115 | mTouchPointPaint = DrawUtils.newPaint(Color.argb(0xdd, 0xff, 0xff, 0xff), 20, Paint.Style.FILL_AND_STROKE);
116 |
117 | // effect paint
118 | mGraffitiLayerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
119 | mGraffitiLayerPaint.setPathEffect(new CornerPathEffect(10));
120 | DrawUtils.initAntiAliasPaint(mGraffitiLayerPaint);
121 | DrawUtils.initRoundPaint(mGraffitiLayerPaint);
122 |
123 | mTouchPoint = new PointF();
124 | mTouchPoint.reset();
125 | mImageRect = new RectF();
126 | mPathWidth = 50;
127 | mSrcInXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
128 | mClearXfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
129 | mSrcOverXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);
130 | mGraffitiLayers = new ArrayList<>();
131 |
132 | setErase(false);
133 | }
134 |
135 | // 设置 src
136 | public void setSrc(String file) {
137 | BitmapFactory.Options bitmapSize = BitmapUtils.getBitmapSize(file);
138 | mImageWidth = bitmapSize.outWidth;
139 | mImageHeight = bitmapSize.outHeight;
140 | mSourceImage = BitmapFactory.decodeFile(file);
141 | requestLayout();
142 | postInvalidate();
143 | }
144 |
145 | // 设置涂抹 layer
146 | public void addGraffitiLayer(GraffitiLayerConfig graffitiLayer) {
147 | if (mSourceImage == null) {
148 | throw new IllegalArgumentException("init setSrc() first");
149 | }
150 | Bitmap mGraffitiImage = graffitiLayer.buildLayer(getContext(), mSourceImage);
151 | mGraffitiLayer = new GraffitiLayer(mGraffitiImage);
152 | mGraffitiLayers.add(mGraffitiLayer);
153 | postInvalidate();
154 | }
155 |
156 | // 设置涂抹的触摸方式
157 | public void setTouchMode(TouchMode touchMode) {
158 | mTouchMode = touchMode;
159 | }
160 |
161 | // 设置是不是擦除状态
162 | public void setErase(boolean erase) {
163 | mIsErase = erase;
164 | mTouchGraffitiPaint.setColor(erase ? mEraseColor : mDrawColor);
165 | }
166 |
167 | // 绘制和擦除时的颜色
168 | public void setEraseAndDrawColor(int eraseColor, int drawColor) {
169 | mEraseColor = eraseColor;
170 | mDrawColor = drawColor;
171 | }
172 |
173 | // 重置
174 | public void reset() {
175 | for (GraffitiLayer layer : mGraffitiLayers) {
176 | BitmapUtils.recycleBitmaps(mSourceImage, layer.mGraffitiImage);
177 | layer.mTouchPartHolders.clear();
178 | }
179 | }
180 |
181 |
182 | @Override
183 | public boolean onTouchEvent(MotionEvent event) {
184 | if (!isEnabled() || event.getPointerCount() > 1
185 | || mSourceImage == null
186 | || mGraffitiLayer == null) {
187 | return super.onTouchEvent(event);
188 | }
189 | switch (event.getActionMasked()) {
190 | case MotionEvent.ACTION_DOWN:
191 | mTouchPoint.set(event);
192 | mIsTouching = true;
193 | mTouchPartHolder = new TouchPartHolder(mIsErase, mTouchMode);
194 | mTouchPartHolder.onTouchDown(event, mPathWidth);
195 | mGraffitiLayer.mTouchPartHolders.add(mTouchPartHolder);
196 | if (mIsErase) {
197 | // 向其他涂层添加擦除路径
198 | for (GraffitiLayer layer : mGraffitiLayers) {
199 | if (!layer.equals(mGraffitiLayer)) {
200 | layer.mTouchPartHolders.add(mTouchPartHolder);
201 | }
202 | }
203 | }
204 | break;
205 | case MotionEvent.ACTION_MOVE:
206 | mTouchPoint.set(event);
207 | if (mTouchPartHolder != null) {
208 | mTouchPartHolder.onTouchMove(event);
209 | }
210 | break;
211 | case MotionEvent.ACTION_UP:
212 | mTouchPoint.reset();
213 | mIsTouching = false;
214 | mTouchPartHolder = null;
215 | break;
216 | default:
217 | break;
218 | }
219 | postInvalidate();
220 | return true;
221 | }
222 |
223 |
224 | @Override
225 | protected void onDraw(Canvas canvas) {
226 | super.onDraw(canvas);
227 | drawOnCanvas(canvas, false);
228 | }
229 |
230 | // 分两层绘制,source image & mosaic image
231 | // 1.初始设计(已弃用):
232 | // 马赛克层需要结合3部分,擦除路径,涂抹路径,涂鸦图层
233 | // 先绘制涂抹路径,然后使用 clear 模式绘制擦除路径,清除与涂抹路径重叠的部分,
234 | // 然后使用 srcIn 模式绘制涂鸦图层,绘制涂鸦图层与清除后的涂抹路径重合地方
235 | // 2.修复设计:
236 | // 擦除和涂抹在一个列表中,使用 clear mode 绘制擦除
237 | // 使用 src over mode 绘制涂抹
238 | // 最后使用 src in mode 绘制绘制涂层
239 | private void drawOnCanvas(Canvas canvas, boolean isSave) {
240 | try {
241 | if (mSourceImage == null || mImageRect == null) {
242 | return;
243 | }
244 |
245 | canvas.drawBitmap(mSourceImage, null, mImageRect, null);
246 |
247 | if (mSrcInXfermode == null || mClearXfermode == null || mGraffitiLayer == null) {
248 | return;
249 | }
250 |
251 | drawLayer(canvas);
252 |
253 | // 如果不是保存最终结果,需要将用户手势动态绘制出来
254 | if (!isSave) {
255 | if (mTouchPartHolder != null && mTouchPartHolder.getRectF() != null) {
256 | // mTouchPartHolder.onDraw(canvas, mTouchGraffitiPaint);
257 | canvas.drawRect(mTouchPartHolder.getRectF(), mTouchPointPaint);
258 | } else if (mTouchPoint.isValid()) {
259 | canvas.drawCircle(mTouchPoint.x, mTouchPoint.y, mPathWidth / 2, mTouchPointPaint);
260 | }
261 | }
262 | } catch (Exception e) {
263 | e.printStackTrace();
264 | }
265 | }
266 |
267 |
268 | // 绘制涂层
269 | private void drawLayer(Canvas canvas) {
270 |
271 | for (GraffitiLayer layer : mGraffitiLayers) {
272 |
273 | if (layer.mGraffitiImage == null) {
274 | continue;
275 | }
276 |
277 | int mosaicLayerCount = canvas.saveLayer(mImageRect, null, Canvas.ALL_SAVE_FLAG);
278 | {
279 | // Collections.sort(mTouchPartHolders);
280 | // 按照时间排序绘制,erase 的用 clear mode,否则用 src over mode
281 | for (TouchPartHolder graffitiPart : layer.mTouchPartHolders) {
282 | mGraffitiLayerPaint.setXfermode(graffitiPart.isErase() ? mClearXfermode : mSrcOverXfermode);
283 | graffitiPart.onDraw(canvas, mGraffitiLayerPaint);
284 | }
285 |
286 | // 使用 src in mode 绘制马赛克涂层
287 | mGraffitiLayerPaint.setXfermode(mSrcInXfermode);
288 | canvas.drawBitmap(layer.mGraffitiImage, null, mImageRect, mGraffitiLayerPaint);
289 |
290 | //最后将画笔去除Xfermode
291 | mGraffitiLayerPaint.setXfermode(null);
292 | canvas.restoreToCount(mosaicLayerCount);
293 | }
294 | }
295 | }
296 |
297 |
298 | @Override
299 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
300 | if (mImageWidth <= 0 || mImageHeight <= 0) {
301 | return;
302 | }
303 | int contentWidth = right - left;
304 | int contentHeight = bottom - top;
305 | float widthRatio = contentWidth / mImageWidth;
306 | float heightRatio = contentHeight / mImageHeight;
307 | float ratio = widthRatio < heightRatio ? widthRatio : heightRatio;
308 | int realWidth = (int) (mImageWidth * ratio);
309 | int realHeight = (int) (mImageHeight * ratio);
310 |
311 | int imageLeft = (contentWidth - realWidth) / 2;
312 | int imageTop = (contentHeight - realHeight) / 2;
313 | int imageRight = imageLeft + realWidth;
314 | int imageBottom = imageTop + realHeight;
315 | mImageRect.set(imageLeft, imageTop, imageRight, imageBottom);
316 | }
317 |
318 |
319 | /**
320 | * 生成带有涂鸦的 bitmap
321 | *
322 | * @return bit
323 | */
324 | public Bitmap save() {
325 |
326 | Bitmap bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
327 |
328 | Canvas canvas = new Canvas(bitmap);
329 |
330 | drawOnCanvas(canvas, true);
331 |
332 | canvas.save();
333 |
334 | return Bitmap.createBitmap(bitmap, ((int) mImageRect.left), ((int) mImageRect.top), ((int) mImageRect.width()), ((int) mImageRect.height()));
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/graffiti/model/TouchPartHolder.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.graffiti.model;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.Path;
6 | import android.graphics.RectF;
7 |
8 | import android.view.MotionEvent;
9 |
10 | import com.march.piceditor.functions.graffiti.GraffitiOverlayView;
11 |
12 | /**
13 | * CreateAt : 7/25/17
14 | * Describe :
15 | * 触摸之后保存触摸的位置,有两种类型
16 | * 1. 路径绘制(Path + PathWidth)
17 | * 2. 矩形区域绘制(Rect)
18 | *
19 | * @author chendong
20 | */
21 | public class TouchPartHolder implements Comparable {
22 |
23 | private Path mPath; // 当前绘制的路径
24 | private int mPathWidth; // 路径的宽度
25 | private RectF mRectF;
26 | private GraffitiOverlayView.TouchMode mTouchMode;
27 | private boolean mIsErase;
28 | private long mCreateTime;
29 |
30 |
31 | private float mRectInitX;
32 | private float mRectInitY;
33 |
34 | public TouchPartHolder(GraffitiOverlayView.TouchMode touchMode) {
35 | mTouchMode = touchMode;
36 | }
37 |
38 | public TouchPartHolder(boolean isErase, GraffitiOverlayView.TouchMode touchMode) {
39 | mTouchMode = touchMode;
40 | mIsErase = isErase;
41 | }
42 |
43 | // down 时初始化
44 | public void onTouchDown(MotionEvent event, int width) {
45 | if (mTouchMode == GraffitiOverlayView.TouchMode.PATH) {
46 | mPath = new Path();
47 | mPath.moveTo(event.getX(), event.getY());
48 | mPathWidth = width;
49 | } else if (mTouchMode == GraffitiOverlayView.TouchMode.RECT) {
50 | // mRectF = new RectF(event.getX(), event.getY(), event.getX(), event.getY());
51 | mRectF = new RectF();
52 | mRectInitX = event.getX();
53 | mRectInitY = event.getY();
54 | mRectF.set(mRectInitX, mRectInitY, mRectInitX, mRectInitY);
55 | }
56 | mCreateTime = System.currentTimeMillis();
57 | }
58 |
59 | // 移动时记录
60 | public void onTouchMove(MotionEvent event) {
61 | float x = event.getX();
62 | float y = event.getY();
63 | if (mTouchMode == GraffitiOverlayView.TouchMode.PATH) {
64 | mPath.lineTo(x, y);
65 | } else if (mTouchMode == GraffitiOverlayView.TouchMode.RECT) {
66 | // mRectF.right = event.getX();
67 | // mRectF.bottom = event.getY();
68 | if (x <= mRectInitX) {
69 | if(y <= mRectInitY){
70 | // 第1象限
71 | mRectF.set(x,y,mRectInitX,mRectInitY);
72 | }else {
73 | // 第3象限
74 | mRectF.set(x,mRectInitY,mRectInitX,y);
75 | }
76 | } else{
77 | if(y <= mRectInitY){
78 | // 第2象限
79 | mRectF.set(mRectInitX,y,x,mRectInitY);
80 | }else {
81 | // 第4象限
82 | mRectF.set(mRectInitX,mRectInitY,x,y);
83 | }
84 | }
85 | }
86 | }
87 |
88 | // 绘制
89 | public void onDraw(Canvas canvas, Paint paint) {
90 | if (mPath != null) {
91 | paint.setStyle(Paint.Style.STROKE);
92 | paint.setStrokeWidth(mPathWidth);
93 | canvas.drawPath(mPath, paint);
94 | } else if (mRectF != null) {
95 | paint.setStyle(Paint.Style.FILL);
96 | canvas.drawRect(mRectF, paint);
97 | }
98 | }
99 |
100 |
101 | public Path getPath() {
102 | return mPath;
103 | }
104 |
105 | public void setPath(Path path) {
106 | mPath = path;
107 | }
108 |
109 | public int getPathWidth() {
110 | return mPathWidth;
111 | }
112 |
113 | public void setPathWidth(int pathWidth) {
114 | mPathWidth = pathWidth;
115 | }
116 |
117 | public RectF getRectF() {
118 | return mRectF;
119 | }
120 |
121 | public void setRectF(RectF rectF) {
122 | mRectF = rectF;
123 | }
124 |
125 | public boolean isErase() {
126 | return mIsErase;
127 | }
128 |
129 | public void setErase(boolean erase) {
130 | mIsErase = erase;
131 | }
132 |
133 | @Override
134 | public String toString() {
135 | return "TouchPartHolder{" +
136 | ", mTouchMode=" + mTouchMode +
137 | ", mIsErase=" + mIsErase +
138 | ", mCreateTime=" + mCreateTime +
139 | '}';
140 | }
141 |
142 | @Override
143 | public int compareTo(TouchPartHolder o) {
144 | if (mCreateTime > o.mCreateTime) {
145 | return 1;
146 | } else if (mCreateTime < o.mCreateTime) {
147 | return -1;
148 | } else return 0;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/rotate/RotateFrameLayout.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.rotate;
2 |
3 | import android.animation.Animator;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.BitmapFactory;
7 | import android.graphics.Matrix;
8 |
9 |
10 |
11 | import android.util.AttributeSet;
12 | import android.view.animation.LinearInterpolator;
13 | import android.widget.FrameLayout;
14 |
15 | import com.march.piceditor.utils.BitmapUtils;
16 |
17 | /**
18 | * CreateAt : 7/18/17
19 | * Describe : 旋转图片
20 | *
21 | * @author chendong
22 | */
23 | public class RotateFrameLayout extends FrameLayout {
24 |
25 | public RotateFrameLayout(Context context) {
26 | super(context);
27 | }
28 |
29 | public RotateFrameLayout(Context context, AttributeSet attrs) {
30 | super(context, attrs);
31 | }
32 |
33 | public RotateFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
34 | super(context, attrs, defStyleAttr);
35 | }
36 |
37 | public static final int ANIM_DURATION = 200;
38 | public static final int FLIP_NO = 1;
39 | public static final int FLIP_YES = -1;
40 | public static final int ROTATE_LEVEL = 90;
41 |
42 | private boolean mIsInAnim;
43 |
44 | public void flipX() {
45 | if (mIsInAnim)
46 | return;
47 | animate().scaleX(-getScaleX())
48 | .setDuration(ANIM_DURATION)
49 | .setInterpolator(new LinearInterpolator())
50 | .start();
51 | }
52 |
53 | public void flipY() {
54 | if (mIsInAnim)
55 | return;
56 | animate().scaleY(-getScaleY())
57 | .setDuration(ANIM_DURATION)
58 | .setInterpolator(new LinearInterpolator())
59 | .start();
60 | }
61 |
62 | public void rotateRight() {
63 | if (mIsInAnim)
64 | return;
65 | animate().rotationBy(ROTATE_LEVEL)
66 | .setDuration(ANIM_DURATION)
67 | .setListener(new MyAnimatorListener())
68 | .setInterpolator(new LinearInterpolator())
69 | .start();
70 | }
71 |
72 |
73 | public void rotateLeft() {
74 | if (mIsInAnim)
75 | return;
76 | animate().rotationBy(-ROTATE_LEVEL)
77 | .setDuration(ANIM_DURATION)
78 | .setListener(new MyAnimatorListener())
79 | .setInterpolator(new LinearInterpolator())
80 | .start();
81 | }
82 |
83 | public boolean isFlipX() {
84 | return getScaleX() == FLIP_YES;
85 | }
86 |
87 | public boolean isFlipY() {
88 | return getScaleY() == FLIP_YES;
89 | }
90 |
91 | public float getRotate() {
92 | return getRotation();
93 | }
94 |
95 |
96 | public class MyAnimatorListener implements Animator.AnimatorListener {
97 | @Override
98 | public void onAnimationStart(Animator animation) {
99 | mIsInAnim = true;
100 | }
101 |
102 | @Override
103 | public void onAnimationEnd(Animator animation) {
104 | mIsInAnim = false;
105 | }
106 |
107 | @Override
108 | public void onAnimationCancel(Animator animation) {
109 | mIsInAnim = false;
110 | }
111 |
112 | @Override
113 | public void onAnimationRepeat(Animator animation) {
114 |
115 | }
116 | }
117 |
118 | public void reset() {
119 | setScaleX(1);
120 | setScaleY(1);
121 | setRotation(0);
122 | }
123 |
124 |
125 | public void resetWithAnimation() {
126 | animate().scaleX(1).scaleY(1).rotation(0)
127 | .setDuration(ANIM_DURATION)
128 | .setListener(new MyAnimatorListener())
129 | .setInterpolator(new LinearInterpolator())
130 | .start();
131 | }
132 |
133 |
134 | public boolean isNotOperate() {
135 | return getScaleX() == 1 && getScaleY() == 1 && getRotation() % 360 == 0;
136 | }
137 |
138 | public Bitmap rotateBitmap(String filePath) {
139 | Bitmap bitmap = BitmapFactory.decodeFile(filePath);
140 | Matrix matrix = new Matrix();
141 | matrix.postScale(getScaleX(), getScaleY());
142 | matrix.postRotate(getRotate());
143 | Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0,
144 | bitmap.getWidth(), bitmap.getHeight(), matrix, true);
145 | BitmapUtils.recycleBitmaps(bitmap);
146 | return newBitmap;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/EasyMenuHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Matrix;
5 |
6 | import com.march.piceditor.utils.BitmapUtils;
7 | import com.march.piceditor.functions.sticker.listener.StickerMenuHandler;
8 | import com.march.piceditor.functions.sticker.model.Sticker;
9 | import com.march.piceditor.functions.sticker.model.StickerMenu;
10 |
11 | /**
12 | * CreateAt : 7/22/17
13 | * Describe : 内置简单版本 menu
14 | *
15 | * @author chendong
16 | */
17 | public enum EasyMenuHandler implements StickerMenuHandler {
18 |
19 | // 隐藏贴纸
20 | HIDE_STICKER() {
21 | @Override
22 | public void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu) {
23 | sticker.setHidden(true);
24 | }
25 | },
26 | // 删除贴纸
27 | DELETE_STICKER() {
28 | @Override
29 | public void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu) {
30 | overlay.removeSticker(sticker);
31 | }
32 | },
33 | // 垂直翻转
34 | FLIP_VERTICAL() {
35 | @Override
36 | public void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu) {
37 | flip(1, -1, sticker);
38 | }
39 | },
40 | // 水平翻转
41 | FLIP_HORIZONTAL() {
42 | @Override
43 | public void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu) {
44 | flip(-1, 1, sticker);
45 | }
46 | },
47 |
48 | // 双向翻转
49 | FLIP_SKEW() {
50 | @Override
51 | public void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu) {
52 | flip(-1, -1, sticker);
53 | }
54 | };
55 |
56 | private static void flip(int sx, int sy, Sticker sticker) {
57 | Bitmap bitmap = sticker.getStickerImage();
58 | Matrix matrix = new Matrix();
59 | matrix.postScale(sx, sy);
60 | Bitmap bitmap1 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
61 | sticker.setStickerImage(bitmap1);
62 | BitmapUtils.recycleBitmaps(bitmap);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/gesture/StickerBaseTouchHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.gesture;
2 |
3 | import com.march.piceditor.common.TouchHandler;
4 | import com.march.piceditor.functions.sticker.model.Sticker;
5 |
6 | /**
7 | * CreateAt : 7/20/17
8 | * Describe :
9 | * 贴纸手势处理基类
10 | *
11 | * @author chendong
12 | */
13 | public abstract class StickerBaseTouchHandler implements TouchHandler {
14 |
15 | public static final int MOVE = 0;
16 | public static final int TWO_FINGER = 1;
17 | public static final int BOTTOM_RIGHT_CORNER = 2;
18 |
19 |
20 | protected Sticker mActiveSticker;
21 |
22 | public void init(Sticker activeSticker) {
23 | mActiveSticker = activeSticker;
24 | }
25 |
26 | protected boolean isHadStickerActive() {
27 | return mActiveSticker != null;
28 | }
29 | }
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/gesture/impl/BottomRightCornerHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.gesture.impl;
2 |
3 | import android.graphics.RectF;
4 | import android.view.MotionEvent;
5 |
6 | import com.march.piceditor.functions.sticker.gesture.StickerBaseTouchHandler;
7 | import com.march.piceditor.utils.CalculateUtils;
8 |
9 | /**
10 | * CreateAt : 7/20/17
11 | * Describe :
12 | * 右下角按钮拉动的缩放和旋转的事件
13 | *
14 | * @author chendong
15 | */
16 | public class BottomRightCornerHandler extends StickerBaseTouchHandler {
17 |
18 | private float mLastDistance;// 上一次触摸点距离贴纸中心距离
19 | private float mLastRotation;// 上一次触摸点旋转角度
20 |
21 | @Override
22 | public void onTouchDown(MotionEvent event) {
23 | if (event.getPointerCount() == 1 && isHadStickerActive()) {
24 | RectF rectF = mActiveSticker.getRectF();
25 | mLastDistance = CalculateUtils.calculateDistance(rectF.centerX(), rectF.centerY(), event.getX(), event.getY());
26 | mLastRotation = CalculateUtils.calculateRotation(rectF.centerX(), rectF.centerY(), event.getX(), event.getY());
27 | }
28 | }
29 |
30 | @Override
31 | public void onTouchMove(MotionEvent event) {
32 | if (event.getPointerCount() == 1
33 | && isHadStickerActive()
34 | && mLastDistance > 0) {
35 |
36 | RectF rectF = mActiveSticker.getRectF();
37 |
38 | float distance = CalculateUtils.calculateDistance(rectF.centerX(), rectF.centerY(), event.getX(), event.getY());
39 |
40 | float scale = distance * 1f / mLastDistance;
41 | // if (mActiveSticker.isCanScale(scale)) {
42 | mActiveSticker.postMatrixScale(scale, scale);
43 | // }
44 | mLastDistance = distance;
45 |
46 | // 旋转
47 | float rotation = CalculateUtils.calculateRotation(rectF.centerX(), rectF.centerY(), event.getX(), event.getY());
48 | mActiveSticker.postMatrixRotate(rotation - mLastRotation);
49 | mLastRotation = rotation;
50 | }
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/gesture/impl/MoveHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.gesture.impl;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.functions.sticker.gesture.StickerBaseTouchHandler;
6 |
7 | /**
8 | * CreateAt : 7/20/17
9 | * Describe : 贴纸跟随手指移动
10 | *
11 | * @author chendong
12 | */
13 | public class MoveHandler extends StickerBaseTouchHandler {
14 |
15 | private float mInitX, mInitY;
16 |
17 | @Override
18 | public void onTouchDown(MotionEvent event) {
19 | if (event.getPointerCount() == 1 && isHadStickerActive()) {
20 | mInitX = event.getX();
21 | mInitY = event.getY();
22 | }
23 | }
24 |
25 | @Override
26 | public void onTouchMove(MotionEvent event) {
27 | if(event.getPointerCount() == 1
28 | && isHadStickerActive()
29 | && mInitX>0&&mInitY>0) {
30 | float diffX = event.getX() - mInitX;
31 | float diffY = event.getY() - mInitY;
32 | if (mActiveSticker!=null && mActiveSticker.getMatrix()!=null) {
33 | // 位移
34 | mActiveSticker.getMatrix().postTranslate(diffX, diffY);
35 | }
36 | mInitX = event.getX();
37 | mInitY = event.getY();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/gesture/impl/TwoFingersHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.gesture.impl;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.functions.sticker.gesture.StickerBaseTouchHandler;
6 | import com.march.piceditor.utils.CalculateUtils;
7 |
8 | /**
9 | * CreateAt : 7/20/17
10 | * Describe :
11 | * 使用双指对贴纸进行缩放和旋转
12 | *
13 | * @author chendong
14 | */
15 | public class TwoFingersHandler extends StickerBaseTouchHandler {
16 |
17 | public static final String TAG = TwoFingersHandler.class.getSimpleName();
18 |
19 | private float mLastFingersDistance;
20 | private float mLastRotation;
21 |
22 | @Override
23 | public void onTouchDown(MotionEvent event) {
24 | if (isHadStickerActive() && event.getPointerCount() == 2) {
25 | mLastFingersDistance = CalculateUtils.calculateDistance(event);
26 | mLastRotation = CalculateUtils.calculateRotation(event);
27 | }
28 | }
29 |
30 | @Override
31 | public void onTouchMove(MotionEvent event) {
32 |
33 | if (isHadStickerActive()
34 | && event.getPointerCount() == 2
35 | && mLastFingersDistance > 0) {
36 |
37 | // 缩放
38 | float distance = CalculateUtils.calculateDistance(event);
39 | float scale = distance * 1f / mLastFingersDistance;
40 |
41 | if (mActiveSticker.isCanScale(scale)) {
42 | mActiveSticker.postMatrixScale(scale, scale);
43 | }
44 | mLastFingersDistance = distance;
45 |
46 | // 旋转
47 | float rotation = CalculateUtils.calculateRotation(event);
48 | mActiveSticker.postMatrixRotate(rotation - mLastRotation);
49 | mLastRotation = rotation;
50 | }
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/listener/OnStickerEventListener.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.listener;
2 |
3 | import com.march.piceditor.functions.sticker.model.Sticker;
4 |
5 | /**
6 | * CreateAt : 7/21/17
7 | * Describe :
8 | *
9 | * @author chendong
10 | */
11 | public interface OnStickerEventListener {
12 |
13 | /**
14 | * 贴纸选择事件
15 | *
16 | * @param preSticker 上一个贴纸,可能为空
17 | * @param currentSticker 当前选中的贴纸,不为空,可能与上一个贴纸相同
18 | */
19 | void OnStickerSelect(Sticker preSticker, Sticker currentSticker);
20 |
21 | void OnEmptyAreaClick();
22 | }
23 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/listener/StickerMenuHandler.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.listener;
2 |
3 | import com.march.piceditor.functions.sticker.StickerDrawOverlay;
4 | import com.march.piceditor.functions.sticker.model.Sticker;
5 | import com.march.piceditor.functions.sticker.model.StickerMenu;
6 |
7 | /**
8 | * CreateAt : 7/21/17
9 | * Describe : 菜单点击之后的动作
10 | *
11 | * @author chendong
12 | */
13 | public interface StickerMenuHandler {
14 | void onMenuClick(StickerDrawOverlay overlay, Sticker sticker, StickerMenu menu);
15 | }
16 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/model/Position.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.model;
2 |
3 | /**
4 | * CreateAt : 7/21/17
5 | * Describe :
6 | *
7 | * @author chendong
8 | */
9 | public class Position {
10 | public static final int TOP_LEFT = 0;
11 | public static final int TOP_RIGHT = 1;
12 | public static final int BOTTOM_LEFT = 2;
13 | public static final int BOTTOM_RIGHT = 3;
14 | }
15 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/model/Sticker.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.model;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.ColorMatrixColorFilter;
7 | import android.graphics.Matrix;
8 | import android.graphics.RectF;
9 |
10 | import android.util.SparseArray;
11 |
12 | import com.march.piceditor.utils.BitmapUtils;
13 | import com.march.piceditor.model.PointF;
14 | import com.march.piceditor.utils.CalculateUtils;
15 | import com.march.piceditor.utils.Utils;
16 |
17 | /**
18 | * CreateAt : 7/20/17
19 | * Describe : 贴纸类
20 | *
21 | * @author chendong
22 | */
23 | public class Sticker implements Comparable {
24 |
25 | private static int sStaticId = 0;
26 |
27 | private Bitmap mStickerImage; // 贴纸资源
28 | private Matrix mMatrix; // 贴纸变换
29 | private RectF mRectF; // 贴纸对应区域,注意,这里是水平矩形,不会旋转
30 |
31 | private boolean mIsActive; // 当前贴纸是否激活
32 | // 当前贴纸是否删除,
33 | // 标记为删除的贴纸为假删,只是不尽兴绘制了而已,
34 | // 如果希望真的删除,使用 StickerDrawOverlay 删除贴纸的方法
35 | private boolean mIsHidden;
36 | // 自动提升,如果允许自动提升,
37 | // 点击时会将当前贴纸下面的贴纸提升上来,
38 | // 避免因为遮挡无法点击下层贴纸
39 | private boolean mIsAutoLifting;
40 | private int mId;
41 | private long mPriority; // 当前贴纸绘制优先级别
42 | private int mMinSize; // 最小限制,不设置时表示不限制
43 | private int mMaxSize; // 最大限制,不设置时表示不限制\
44 |
45 | private float mInitScale = 1;
46 | private float mInitTranslateX, mInitTranslateY;
47 |
48 | private ColorMatrixColorFilter mColorFilter; // 颜色过滤器,将贴纸过滤成纯色
49 | private SparseArray mCornerPointMap; // 四角点的位置,可倾斜矩形
50 | private SparseArray mMenuMap; // 四个菜单键的存储
51 |
52 |
53 | public Sticker(Context context) {
54 | mStickerImage = BitmapFactory.decodeResource(context.getResources(), android.R.mipmap.sym_def_app_icon);
55 | init();
56 | }
57 |
58 | public Sticker(Bitmap source) {
59 | mStickerImage = source;
60 | init();
61 | }
62 |
63 |
64 | private void init() {
65 | mId = sStaticId++;
66 | mMatrix = new Matrix();
67 | mRectF = new RectF();
68 | mPriority = System.currentTimeMillis();
69 | mCornerPointMap = new SparseArray<>();
70 | mMenuMap = new SparseArray<>();
71 | mCornerPointMap.put(Position.TOP_LEFT, new PointF());
72 | mCornerPointMap.put(Position.TOP_RIGHT, new PointF());
73 | mCornerPointMap.put(Position.BOTTOM_RIGHT, new PointF());
74 | mCornerPointMap.put(Position.BOTTOM_LEFT, new PointF());
75 | }
76 |
77 | public boolean isActive() {
78 | return mIsActive;
79 | }
80 |
81 | public void setActive(boolean active) {
82 | mIsActive = active;
83 | }
84 |
85 | public Bitmap getStickerImage() {
86 | return mStickerImage;
87 | }
88 |
89 | public Matrix getMatrix() {
90 | return mMatrix;
91 | }
92 |
93 | public void addStickerMenu(StickerMenu... stickerMenu) {
94 | for (StickerMenu menu : stickerMenu) {
95 | menu.attachSticker(this);
96 | mMenuMap.put(menu.getPositionType(), menu);
97 | }
98 | }
99 |
100 | public StickerMenu[] getStickerMenus() {
101 | StickerMenu[] stickerMenus = new StickerMenu[mMenuMap.size()];
102 | for (int i = 0; i < mMenuMap.size(); i++) {
103 | stickerMenus[i] = mMenuMap.valueAt(i);
104 | }
105 | return stickerMenus;
106 | }
107 |
108 | public PointF[] getCornerPoints() {
109 | mapPoints();
110 | return new PointF[]{
111 | mCornerPointMap.get(Position.TOP_LEFT),
112 | mCornerPointMap.get(Position.TOP_RIGHT),
113 | mCornerPointMap.get(Position.BOTTOM_RIGHT),
114 | mCornerPointMap.get(Position.BOTTOM_LEFT)
115 | };
116 | }
117 |
118 | public boolean isHidden() {
119 | return mIsHidden;
120 | }
121 |
122 | public void setHidden(boolean hidden) {
123 | mIsHidden = hidden;
124 | }
125 |
126 |
127 | public float getInitScale() {
128 | return mInitScale;
129 | }
130 |
131 | public float getInitTranslateX() {
132 | return mInitTranslateX;
133 | }
134 |
135 | public float getInitTranslateY() {
136 | return mInitTranslateY;
137 | }
138 |
139 | public void setStickerImage(Bitmap stickerImage) {
140 | mStickerImage = stickerImage;
141 | }
142 |
143 | public void bringTopLayer() {
144 | mPriority = System.currentTimeMillis();
145 | }
146 |
147 | public void bringBottomLayer() {
148 | mPriority = -System.currentTimeMillis();
149 | }
150 |
151 | public RectF getRectF() {
152 | mRectF.set(0, 0, mStickerImage.getWidth(), mStickerImage.getHeight());
153 | mMatrix.mapRect(mRectF);
154 | return mRectF;
155 | }
156 |
157 | private void mapPoints() {
158 |
159 | float[] dst = new float[8];
160 |
161 | float[] src = new float[]{
162 | 0, 0, mStickerImage.getWidth(),
163 | 0, 0, mStickerImage.getHeight(),
164 | mStickerImage.getWidth(), mStickerImage.getHeight()};
165 |
166 | mMatrix.mapPoints(dst, src);
167 |
168 | mCornerPointMap.get(Position.TOP_LEFT).set(dst[0], dst[1]);
169 | mCornerPointMap.get(Position.TOP_RIGHT).set(dst[2], dst[3]);
170 | mCornerPointMap.get(Position.BOTTOM_LEFT).set(dst[4], dst[5]);
171 | mCornerPointMap.get(Position.BOTTOM_RIGHT).set(dst[6], dst[7]);
172 | }
173 |
174 | public SparseArray getCornerPointMap() {
175 | return mCornerPointMap;
176 | }
177 |
178 | public SparseArray getMenuMap() {
179 | return mMenuMap;
180 | }
181 |
182 | public boolean isTouchIn(float x, float y) {
183 | PointF[] points = getCornerPoints();
184 | return CalculateUtils.isRectContainsPoint(points[0],
185 | points[1], points[2],
186 | points[3], new PointF(x, y));
187 | }
188 |
189 | @Override
190 | public int compareTo( Sticker o) {
191 | if (mPriority > o.mPriority) {
192 | return 1;
193 | } else if (mPriority < o.mPriority) {
194 | return -1;
195 | } else {
196 | return 0;
197 | }
198 | }
199 |
200 | public void setColorFilter(int red, int green, int blue) {
201 | if (red == -1 || green == -1 || blue == -1) {
202 | mColorFilter = null;
203 | } else
204 | mColorFilter = Utils.buildColorFilter(red, green, blue);
205 | }
206 |
207 | public void setNoColorFilter() {
208 | mColorFilter = null;
209 | }
210 |
211 | public ColorMatrixColorFilter getColorFilter() {
212 | return mColorFilter;
213 | }
214 |
215 | public void setInitScale(float initScale) {
216 | mInitScale = initScale;
217 | }
218 |
219 | public void setInitTranslate(float tx, float ty) {
220 | mInitTranslateX = tx;
221 | mInitTranslateY = ty;
222 | }
223 |
224 | public void setMinSize(int minSize) {
225 | mMinSize = minSize;
226 | }
227 |
228 | public void setMaxSize(int maxSize) {
229 | mMaxSize = maxSize;
230 | }
231 |
232 | public boolean isAutoLifting() {
233 | return mIsAutoLifting;
234 | }
235 |
236 | public void setAutoLifting(boolean autoLifting) {
237 | mIsAutoLifting = autoLifting;
238 | }
239 |
240 | // matrix 辅助
241 | public void postMatrixScale(float sx, float sy) {
242 | RectF rectF = getRectF();
243 | float cy = rectF.centerY();
244 | float cx = rectF.centerX();
245 | getMatrix().postScale(sx, sy, cx, cy);
246 | }
247 |
248 | public void postMatrixRotate(float rotation) {
249 | RectF rectF = getRectF();
250 | float cy = rectF.centerY();
251 | float cx = rectF.centerX();
252 | getMatrix().postRotate(rotation, cx, cy);
253 | }
254 |
255 | // 两边中的较大值小于最大值,两边中最小值大于最小值
256 | public boolean isCanScale(float scale) {
257 | float length1 = CalculateUtils.calculateDistance(mCornerPointMap.get(Position.TOP_LEFT), mCornerPointMap.get(Position.TOP_RIGHT));
258 | float length2 = CalculateUtils.calculateDistance(mCornerPointMap.get(Position.TOP_RIGHT), mCornerPointMap.get(Position.BOTTOM_RIGHT));
259 | if (scale > 1) {
260 | // 放大时,没设置限制 || 没到达最大值
261 | return mMaxSize <= 0 || Math.max(length1, length2) < mMaxSize;
262 | } else if (scale < 1) {
263 | // 缩小时,没设置限制 || 没到达最小值
264 | return mMinSize <= 0 || Math.min(length1, length2) > mMinSize;
265 | } else return true;
266 | }
267 |
268 |
269 | public void destroy() {
270 | System.gc();
271 | mIsActive = false;
272 | mIsHidden = true;
273 | mColorFilter = null;
274 | mCornerPointMap.clear();
275 | mMenuMap.clear();
276 | BitmapUtils.recycleBitmaps(mStickerImage);
277 | }
278 |
279 |
280 | @Override
281 | public boolean equals(Object o) {
282 | if (this == o)
283 | return true;
284 | if (o == null || getClass() != o.getClass())
285 | return false;
286 | Sticker sticker = (Sticker) o;
287 | return mId == sticker.mId;
288 | }
289 |
290 | @Override
291 | public int hashCode() {
292 | return 31;
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/functions/sticker/model/StickerMenu.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.functions.sticker.model;
2 |
3 | import android.graphics.Rect;
4 | import android.graphics.drawable.Drawable;
5 |
6 | import com.march.piceditor.model.PointF;
7 | import com.march.piceditor.functions.sticker.listener.StickerMenuHandler;
8 |
9 | /**
10 | * CreateAt : 7/21/17
11 | * Describe : 贴纸菜单
12 | * 相同的icon可以引用同一个,避免创建大量的drawable
13 | *
14 | * @author chendong
15 | */
16 | public class StickerMenu {
17 |
18 | private Drawable mMenuIcon;
19 | private Rect mBoundRect;
20 | private Sticker mAttachSticker;
21 | private Object mTag;
22 |
23 | private int mScale;
24 | private int mPositionType;
25 |
26 | private StickerMenuHandler mStickerMenuHandler;
27 |
28 |
29 | public StickerMenu(int type, Drawable menuIcon) {
30 | init(type, menuIcon);
31 | }
32 |
33 | public void init(int type, Drawable menuIcon) {
34 | mMenuIcon = menuIcon;
35 | mPositionType = type;
36 | mScale = 2;
37 | mBoundRect = new Rect();
38 | }
39 |
40 | public void attachSticker(Sticker sticker) {
41 | mAttachSticker = sticker;
42 | }
43 |
44 | public Drawable getMenuIcon() {
45 | return mMenuIcon;
46 | }
47 |
48 | public void setMenuIcon(Drawable menuIcon) {
49 | mMenuIcon = menuIcon;
50 | }
51 |
52 | public int getMenuWidth() {
53 | return mMenuIcon.getIntrinsicWidth();
54 | }
55 |
56 | public int getMenuHeight() {
57 | return mMenuIcon.getIntrinsicHeight();
58 | }
59 |
60 | public int getPositionType() {
61 | return mPositionType;
62 | }
63 |
64 | public Object getTag() {
65 | return mTag;
66 | }
67 |
68 | public void setTag(Object tag) {
69 | mTag = tag;
70 | }
71 |
72 | public void updateBounds() {
73 | mMenuIcon.setBounds(getBounds());
74 | }
75 |
76 | public Rect getBounds() {
77 |
78 | PointF p = mAttachSticker.getCornerPointMap().get(mPositionType);
79 |
80 | mBoundRect.set((int) (p.x - getMenuWidth() / mScale / 2),
81 | (int) (p.y - getMenuHeight() / mScale / 2),
82 | (int) (p.x - getMenuWidth() / mScale / 2 + getMenuWidth() / mScale),
83 | (int) (p.y - getMenuHeight() / mScale / 2 + getMenuHeight() / mScale));
84 |
85 | return mBoundRect;
86 | }
87 |
88 | public StickerMenuHandler getStickerMenuHandler() {
89 | return mStickerMenuHandler;
90 | }
91 |
92 | public void setStickerMenuHandler(StickerMenuHandler stickerMenuHandler) {
93 | mStickerMenuHandler = stickerMenuHandler;
94 | }
95 |
96 |
97 | public boolean isTouchIn(float x, float y) {
98 | return getBounds().contains((int) x, (int) y);
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/model/PointF.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.model;
2 |
3 | import android.view.MotionEvent;
4 |
5 | /**
6 | * CreateAt : 7/21/17
7 | * Describe : float 类型的点
8 | *
9 | * @author chendong
10 | */
11 | public class PointF {
12 |
13 | public float x;
14 | public float y;
15 |
16 | public PointF(float x, float y) {
17 | this.x = x;
18 | this.y = y;
19 | }
20 |
21 | public PointF() {
22 | }
23 |
24 | public void set(float x, float y) {
25 | this.x = x;
26 | this.y = y;
27 | }
28 |
29 | public void set(MotionEvent event) {
30 | set(event.getX(), event.getY());
31 | }
32 |
33 | public boolean isValid() {
34 | return x != -1 && y != -1;
35 | }
36 |
37 | public void reset() {
38 | x = -1;
39 | y = -1;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/BitmapUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapFactory;
5 |
6 |
7 | import java.io.BufferedOutputStream;
8 | import java.io.File;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 |
12 | /**
13 | * CreateAt : 2017/11/29
14 | * Describe :
15 | * bitmap 处理类
16 | *
17 | * @author chendong
18 | */
19 | public class BitmapUtils {
20 |
21 | public static BitmapFactory.Options getBitmapSize(String filePath) {
22 | BitmapFactory.Options options = new BitmapFactory.Options();
23 | options.inJustDecodeBounds = true;
24 | BitmapFactory.decodeFile(filePath, options);
25 | options.inJustDecodeBounds = false;
26 | return options;
27 | }
28 |
29 | /**
30 | * @param bmp 位图
31 | * @param file 文件
32 | * @param format format
33 | * @param quality 质量
34 | * @param isRecycle 是否回收资源
35 | * @return 存入的file
36 | */
37 | public static File compressImage(Bitmap bmp, File file, Bitmap.CompressFormat format, int quality, boolean isRecycle) {
38 | try {
39 | BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
40 |
41 | bmp.compress(format, quality, bos);
42 | bos.flush();
43 | bos.close();
44 | if (isRecycle)
45 | recycleBitmaps(bmp);
46 | } catch (IOException e) {
47 | e.printStackTrace();
48 | }
49 | return file;
50 | }
51 |
52 |
53 | public static int calculateSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
54 | double wr = (double) actualWidth / desiredWidth;
55 | double hr = (double) actualHeight / desiredHeight;
56 | double ratio = Math.min(wr, hr);
57 | float inSampleSize = 1.0f;
58 | while ((inSampleSize * 2) <= ratio) {
59 | inSampleSize *= 2;
60 | }
61 | return (int) inSampleSize;
62 | }
63 |
64 | // 通过传入的bitmap,进行压缩,得到符合标准的bitmap
65 | public static Bitmap createScaleBitmap(Bitmap tempBitmap, int destWidth, int destHeight) {
66 | // If necessary, scale down to the maximal acceptable size.
67 | if (tempBitmap != null && (tempBitmap.getWidth() > destWidth || tempBitmap.getHeight() > destHeight)) {
68 | // 如果是放大图片,filter决定是否平滑,如果是缩小图片,filter无影响
69 | Bitmap bitmap = Bitmap.createScaledBitmap(tempBitmap, destWidth, destHeight, true);
70 | recycleBitmaps(tempBitmap);
71 | return bitmap;
72 | } else {
73 | return tempBitmap; // 如果没有缩放,那么不回收
74 | }
75 | }
76 |
77 |
78 | public static void recycleBitmaps(Bitmap... bitmaps) {
79 | for (Bitmap bitmap : bitmaps) {
80 | try {
81 | if (bitmap != null && !bitmap.isRecycled()) {
82 | bitmap.recycle();
83 | }
84 | } catch (Exception e) {
85 | e.printStackTrace();
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/Blur.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.graphics.Bitmap;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.PorterDuff;
10 | import android.graphics.PorterDuffColorFilter;
11 | import android.os.Build;
12 | import android.renderscript.Allocation;
13 | import android.renderscript.Element;
14 | import android.renderscript.RSRuntimeException;
15 | import android.renderscript.RenderScript;
16 | import android.renderscript.ScriptIntrinsicBlur;
17 | import android.view.View;
18 |
19 | import com.march.piceditor.utils.BitmapUtils;
20 |
21 | public class Blur {
22 |
23 | public static class BlurFactor {
24 |
25 | public static final int DEFAULT_RADIUS = 25;
26 | public static final int DEFAULT_SCALE = 1;
27 |
28 | public int width;
29 | public int height;
30 | public int radius = DEFAULT_RADIUS;
31 | public int scale = DEFAULT_SCALE;
32 | public int color = Color.TRANSPARENT;
33 | }
34 |
35 | public static Bitmap blur(View view, BlurFactor factor) {
36 | view.setDrawingCacheEnabled(true);
37 | view.destroyDrawingCache();
38 | view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW);
39 | Bitmap cache = view.getDrawingCache();
40 | Bitmap bitmap = blur(view.getContext(), cache, factor);
41 | cache.recycle();
42 | return bitmap;
43 | }
44 |
45 | public static Bitmap blur(Context context, Bitmap source, BlurFactor factor) {
46 |
47 | int width = factor.width / factor.scale;
48 | int height = factor.height / factor.scale;
49 |
50 | if (width == 0 || height == 0) {
51 | return null;
52 | }
53 |
54 | Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
55 |
56 | Canvas canvas = new Canvas(bitmap);
57 | canvas.scale(1 / (float) factor.scale, 1 / (float) factor.scale);
58 | Paint paint = new Paint();
59 | paint.setFlags(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
60 | PorterDuffColorFilter filter =
61 | new PorterDuffColorFilter(factor.color, PorterDuff.Mode.SRC_ATOP);
62 | paint.setColorFilter(filter);
63 | canvas.drawBitmap(source, 0, 0, paint);
64 |
65 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
66 | try {
67 | bitmap = Blur.rs(context, bitmap, factor.radius);
68 | } catch (RSRuntimeException e) {
69 | bitmap = Blur.stack(bitmap, factor.radius, true);
70 | }
71 | } else {
72 | bitmap = Blur.stack(bitmap, factor.radius, true);
73 | }
74 |
75 | if (factor.scale == BlurFactor.DEFAULT_SCALE) {
76 | return bitmap;
77 | } else {
78 | Bitmap scaled = Bitmap.createScaledBitmap(bitmap, factor.width, factor.height, true);
79 | BitmapUtils.recycleBitmaps(bitmap);
80 | return scaled;
81 | }
82 | }
83 |
84 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
85 | private static Bitmap rs(Context context, Bitmap bitmap, int radius) throws RSRuntimeException {
86 | RenderScript rs = null;
87 | Allocation input = null;
88 | Allocation output = null;
89 | ScriptIntrinsicBlur blur = null;
90 | try {
91 | rs = RenderScript.create(context);
92 | rs.setMessageHandler(new RenderScript.RSMessageHandler());
93 | input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE,
94 | Allocation.USAGE_SCRIPT);
95 | output = Allocation.createTyped(rs, input.getType());
96 | blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
97 |
98 | blur.setInput(input);
99 | blur.setRadius(radius);
100 | blur.forEach(output);
101 | output.copyTo(bitmap);
102 | } finally {
103 | if (rs != null) {
104 | rs.destroy();
105 | }
106 | if (input != null) {
107 | input.destroy();
108 | }
109 | if (output != null) {
110 | output.destroy();
111 | }
112 | if (blur != null) {
113 | blur.destroy();
114 | }
115 | }
116 | return bitmap;
117 | }
118 |
119 |
120 | private static Bitmap stack(Bitmap sentBitmap, int radius, boolean canReuseInBitmap) {
121 |
122 | // Stack Blur v1.0 from
123 | // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
124 | //
125 | // Java Author: Mario Klingemann
126 | // http://incubator.quasimondo.com
127 | // created Feburary 29, 2004
128 | // Android port : Yahel Bouaziz
129 | // http://www.kayenko.com
130 | // ported april 5th, 2012
131 |
132 | // This is a compromise between Gaussian Blur and Box blur
133 | // It creates much better looking blurs than Box Blur, but is
134 | // 7x faster than my Gaussian Blur implementation.
135 | //
136 | // I called it Stack Blur because this describes best how this
137 | // filter works internally: it creates a kind blur moving stack
138 | // blur colors whilst scanning through the image. Thereby it
139 | // just has to add one new block blur color to the right side
140 | // blur the stack and remove the leftmost color. The remaining
141 | // colors on the topmost layer blur the stack are either added on
142 | // or reduced by one, depending on if they are on the right or
143 | // on the left side blur the stack.
144 | //
145 | // If you are using this algorithm in your code please add
146 | // the following line:
147 | //
148 | // Stack Blur Algorithm by Mario Klingemann
149 |
150 | Bitmap bitmap;
151 | if (canReuseInBitmap) {
152 | bitmap = sentBitmap;
153 | } else {
154 | bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
155 | }
156 |
157 | if (radius < 1) {
158 | return (null);
159 | }
160 |
161 | int w = bitmap.getWidth();
162 | int h = bitmap.getHeight();
163 |
164 | int[] pix = new int[w * h];
165 | bitmap.getPixels(pix, 0, w, 0, 0, w, h);
166 |
167 | int wm = w - 1;
168 | int hm = h - 1;
169 | int wh = w * h;
170 | int div = radius + radius + 1;
171 |
172 | int r[] = new int[wh];
173 | int g[] = new int[wh];
174 | int b[] = new int[wh];
175 | int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
176 | int vmin[] = new int[Math.max(w, h)];
177 |
178 | int divsum = (div + 1) >> 1;
179 | divsum *= divsum;
180 | int dv[] = new int[256 * divsum];
181 | for (i = 0; i < 256 * divsum; i++) {
182 | dv[i] = (i / divsum);
183 | }
184 |
185 | yw = yi = 0;
186 |
187 | int[][] stack = new int[div][3];
188 | int stackpointer;
189 | int stackstart;
190 | int[] sir;
191 | int rbs;
192 | int r1 = radius + 1;
193 | int routsum, goutsum, boutsum;
194 | int rinsum, ginsum, binsum;
195 |
196 | for (y = 0; y < h; y++) {
197 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
198 | for (i = -radius; i <= radius; i++) {
199 | p = pix[yi + Math.min(wm, Math.max(i, 0))];
200 | sir = stack[i + radius];
201 | sir[0] = (p & 0xff0000) >> 16;
202 | sir[1] = (p & 0x00ff00) >> 8;
203 | sir[2] = (p & 0x0000ff);
204 | rbs = r1 - Math.abs(i);
205 | rsum += sir[0] * rbs;
206 | gsum += sir[1] * rbs;
207 | bsum += sir[2] * rbs;
208 | if (i > 0) {
209 | rinsum += sir[0];
210 | ginsum += sir[1];
211 | binsum += sir[2];
212 | } else {
213 | routsum += sir[0];
214 | goutsum += sir[1];
215 | boutsum += sir[2];
216 | }
217 | }
218 | stackpointer = radius;
219 |
220 | for (x = 0; x < w; x++) {
221 |
222 | r[yi] = dv[rsum];
223 | g[yi] = dv[gsum];
224 | b[yi] = dv[bsum];
225 |
226 | rsum -= routsum;
227 | gsum -= goutsum;
228 | bsum -= boutsum;
229 |
230 | stackstart = stackpointer - radius + div;
231 | sir = stack[stackstart % div];
232 |
233 | routsum -= sir[0];
234 | goutsum -= sir[1];
235 | boutsum -= sir[2];
236 |
237 | if (y == 0) {
238 | vmin[x] = Math.min(x + radius + 1, wm);
239 | }
240 | p = pix[yw + vmin[x]];
241 |
242 | sir[0] = (p & 0xff0000) >> 16;
243 | sir[1] = (p & 0x00ff00) >> 8;
244 | sir[2] = (p & 0x0000ff);
245 |
246 | rinsum += sir[0];
247 | ginsum += sir[1];
248 | binsum += sir[2];
249 |
250 | rsum += rinsum;
251 | gsum += ginsum;
252 | bsum += binsum;
253 |
254 | stackpointer = (stackpointer + 1) % div;
255 | sir = stack[(stackpointer) % div];
256 |
257 | routsum += sir[0];
258 | goutsum += sir[1];
259 | boutsum += sir[2];
260 |
261 | rinsum -= sir[0];
262 | ginsum -= sir[1];
263 | binsum -= sir[2];
264 |
265 | yi++;
266 | }
267 | yw += w;
268 | }
269 | for (x = 0; x < w; x++) {
270 | rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
271 | yp = -radius * w;
272 | for (i = -radius; i <= radius; i++) {
273 | yi = Math.max(0, yp) + x;
274 |
275 | sir = stack[i + radius];
276 |
277 | sir[0] = r[yi];
278 | sir[1] = g[yi];
279 | sir[2] = b[yi];
280 |
281 | rbs = r1 - Math.abs(i);
282 |
283 | rsum += r[yi] * rbs;
284 | gsum += g[yi] * rbs;
285 | bsum += b[yi] * rbs;
286 |
287 | if (i > 0) {
288 | rinsum += sir[0];
289 | ginsum += sir[1];
290 | binsum += sir[2];
291 | } else {
292 | routsum += sir[0];
293 | goutsum += sir[1];
294 | boutsum += sir[2];
295 | }
296 |
297 | if (i < hm) {
298 | yp += w;
299 | }
300 | }
301 | yi = x;
302 | stackpointer = radius;
303 | for (y = 0; y < h; y++) {
304 | // Preserve alpha channel: ( 0xff000000 & pix[yi] )
305 | pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum];
306 |
307 | rsum -= routsum;
308 | gsum -= goutsum;
309 | bsum -= boutsum;
310 |
311 | stackstart = stackpointer - radius + div;
312 | sir = stack[stackstart % div];
313 |
314 | routsum -= sir[0];
315 | goutsum -= sir[1];
316 | boutsum -= sir[2];
317 |
318 | if (x == 0) {
319 | vmin[y] = Math.min(y + r1, hm) * w;
320 | }
321 | p = x + vmin[y];
322 |
323 | sir[0] = r[p];
324 | sir[1] = g[p];
325 | sir[2] = b[p];
326 |
327 | rinsum += sir[0];
328 | ginsum += sir[1];
329 | binsum += sir[2];
330 |
331 | rsum += rinsum;
332 | gsum += ginsum;
333 | bsum += binsum;
334 |
335 | stackpointer = (stackpointer + 1) % div;
336 | sir = stack[stackpointer];
337 |
338 | routsum += sir[0];
339 | goutsum += sir[1];
340 | boutsum += sir[2];
341 |
342 | rinsum -= sir[0];
343 | ginsum -= sir[1];
344 | binsum -= sir[2];
345 |
346 | yi += w;
347 | }
348 | }
349 |
350 | bitmap.setPixels(pix, 0, w, 0, 0, w, h);
351 |
352 | return (bitmap);
353 | }
354 | }
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/CalculateUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.view.MotionEvent;
4 |
5 | import com.march.piceditor.model.PointF;
6 |
7 | /**
8 | * CreateAt : 7/20/17
9 | * Describe : 计算类
10 | *
11 | * @author chendong
12 | */
13 | public class CalculateUtils {
14 |
15 | public static float calculateDistance(PointF p1, PointF p2){
16 | return (float) Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
17 | }
18 |
19 | public static float calculateDistance(float x1, float y1, float x2, float y2) {
20 | return (float) Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
21 | }
22 |
23 | public static float calculateDistance(MotionEvent event) {
24 | return calculateDistance(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
25 | }
26 |
27 |
28 | public static float calculateRotation(float x1, float y1, float x2, float y2) {
29 | double radians = Math.atan2(y2 - y1, x2 - x1);
30 | return (float) Math.toDegrees(radians);
31 | }
32 |
33 | public static float calculateRotation(MotionEvent event) {
34 | return calculateRotation(event.getX(0), event.getY(0), event.getX(1), event.getY(1));
35 | }
36 |
37 |
38 | // 先寫函數 W(p,q)= W( (px,py), (qx,qy) )= px*qy-py*qx
39 | // 之後: (C點不必用)
40 | // v=(vx, vy)=(Px-Ax, Py-Ay);
41 | // a=(ax, ay)=(Bx-Ax, By-Ay);
42 | // b=(bx, by)=(Dx-Ax, Dy-Ay);
43 | // h=W(v,b)/W(a,b);
44 | // k=W(a,v)/W(a,b);
45 | // 在內部 <==> ( 0 0) {
37 | paint.setStrokeWidth((float) width);
38 | }
39 |
40 | initAntiAliasPaint(paint);
41 | return paint;
42 | }
43 |
44 | public static void initRoundPaint(Paint paint) {
45 | paint.setStrokeCap(Paint.Cap.ROUND);
46 | paint.setStrokeJoin(Paint.Join.ROUND);
47 | }
48 |
49 | public static void initAntiAliasPaint(Paint paint) {
50 | paint.setAntiAlias(true);
51 | paint.setFilterBitmap(true);
52 | paint.setDither(true);
53 | }
54 |
55 | public static void drawViewOnCanvas(Canvas canvas, Paint paint, View view, int width, int height) {
56 | view.setDrawingCacheEnabled(true);
57 | Bitmap drawingCache = view.getDrawingCache();
58 | Bitmap scaledBitmap;
59 | if (drawingCache.getWidth() == width && drawingCache.getHeight() == height) {
60 | scaledBitmap = drawingCache;
61 | } else {
62 | scaledBitmap = Bitmap.createScaledBitmap(drawingCache, width, height, true);
63 | }
64 |
65 | canvas.drawBitmap(scaledBitmap, 0.0F, 0.0F, paint);
66 | view.setDrawingCacheEnabled(false);
67 | BitmapUtils.recycleBitmaps(drawingCache, scaledBitmap);
68 | }
69 |
70 | public static void drawViewOnCanvasNoScale(Canvas canvas, Paint paint, View view) {
71 | view.setDrawingCacheEnabled(true);
72 | Bitmap drawingCache = view.getDrawingCache();
73 | canvas.drawBitmap(drawingCache, 0.0F, 0.0F, paint);
74 | view.setDrawingCacheEnabled(false);
75 | BitmapUtils.recycleBitmaps(drawingCache);
76 | }
77 |
78 | public static void drawHLine(Canvas canvas, Paint paint, float y, float fromX, float width) {
79 | canvas.drawLine(fromX, y, fromX + width, y, paint);
80 | }
81 |
82 | public static void drawVLine(Canvas canvas, Paint paint, float x, float fromY, float height) {
83 | canvas.drawLine(x, fromY, x, fromY + height, paint);
84 | }
85 |
86 | public static float measureTextHeight(Paint p) {
87 | return Math.abs(p.ascent() + p.descent());
88 | }
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/GraffitiUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.Canvas;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 |
9 | import com.march.piceditor.utils.BitmapUtils;
10 |
11 | /**
12 | * CreateAt : 7/25/17
13 | * Describe :
14 | *
15 | * @author chendong
16 | */
17 | public class GraffitiUtils {
18 |
19 |
20 | /**
21 | * 创建纯色 bitmap
22 | *
23 | * @param srcBitmap src
24 | * @param color color
25 | * @return 纯色 bitmap
26 | */
27 | public static Bitmap getColorBitmap(Bitmap srcBitmap, int color) {
28 | if (srcBitmap == null || srcBitmap.getWidth() == 0 || srcBitmap.getHeight() == 0)
29 | return null;
30 | Bitmap bitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(),
31 | Bitmap.Config.ARGB_8888);
32 | Canvas canvas = new Canvas(bitmap);
33 | Rect rect = new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight());
34 | Paint paint = new Paint();
35 | paint.setColor(color);
36 | canvas.drawRect(rect, paint);
37 | canvas.save();
38 | return bitmap;
39 | }
40 |
41 | /**
42 | * 将图片转换为马赛克图片
43 | *
44 | * @param srcBitmap source srcBitmap
45 | * @param radius 马赛克半径
46 | * @return 马赛克后的图片
47 | */
48 | public static Bitmap getMosaicBitmap(Bitmap srcBitmap, int radius) {
49 | int width = srcBitmap.getWidth();
50 | int height = srcBitmap.getHeight();
51 |
52 | Bitmap mosaicBitmap = Bitmap.createBitmap(width, height,
53 | Bitmap.Config.ARGB_8888);
54 | Canvas canvas = new Canvas(mosaicBitmap);
55 |
56 | int horCount = (int) Math.ceil(width / (float) radius);
57 | int verCount = (int) Math.ceil(height / (float) radius);
58 |
59 | Paint paint = new Paint();
60 | paint.setAntiAlias(true);
61 |
62 | for (int horIndex = 0; horIndex < horCount; ++horIndex) {
63 | for (int verIndex = 0; verIndex < verCount; ++verIndex) {
64 | int l = radius * horIndex;
65 | int t = radius * verIndex;
66 | int r = l + radius;
67 | if (r > width) {
68 | r = width;
69 | }
70 | int b = t + radius;
71 | if (b > height) {
72 | b = height;
73 | }
74 | int color = srcBitmap.getPixel(l, t);
75 | Rect rect = new Rect(l, t, r, b);
76 | paint.setColor(color);
77 | canvas.drawRect(rect, paint);
78 | }
79 | }
80 | canvas.save();
81 |
82 | return mosaicBitmap;
83 | }
84 |
85 |
86 | /**
87 | * 获取模糊图,模糊算法使用 rs 和 fast blur 兼容
88 | *
89 | * @param context ctx
90 | * @param srcBitmap src
91 | * @param blurRadius 模糊半径
92 | * @return 模糊后的图片
93 | */
94 | public static Bitmap getBlurBitmap(Context context, Bitmap srcBitmap, int blurRadius) {
95 | Blur.BlurFactor factor = new Blur.BlurFactor();
96 | factor.width = srcBitmap.getWidth();
97 | factor.height = srcBitmap.getHeight();
98 | factor.radius = blurRadius;
99 | return Blur.blur(context, srcBitmap, factor);
100 | }
101 |
102 |
103 | /**
104 | * 将 cropImage 中心裁剪适配 srcBitmap
105 | * @param srcBitmap 操作的 bitmap
106 | * @param cropImage 作为涂抹涂层的 bitmap
107 | * @return 裁剪后的 bitmap
108 | */
109 | public static Bitmap getCenterCropBitmap(Bitmap srcBitmap, Bitmap cropImage) {
110 | int width = srcBitmap.getWidth();
111 | int height = srcBitmap.getHeight();
112 |
113 | if (cropImage.getWidth() == width && cropImage.getHeight() == height) {
114 | return cropImage;
115 | } else {
116 | float scale = Math.min(cropImage.getWidth() * 1f / width, cropImage.getHeight() * 1f / height);
117 | Bitmap finalBitmap;
118 | if (scale > 1) {
119 | // 截取中间部分
120 | finalBitmap = Bitmap.createBitmap(cropImage, (cropImage.getWidth() - width) / 2, (cropImage.getHeight() - height) / 2, width, height);
121 | BitmapUtils.recycleBitmaps(cropImage);
122 | } else {
123 | // 放大到至少和 src 一样大
124 | Bitmap scaledBitmap = Bitmap.createScaledBitmap(cropImage, ((int) (cropImage.getWidth() / scale)), ((int) (cropImage.getHeight() / scale)), false);
125 | // 截取中间部分
126 | finalBitmap = Bitmap.createBitmap(scaledBitmap, (scaledBitmap.getWidth() - width) / 2, (scaledBitmap.getHeight() - height) / 2, width, height);
127 | BitmapUtils.recycleBitmaps(cropImage, scaledBitmap);
128 | }
129 | return finalBitmap;
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/LogUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.util.Log;
4 |
5 | /**
6 | * CreateAt : 2017/11/29
7 | * Describe : 日志类
8 | *
9 | * @author chendong
10 | */
11 | public class LogUtils {
12 |
13 | private static boolean DEBUG = true;
14 | private static String TAG = "LogUtils";
15 |
16 | public LogUtils() {
17 | }
18 |
19 | public static void setDebug(boolean debug) {
20 | DEBUG = debug;
21 | }
22 |
23 | public static void setDefTag(String defTag) {
24 | TAG = defTag;
25 | }
26 |
27 | private static boolean checkMsgNotNull(Object msg) {
28 | if(msg == null) {
29 | Log.e(TAG, "log msg is null");
30 | return false;
31 | } else {
32 | return true;
33 | }
34 | }
35 |
36 | private static boolean checkMsgNotNull(String tag, Object msg) {
37 | if(msg == null) {
38 | Log.e(getTag(tag), "log msg is null");
39 | return false;
40 | } else {
41 | return true;
42 | }
43 | }
44 |
45 | private static String getTag(String tag) {
46 | return tag == null?TAG:tag;
47 | }
48 |
49 | public static void i(Object msg) {
50 | if(DEBUG && checkMsgNotNull(msg)) {
51 | Log.i(TAG, msg.toString());
52 | }
53 |
54 | }
55 |
56 | public static void i(String tag, Object msg) {
57 | if(DEBUG && checkMsgNotNull(tag, msg)) {
58 | Log.i(getTag(tag), msg.toString());
59 | }
60 |
61 | }
62 |
63 | public static void e(Object msg) {
64 | if(DEBUG && checkMsgNotNull(msg)) {
65 | Log.e(TAG, msg.toString());
66 | }
67 |
68 | }
69 |
70 | public static void e(String tag, Object msg) {
71 | if(DEBUG && checkMsgNotNull(tag, msg)) {
72 | Log.e(getTag(tag), msg.toString());
73 | }
74 |
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.graphics.ColorMatrixColorFilter;
4 |
5 | /**
6 | * CreateAt : 7/22/17
7 | * Describe :
8 | *
9 | * @author chendong
10 | */
11 | public class Utils {
12 |
13 | /**
14 | * 转换 rgb 为 ColorMatrixColorFilter
15 | *
16 | * @param red r
17 | * @param green g
18 | * @param blue b
19 | * @return ColorMatrixColorFilter
20 | */
21 | public static ColorMatrixColorFilter buildColorFilter(int red, int green, int blue) {
22 | float[] src = new float[]{
23 | 0, 0, 0, 0, red,
24 | 0, 0, 0, 0, green,
25 | 0, 0, 0, 0, blue,
26 | 0, 0, 0, 1, 0};
27 | return new ColorMatrixColorFilter(src);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/piceditor/src/main/java/com/march/piceditor/utils/ViewUtils.java:
--------------------------------------------------------------------------------
1 | package com.march.piceditor.utils;
2 |
3 | import android.graphics.drawable.Drawable;
4 | import android.os.Build;
5 |
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * CreateAt : 2017/11/29
11 | * Describe :
12 | *
13 | * @author chendong
14 | */
15 | public class ViewUtils {
16 |
17 | public static void setBackground( View view, Drawable drawable) {
18 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
19 | view.setBackground(drawable);
20 | else
21 | view.setBackgroundDrawable(drawable);
22 | }
23 |
24 |
25 | public static void setVisibility( View view, int visibility) {
26 | if (view.getVisibility() != visibility) {
27 | view.setVisibility(visibility);
28 | }
29 | }
30 |
31 | public static void setLayoutParam(int width, int height, View... views) {
32 | ViewGroup.LayoutParams layoutParams;
33 | for (View view : views) {
34 | layoutParams = view.getLayoutParams();
35 | layoutParams.width = width;
36 | layoutParams.height = height;
37 | view.setLayoutParams(layoutParams);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/piceditor/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PicEditor
3 |
4 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | include ':piceditor'
3 | include ':lowpoly'
4 | include ':uikit'
5 | include ':lightadapter'
6 | include ':common'
7 | include ':gallery'
8 |
--------------------------------------------------------------------------------