├── .gitignore ├── LICENSE ├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── im4j │ │ └── picturebeautify │ │ └── demo │ │ ├── FileUtils.java │ │ └── MainActivity.java │ └── res │ ├── layout │ └── activity_main.xml │ ├── mipmap-xhdpi │ └── ic_launcher.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── assets │ ├── fonts │ │ ├── GothamNarrow-Light.ttf │ │ ├── Roboto-Black.ttf │ │ ├── Roboto-BlackItalic.ttf │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-BoldCondensed.ttf │ │ ├── Roboto-BoldCondensedItalic.ttf │ │ ├── Roboto-BoldItalic.ttf │ │ ├── Roboto-Condensed.ttf │ │ ├── Roboto-CondensedItalic.ttf │ │ ├── Roboto-Italic.ttf │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-LightItalic.ttf │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-MediumItalic.ttf │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Thin.ttf │ │ └── Roboto-ThinItalic.ttf │ └── stickers │ │ ├── biankuang │ │ ├── bianjiao1.png │ │ ├── bianjiao2.png │ │ ├── bianjiao3.png │ │ └── bianjiao4.png │ │ ├── chunjie │ │ ├── xinnian1.png │ │ ├── xinnian2.png │ │ ├── xinnian3.png │ │ ├── xinnian4.png │ │ ├── xinnian5.png │ │ ├── xinnian6.png │ │ ├── xinnian7.png │ │ ├── xinnian8.png │ │ └── xinnian9.png │ │ ├── cos │ │ ├── cos1.png.svntmp │ │ ├── cos10.png │ │ ├── cos11.png │ │ ├── cos12.png │ │ ├── cos13.png │ │ ├── cos14.png │ │ ├── cos15.png │ │ ├── cos16.png │ │ ├── cos2.png │ │ ├── cos3.png │ │ ├── cos4.png │ │ ├── cos5.png │ │ ├── cos6.png │ │ ├── cos7.png │ │ ├── cos8.png │ │ └── cos9.png │ │ ├── dongwu │ │ ├── 1dongwu1.png.svntmp │ │ ├── 1dongwu10.png │ │ ├── 1dongwu2.png │ │ ├── 1dongwu3.png │ │ ├── 1dongwu4.png │ │ ├── 1dongwu5.png │ │ ├── 1dongwu6.png │ │ ├── 1dongwu7.png │ │ ├── 1dongwu8.png │ │ └── 1dongwu9.png │ │ ├── fuhao │ │ ├── fuhao1.png │ │ ├── fuhao10.png │ │ ├── fuhao2.png │ │ ├── fuhao3.png │ │ ├── fuhao4.png │ │ ├── fuhao5.png │ │ ├── fuhao6.png │ │ ├── fuhao7.png │ │ ├── fuhao8.png │ │ └── fuhao9.png │ │ ├── shipin │ │ ├── shipin1.png │ │ ├── shipin10.png │ │ ├── shipin2.png │ │ ├── shipin3.png │ │ ├── shipin4.png │ │ ├── shipin5.png │ │ ├── shipin6.png │ │ ├── shipin7.png │ │ ├── shipin8.png │ │ └── shipin9.png │ │ ├── shuzi │ │ ├── shuzi1.png │ │ ├── shuzi10.png │ │ ├── shuzi11.png │ │ ├── shuzi12.png │ │ ├── shuzi13.png │ │ ├── shuzi14.png │ │ ├── shuzi15.png │ │ ├── shuzi2.png │ │ ├── shuzi3.png │ │ ├── shuzi4.png │ │ ├── shuzi5.png │ │ ├── shuzi6.png │ │ ├── shuzi7.png │ │ ├── shuzi8.png │ │ └── shuzi9.png │ │ ├── wenzi │ │ ├── wenzi1.png │ │ ├── wenzi10.png │ │ ├── wenzi11.png │ │ ├── wenzi12.png │ │ ├── wenzi13.png │ │ ├── wenzi14.png │ │ ├── wenzi15.png │ │ ├── wenzi16.png │ │ ├── wenzi17.png │ │ ├── wenzi18.png │ │ ├── wenzi19.png │ │ ├── wenzi2.png │ │ ├── wenzi20.png │ │ ├── wenzi3.png │ │ ├── wenzi4.png │ │ ├── wenzi5.png │ │ ├── wenzi6.png │ │ ├── wenzi7.png │ │ ├── wenzi8.png │ │ └── wenzi9.png │ │ ├── xinqing │ │ ├── 2xinqing1.png │ │ ├── 2xinqing10.png │ │ ├── 2xinqing11.png │ │ ├── 2xinqing12.png │ │ ├── 2xinqing13.png │ │ ├── 2xinqing14.png │ │ ├── 2xinqing15.png │ │ ├── 2xinqing16.png │ │ ├── 2xinqing17.png │ │ ├── 2xinqing18.png │ │ ├── 2xinqing19.png │ │ ├── 2xinqing2.png │ │ ├── 2xinqing20.png │ │ ├── 2xinqing3.png │ │ ├── 2xinqing4.png │ │ ├── 2xinqing5.png │ │ ├── 2xinqing6.png │ │ ├── 2xinqing7.png │ │ ├── 2xinqing8.png │ │ └── 2xinqing9.png │ │ └── zhiye │ │ ├── zhiye1.png │ │ ├── zhiye10.png │ │ ├── zhiye2.png │ │ ├── zhiye3.png │ │ ├── zhiye4.png │ │ ├── zhiye5.png │ │ ├── zhiye6.png │ │ ├── zhiye7.png │ │ ├── zhiye8.png │ │ └── zhiye9.png │ ├── java │ └── com │ │ └── im4j │ │ └── picturebeautify │ │ ├── BaseActivity.java │ │ ├── editimage │ │ ├── EditImageActivity.java │ │ ├── adapter │ │ │ ├── FontTypeAdapter.java │ │ │ ├── StickerAdapter.java │ │ │ └── StickerTypeAdapter.java │ │ ├── fragment │ │ │ ├── CropFragment.java │ │ │ ├── FliterListFragment.java │ │ │ ├── MainMenuFragment.java │ │ │ ├── RotateFragment.java │ │ │ ├── StirckerFragment.java │ │ │ └── TextFragment.java │ │ ├── model │ │ │ └── RatioItem.java │ │ ├── utils │ │ │ ├── BitmapUtils.java │ │ │ ├── DimensionUtils.java │ │ │ ├── Matrix3.java │ │ │ ├── MatrixUtils.java │ │ │ ├── PaintUtil.java │ │ │ ├── PhotoUtils.java │ │ │ └── PointUtils.java │ │ └── view │ │ │ ├── CropImageView.java │ │ │ ├── CustomViewPager.java │ │ │ ├── LabelTextView.java │ │ │ ├── RotateImageView.java │ │ │ ├── StickerItem.java │ │ │ ├── StickerView.java │ │ │ ├── TextItem.java │ │ │ └── imagezoom │ │ │ ├── ImageViewTouch.java │ │ │ ├── ImageViewTouchBase.java │ │ │ ├── easing │ │ │ ├── Cubic.java │ │ │ ├── Easing.java │ │ │ └── Elastic.java │ │ │ └── graphic │ │ │ ├── FastBitmapDrawable.java │ │ │ └── IBitmapDrawable.java │ │ └── picchooser │ │ ├── BucketItem.java │ │ ├── BucketsFragment.java │ │ ├── GalleryAdapter.java │ │ ├── GridItem.java │ │ ├── ImagesFragment.java │ │ ├── SelectPictureActivity.java │ │ └── SquareImageView.java │ └── res │ ├── anim │ ├── in_bottom_to_top.xml │ └── out_bottom_to_top.xml │ ├── drawable-hdpi │ ├── button_back_default.png │ ├── button_back_pressed.png │ ├── crop_normal.png │ ├── crop_pressed.png │ ├── fliters_normal.png │ ├── fliters_pressed.png │ ├── font_normal.png │ ├── font_pressed.png │ ├── ic_menu_gallery.png │ ├── image_edit_back.png │ ├── sticker_delete.png │ ├── sticker_normal.png │ ├── sticker_pressed.png │ ├── sticker_rotate.png │ ├── stickers_type_animal.png │ ├── stickers_type_cos.png │ ├── stickers_type_decoration.png │ ├── stickers_type_frame.png │ ├── stickers_type_mark.png │ ├── stickers_type_motion.png │ ├── stickers_type_number.png │ ├── stickers_type_profession.png │ ├── stickers_type_spring.png │ ├── stickers_type_text.png │ ├── texture_normal.png │ ├── texture_pressed.png │ └── yd_image_tx.png │ ├── drawable │ ├── btn_back_selector.xml │ ├── image_edit_icon_crop.xml │ ├── image_edit_icon_filter.xml │ ├── image_edit_icon_rotate.xml │ ├── image_edit_icon_sticker.xml │ ├── image_edit_icon_text.xml │ └── shape_rect.xml │ ├── layout │ ├── activity_image_edit.xml │ ├── activity_main.xml │ ├── bucketitem.xml │ ├── dialog_input.xml │ ├── fragment_edit_image_crop.xml │ ├── fragment_edit_image_fliter.xml │ ├── fragment_edit_image_main_menu.xml │ ├── fragment_edit_image_rotate.xml │ ├── fragment_edit_image_sticker_type.xml │ ├── fragment_edit_image_text.xml │ ├── gallery.xml │ ├── imageitem.xml │ ├── view_font_item.xml │ ├── view_sticker_item.xml │ └── view_sticker_type_item.xml │ └── values │ ├── dimens.xml │ └── strings.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Proguard folder generated by Eclipse 23 | proguard/ 24 | 25 | # Log Files 26 | *.log 27 | 28 | # Android Studio Navigation editor temp files 29 | .navigation/ 30 | 31 | # Android Studio captures folder 32 | captures/ 33 | 34 | *.iml 35 | /.idea 36 | .DS_Store 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidImageEditor 2 | 3 | AndroidImageEditor 安卓设备上图形编辑开源控件,支持自定义贴图 图片滤镜 图片旋转 以及图片剪裁操作
4 |
5 | For edit image,supply stickers filter rotate crop 6 |
7 | 动态效果图 8 |
9 | 10 |
11 |
12 | 13 | 14 | 效果图 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 |
24 | 25 |
26 | 27 |
28 | 使用方法:见DEMO示例 29 | 30 |
31 | usage:see the demo project -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.im4j.picturebeautify.demo" 9 | minSdkVersion 11 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:23.1.1' 25 | compile project(':library') 26 | } 27 | -------------------------------------------------------------------------------- /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/king/Library/Android/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 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/im4j/picturebeautify/demo/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.im4j.picturebeautify.demo; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | 7 | import android.content.Context; 8 | import android.graphics.Bitmap; 9 | import android.net.ConnectivityManager; 10 | import android.net.NetworkInfo; 11 | import android.os.Environment; 12 | 13 | /** 14 | * 文件相关辅助类 15 | * 16 | * @author panyi 17 | * 18 | */ 19 | public class FileUtils { 20 | public static final String FOLDER_NAME = "xinlanedit"; 21 | 22 | /** 23 | * 获取存贮文件的文件夹路径 24 | * 25 | * @return 26 | */ 27 | public static File createFolders() { 28 | File baseDir; 29 | if (android.os.Build.VERSION.SDK_INT < 8) { 30 | baseDir = Environment.getExternalStorageDirectory(); 31 | } else { 32 | baseDir = Environment 33 | .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); 34 | } 35 | if (baseDir == null) 36 | return Environment.getExternalStorageDirectory(); 37 | File aviaryFolder = new File(baseDir, FOLDER_NAME); 38 | if (aviaryFolder.exists()) 39 | return aviaryFolder; 40 | if (aviaryFolder.isFile()) 41 | aviaryFolder.delete(); 42 | if (aviaryFolder.mkdirs()) 43 | return aviaryFolder; 44 | return Environment.getExternalStorageDirectory(); 45 | } 46 | 47 | public static File getEmptyFile(String name) { 48 | File folder = FileUtils.createFolders(); 49 | if (folder != null) { 50 | if (folder.exists()) { 51 | File file = new File(folder, name); 52 | return file; 53 | } 54 | } 55 | return null; 56 | } 57 | 58 | }// end 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/im4j/picturebeautify/demo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.im4j.picturebeautify.demo; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.os.AsyncTask; 8 | import android.os.Build; 9 | import android.os.Bundle; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.text.TextUtils; 12 | import android.util.DisplayMetrics; 13 | import android.view.View; 14 | import android.widget.ImageView; 15 | import android.widget.Toast; 16 | 17 | import com.im4j.picturebeautify.editimage.EditImageActivity; 18 | import com.im4j.picturebeautify.picchooser.SelectPictureActivity; 19 | 20 | import java.io.File; 21 | 22 | public class MainActivity extends AppCompatActivity { 23 | public static final int SELECT_GALLERY_IMAGE_CODE = 7; 24 | public static final int ACTION_REQUEST_EDITIMAGE = 9; 25 | private ImageView imgView; 26 | private Bitmap mainBitmap; 27 | private int imageWidth, imageHeight;// 28 | private String path; 29 | 30 | @Override 31 | public void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_main); 34 | initView(); 35 | } 36 | 37 | private void initView() { 38 | DisplayMetrics metrics = getResources().getDisplayMetrics(); 39 | imageWidth = (int) ((float) metrics.widthPixels / 1.5); 40 | imageHeight = (int) ((float) metrics.heightPixels / 1.5); 41 | 42 | imgView = (ImageView) findViewById(R.id.img); 43 | 44 | findViewById(R.id.select_ablum).setOnClickListener(new SelectClick()); 45 | findViewById(R.id.edit_image).setOnClickListener(new EditImageClick()); 46 | } 47 | 48 | /** 49 | * 编辑选择的图片 50 | * 51 | * @author panyi 52 | */ 53 | private final class EditImageClick implements View.OnClickListener { 54 | @Override 55 | public void onClick(View v) { 56 | if (TextUtils.isEmpty(path)) { 57 | Toast.makeText(MainActivity.this, R.string.no_choose, Toast.LENGTH_SHORT).show(); 58 | return; 59 | } 60 | 61 | Intent it = new Intent(MainActivity.this, EditImageActivity.class); 62 | it.putExtra(EditImageActivity.FILE_PATH, path); 63 | File outputFile = FileUtils.getEmptyFile("tietu" 64 | + System.currentTimeMillis() + ".jpg"); 65 | it.putExtra(EditImageActivity.EXTRA_OUTPUT, 66 | outputFile.getAbsolutePath()); 67 | MainActivity.this.startActivityForResult(it, 68 | ACTION_REQUEST_EDITIMAGE); 69 | } 70 | }// end inner class 71 | 72 | private final class SelectClick implements View.OnClickListener { 73 | @Override 74 | public void onClick(View v) { 75 | MainActivity.this.startActivityForResult(new Intent( 76 | MainActivity.this, SelectPictureActivity.class), 77 | SELECT_GALLERY_IMAGE_CODE); 78 | } 79 | }// end inner class 80 | 81 | @Override 82 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 83 | super.onActivityResult(requestCode, resultCode, data); 84 | if (resultCode == RESULT_OK) { 85 | switch (requestCode) { 86 | case SELECT_GALLERY_IMAGE_CODE:// 87 | handleSelectFromAblum(data); 88 | break; 89 | case ACTION_REQUEST_EDITIMAGE:// 90 | handleEditorImage(data); 91 | break; 92 | } 93 | } 94 | } 95 | 96 | private void handleEditorImage(Intent data) { 97 | String newFilePath = data.getStringExtra("save_file_path"); 98 | Toast.makeText(this, "new image path: " + newFilePath, Toast.LENGTH_LONG).show(); 99 | LoadImageTask loadTask = new LoadImageTask(); 100 | loadTask.execute(newFilePath); 101 | } 102 | 103 | private void handleSelectFromAblum(Intent data) { 104 | path = data.getStringExtra("imgPath"); 105 | LoadImageTask task = new LoadImageTask(); 106 | task.execute(path); 107 | } 108 | 109 | 110 | private final class LoadImageTask extends AsyncTask { 111 | @Override 112 | protected Bitmap doInBackground(String... params) { 113 | return getSampledBitmap(params[0], imageWidth, imageHeight); 114 | } 115 | 116 | @Override 117 | protected void onCancelled() { 118 | super.onCancelled(); 119 | } 120 | 121 | @TargetApi(Build.VERSION_CODES.HONEYCOMB) 122 | @Override 123 | protected void onCancelled(Bitmap result) { 124 | super.onCancelled(result); 125 | } 126 | 127 | @Override 128 | protected void onPreExecute() { 129 | super.onPreExecute(); 130 | } 131 | 132 | @Override 133 | protected void onPostExecute(Bitmap result) { 134 | super.onPostExecute(result); 135 | if (mainBitmap != null) { 136 | mainBitmap.recycle(); 137 | mainBitmap = null; 138 | System.gc(); 139 | } 140 | mainBitmap = result; 141 | imgView.setImageBitmap(mainBitmap); 142 | } 143 | }// end inner class 144 | 145 | public static Bitmap getSampledBitmap(String filePath, int reqWidth, 146 | int reqHeight) { 147 | BitmapFactory.Options options = new BitmapFactory.Options(); 148 | options.inJustDecodeBounds = true; 149 | 150 | BitmapFactory.decodeFile(filePath, options); 151 | 152 | // Raw height and width of image 153 | final int height = options.outHeight; 154 | final int width = options.outWidth; 155 | int inSampleSize = 1; 156 | 157 | if (height > reqHeight || width > reqWidth) { 158 | if (width > height) { 159 | inSampleSize = (int) Math.floor(((float) height / reqHeight) + 0.5f); // Math.round((float)height 160 | // / 161 | // (float)reqHeight); 162 | } else { 163 | inSampleSize = (int) Math.floor(((float) width / reqWidth) + 0.5f); // Math.round((float)width 164 | // / 165 | // (float)reqWidth); 166 | } 167 | } 168 | // System.out.println("inSampleSize--->"+inSampleSize); 169 | 170 | options.inSampleSize = inSampleSize; 171 | options.inJustDecodeBounds = false; 172 | 173 | return BitmapFactory.decodeFile(filePath, options); 174 | } 175 | }//end class 176 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 10 | 11 | 17 | 18 |