├── .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 | 17 | 27 | 28 | 29 | 30 | 31 | 32 | 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 | 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 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 |