├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── jimageeditdemo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── apk │ │ └── app-debug.apk │ ├── java │ │ └── com │ │ │ ├── example │ │ │ └── jimageeditdemo │ │ │ │ ├── MainActivity.java │ │ │ │ └── api │ │ │ │ ├── BitmapFilter.java │ │ │ │ ├── BlockFilter.java │ │ │ │ ├── CartonFilter.java │ │ │ │ ├── EclosionFilter.java │ │ │ │ ├── GrayFilter.java │ │ │ │ ├── HahaFilter.java │ │ │ │ ├── IceFilter.java │ │ │ │ ├── InvertFilter.java │ │ │ │ ├── LightFilter.java │ │ │ │ ├── LomoFilter.java │ │ │ │ ├── MoltenFilter.java │ │ │ │ ├── OilFilter.java │ │ │ │ ├── OldFilter.java │ │ │ │ ├── ReliefFilter.java │ │ │ │ └── SoftnessFilter.java │ │ │ └── pmmq │ │ │ └── pmmqproject │ │ │ ├── config │ │ │ └── Constant.java │ │ │ ├── ui │ │ │ ├── picture │ │ │ │ ├── CropActivity.java │ │ │ │ ├── CropImageView.java │ │ │ │ ├── HighlightView.java │ │ │ │ ├── ImageViewTouchBase.java │ │ │ │ ├── MonitoredActivity.java │ │ │ │ ├── RotateBitmap.java │ │ │ │ ├── TakePicActivity.java │ │ │ │ ├── TouchImageView.java │ │ │ │ ├── WaterMarkActivity.java │ │ │ │ └── WaterMarkActivity_ImageFilter.java │ │ │ └── tag │ │ │ │ ├── AddTagActivity.java │ │ │ │ ├── EmojiconTextView.java │ │ │ │ ├── PreViewActivity.java │ │ │ │ ├── ShowTagActivity.java │ │ │ │ ├── TagInfo.java │ │ │ │ ├── TagView.java │ │ │ │ ├── TagViewLeft.java │ │ │ │ └── TagViewRight.java │ │ │ └── util │ │ │ ├── BitmapLoader.java │ │ │ ├── FileUtils.java │ │ │ ├── Logger.java │ │ │ └── NormalUtils.java │ └── res │ │ ├── anim │ │ ├── black_anim.xml │ │ └── white_anim.xml │ │ ├── drawable-hdpi │ │ ├── brand_tag_point_black_bg.png │ │ ├── brand_tag_point_white_bg.png │ │ ├── camera_crop_height.png │ │ ├── camera_crop_width.png │ │ ├── ic_launcher.png │ │ ├── icon_place.png │ │ ├── icon_tag_brand_active.png │ │ ├── icon_tag_brand_normal.png │ │ ├── icon_tag_geolocation_active.png │ │ ├── icon_tag_geolocation_normal.png │ │ ├── icon_tag_user_active.png │ │ ├── icon_tag_user_normal.png │ │ ├── indicator_autocrop.png │ │ ├── tag_text_bg.9.png │ │ ├── tag_text_bg_left.9.png │ │ ├── tag_text_bg_right.9.png │ │ ├── wm_1.png │ │ ├── wm_2.png │ │ ├── wm_3.png │ │ ├── wm_4.png │ │ ├── wm_5.png │ │ └── wm_6.png │ │ ├── drawable-mdpi │ │ └── ic_launcher.png │ │ ├── drawable-xhdpi │ │ ├── huishu.jpg │ │ └── ic_launcher.png │ │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ │ ├── layout │ │ ├── activity_add_tag.xml │ │ ├── activity_crop.xml │ │ ├── activity_main.xml │ │ ├── activity_pre_view.xml │ │ ├── activity_show_tag.xml │ │ ├── activity_take_pic.xml │ │ ├── activity_water_mark.xml │ │ ├── activity_water_mark_image_filter.xml │ │ ├── fragment_main.xml │ │ ├── tag_view_left.xml │ │ └── tag_view_right.xml │ │ ├── menu │ │ └── main.xml │ │ ├── values-v11 │ │ └── styles.xml │ │ ├── values-v14 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── jimageeditdemo │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── 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 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | BiaoQian -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.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 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | Android API 19 Platform 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidtagView 2 | Android 图片裁剪、添加水印、标签。仿nice添加标签 3 | 4 | #此贴在安卓bus上有引用,引用地址如下。 5 | http://www.apkbus.com/forum.php?mod=viewthread&tid=254407&extra=page%3D2%26filter%3Dsortid%26orderby%3Ddateline%26sortid%3D12 6 | 7 | 8 | #先看效果图 9 | ##1,拍照或者选择照片 10 | ![image](http://a2.qpic.cn/psb?/V13yyfT92tt1VM/1bTAATgappA4bK9yk3Sh25vIV..rp7ayI9ZqC6pZMdo!/b/dHUBAAAAAAAA&bo=gAJyBIQDQAYFChw!&rf=viewer_4) 11 | ##2,对照片进行裁剪 12 | ![image](http://a3.qpic.cn/psb?/V13yyfT92tt1VM/E4eZ4FGvKz.suxuOVB41PfVrnJPxr3PIPMKvm6C8jCE!/b/dG4AAAAAAAAA&bo=gAJyBIQDQAYFABY!&rf=viewer_4) 13 | ##3,添加贴图 14 | ![image](http://a3.qpic.cn/psb?/V13yyfT92tt1VM/hG5CE8Bt5fXCMFi6R.GQcOQDsHmdt95KpA*otyTrTgs!/b/dH8BAAAAAAAA&bo=gAJyBIQDQAYFABY!&rf=viewer_4) 15 | ##4,动态添加多个标签 16 | ![image](http://a2.qpic.cn/psb?/V13yyfT92tt1VM/O6lbvQlH6I6Bn0tDqDMxFsWlSMcviQC..3FoBkzJUOA!/b/dHIBAAAAAAAA&bo=gAJyBIQDQAYFABY!&rf=viewer_4) 17 | 18 | ##5,完成后可以保存图片 19 | ![image](http://a1.qpic.cn/psb?/V13yyfT92tt1VM/PzJ156zQtKHgYrR9qf10VAEkndxvAAIRgtg0wQ8Gn1Y!/b/dHQBAAAAAAAA&bo=gAJyBIQDQAYFABY!&rf=viewer_4) 20 | 21 | #这个项目可以直接导入到Android studio中,直接运行。大家可以自己研究下,直接使用到你自己的项目中。 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.example.jimageeditdemo" 9 | minSdkVersion 14 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 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.0.1' 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 C:\qcl\as\android-sdk-windows/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/androidTest/java/com/example/jimageeditdemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 38 | 39 | 40 | 45 | 46 | 47 | 48 | 53 | 54 | 55 | 60 | 61 | 62 | 67 | 68 | 69 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /app/src/main/apk/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/apk/app-debug.apk -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo; 2 | 3 | import android.support.v7.app.ActionBarActivity; 4 | import android.support.v7.app.ActionBar; 5 | import android.support.v4.app.Fragment; 6 | import android.os.Bundle; 7 | import android.view.LayoutInflater; 8 | import android.view.Menu; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.os.Build; 13 | 14 | public class MainActivity extends ActionBarActivity { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_main); 20 | 21 | if (savedInstanceState == null) { 22 | getSupportFragmentManager().beginTransaction() 23 | .add(R.id.container, new PlaceholderFragment()) 24 | .commit(); 25 | } 26 | } 27 | 28 | 29 | @Override 30 | public boolean onCreateOptionsMenu(Menu menu) { 31 | 32 | // Inflate the menu; this adds items to the action bar if it is present. 33 | getMenuInflater().inflate(R.menu.main, menu); 34 | return true; 35 | } 36 | 37 | @Override 38 | public boolean onOptionsItemSelected(MenuItem item) { 39 | // Handle action bar item clicks here. The action bar will 40 | // automatically handle clicks on the Home/Up button, so long 41 | // as you specify a parent activity in AndroidManifest.xml. 42 | int id = item.getItemId(); 43 | if (id == R.id.action_settings) { 44 | return true; 45 | } 46 | return super.onOptionsItemSelected(item); 47 | } 48 | 49 | /** 50 | * A placeholder fragment containing a simple view. 51 | */ 52 | public static class PlaceholderFragment extends Fragment { 53 | 54 | public PlaceholderFragment() { 55 | } 56 | 57 | @Override 58 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 59 | Bundle savedInstanceState) { 60 | View rootView = inflater.inflate(R.layout.fragment_main, container, false); 61 | return rootView; 62 | } 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/BitmapFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * 滤镜效果的类,定义了基本的渲染方法 7 | * 8 | */ 9 | public class BitmapFilter { 10 | /** 11 | * 所有滤镜效果的id 12 | */ 13 | public static final int GRAY_STYLE = 1; // 黑白效果 14 | public static final int BLOCK_STYLE = 2; // 版画 15 | public static final int OLD_STYLE = 3; // 怀旧效果 16 | public static final int ICE_STYLE = 4; //冰冻效果 17 | public static final int CARTON_STYLE = 5; //连环画效果 18 | public static final int MOLTEN_STYLE = 6; //铸融效果 19 | public static final int SOFTNESS_STYLE = 7; //柔化效果 20 | public static final int ECLOSION_STYLE = 8; //羽化效果 21 | public static final int RELIEF_STYLE = 9; // 浮雕效果 22 | public static final int OIL_STYLE = 10; // 油画效果 23 | public static final int INVERT_STYLE = 11; // 反色效果 24 | public static final int LIGHT_STYLE = 12; // 光照效果 25 | public static final int LOMO_STYLE = 13; //LOMO效果 26 | public static final int HAHA_STYLE = 14; //哈哈镜效果 27 | 28 | /** 29 | * 设置滤镜效果, 30 | * @param bitmap 31 | * @param 32 | */ 33 | public static Bitmap changeStyle(Bitmap bitmap, int styleNo) { 34 | Bitmap newBitmap = null; 35 | switch(styleNo){ 36 | case GRAY_STYLE: 37 | newBitmap = GrayFilter.changeToGray(bitmap); 38 | break; 39 | case BLOCK_STYLE: 40 | newBitmap = BlockFilter.changeToBlock(bitmap); 41 | break; 42 | case OLD_STYLE: 43 | newBitmap = OldFilter.changeToOld(bitmap); 44 | break; 45 | case ICE_STYLE: 46 | newBitmap = IceFilter.changeToIce(bitmap); 47 | break; 48 | case CARTON_STYLE: 49 | newBitmap = CartonFilter.changeToCarton(bitmap); 50 | break; 51 | case MOLTEN_STYLE: 52 | newBitmap = MoltenFilter.changeToMolten(bitmap); 53 | break; 54 | case SOFTNESS_STYLE: 55 | newBitmap = SoftnessFilter.changeToSoftness(bitmap); 56 | break; 57 | case ECLOSION_STYLE: 58 | newBitmap = EclosionFilter.changeToEclosion(bitmap); 59 | break; 60 | case RELIEF_STYLE: 61 | newBitmap = ReliefFilter.changeToRelief(bitmap); 62 | break; 63 | case OIL_STYLE: 64 | newBitmap = OilFilter.changeToOil(bitmap); 65 | break; 66 | case INVERT_STYLE: 67 | newBitmap = InvertFilter.chageToInvert(bitmap); 68 | break; 69 | case LIGHT_STYLE: 70 | newBitmap = LightFilter.changeToLight(bitmap); 71 | break; 72 | case LOMO_STYLE: 73 | newBitmap = LomoFilter.changeToLomo(bitmap); 74 | break; 75 | case HAHA_STYLE: 76 | newBitmap = HahaFilter.changeToHaha(bitmap); 77 | break; 78 | default: 79 | newBitmap = bitmap; 80 | break; 81 | } 82 | 83 | return newBitmap; 84 | } 85 | } 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/BlockFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | public class BlockFilter { 7 | // 版画效果函数 8 | public static Bitmap changeToBlock(Bitmap bitmap) { 9 | int width = bitmap.getWidth(); 10 | int height = bitmap.getHeight(); 11 | 12 | int dst[] = new int[width * height]; 13 | bitmap.getPixels(dst, 0, width, 0, 0, width, height); 14 | 15 | int iPixel = 0; 16 | int i, j, color, pos; 17 | for (j = 0; j < height; j++) { 18 | for (i = 0; i < width; i++) { 19 | pos = j * width + i; 20 | color = dst[pos]; 21 | int avg = (Color.red(color) + Color.green(color) + Color.blue(color)) / 3; 22 | if (avg >= 100) 23 | iPixel = 255; 24 | else 25 | iPixel = 0; 26 | 27 | dst[pos] = Color.rgb(iPixel, iPixel, iPixel); 28 | } 29 | } 30 | 31 | Bitmap bmpReturn = Bitmap.createBitmap(width, height, 32 | Bitmap.Config.RGB_565); 33 | bmpReturn.setPixels(dst, 0, width, 0, 0, width, height); 34 | return bmpReturn; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/CartonFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | public class CartonFilter { 7 | // 连环画效果 8 | public static Bitmap changeToCarton(Bitmap bitmap) { 9 | int width = bitmap.getWidth(); 10 | int height = bitmap.getHeight(); 11 | int dst[] = new int[width * height]; 12 | bitmap.getPixels(dst, 0, width, 0, 0, width, height); 13 | 14 | int R, G, B, pixel; 15 | int pos, pixColor; 16 | for (int y = 0; y < height; y++) { 17 | for (int x = 0; x < width; x++) { 18 | pos = y * width + x; 19 | pixColor = dst[pos]; 20 | R = Color.red(pixColor); // (color >> 16) & 0xFF 21 | G = Color.green(pixColor); // (color >> 8) & 0xFF; 22 | B = Color.blue(pixColor); // color & 0xFF 23 | pixel = G - B + G + R; 24 | if (pixel < 0) 25 | pixel = -pixel; 26 | pixel = pixel * R / 256; 27 | if (pixel > 255) 28 | pixel = 255; 29 | R = pixel; 30 | 31 | pixel = B - G + B + R; 32 | if (pixel < 0) 33 | pixel = -pixel; 34 | pixel = pixel * R / 256; 35 | if (pixel > 255) 36 | pixel = 255; 37 | G = pixel; 38 | 39 | pixel = B - G + B + R; 40 | if (pixel < 0) 41 | pixel = -pixel; 42 | pixel = pixel * G / 256; 43 | if (pixel > 255) 44 | pixel = 255; 45 | B = pixel; 46 | 47 | dst[pos] = Color.rgb(R, G, B); 48 | } 49 | } 50 | Bitmap processBitmap = Bitmap.createBitmap(width, height, 51 | Bitmap.Config.RGB_565); 52 | processBitmap.setPixels(dst, 0, width, 0, 0, width, height); 53 | return processBitmap; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/EclosionFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | public class EclosionFilter { 7 | // 羽化效果 8 | public static Bitmap changeToEclosion(Bitmap bitmap) { 9 | int width = bitmap.getWidth(); 10 | int height = bitmap.getHeight(); 11 | int dst[] = new int[width * height]; 12 | bitmap.getPixels(dst, 0, width, 0, 0, width, height); 13 | 14 | int ratio = width > height ? height*32768/width : width*32768/height; 15 | 16 | int cx = width >> 1; 17 | int cy = height >> 1; 18 | int max = cx * cx + cy * cy; 19 | int min = (int) (max * (1 - 0.5f)); 20 | int diff = max - min; 21 | 22 | int R, G, B; 23 | int pos, pixColor; 24 | for (int y = 0; y < height; y++) { 25 | for (int x = 0; x < width; x++) { 26 | pos = y * width + x; 27 | pixColor = dst[pos]; 28 | R = Color.red(pixColor); 29 | G = Color.green(pixColor); 30 | B = Color.blue(pixColor); 31 | 32 | int dx = cx - x; 33 | int dy = cy - y; 34 | if (width > height) { 35 | dx = (dx * ratio) >> 15; 36 | } else { 37 | dy = (dy * ratio) >> 15; 38 | } 39 | 40 | int distSq = dx * dx + dy * dy; 41 | float v = ((float) distSq / diff) * 255; 42 | R = (int) (R + (v)); 43 | G = (int) (G + (v)); 44 | B = (int) (B + (v)); 45 | R = (R > 255 ? 255 : (R < 0 ? 0 : R)); 46 | G = (G > 255 ? 255 : (G < 0 ? 0 : G)); 47 | B = (B > 255 ? 255 : (B < 0 ? 0 : B)); 48 | 49 | dst[pos] = Color.rgb(R, G, B); 50 | } 51 | } 52 | Bitmap processBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 53 | processBitmap.setPixels(dst, 0, width, 0, 0, width, height); 54 | return processBitmap; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/GrayFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Canvas; 5 | import android.graphics.ColorMatrix; 6 | import android.graphics.ColorMatrixColorFilter; 7 | import android.graphics.Paint; 8 | 9 | public class GrayFilter { 10 | // 黑白效果函数 11 | public static Bitmap changeToGray(Bitmap bitmap) { 12 | 13 | int width, height; 14 | width = bitmap.getWidth(); 15 | height = bitmap.getHeight(); 16 | 17 | Bitmap grayBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); 18 | Canvas canvas = new Canvas(grayBitmap); 19 | Paint paint = new Paint(); 20 | paint.setAntiAlias(true); // 设置抗锯齿 21 | 22 | //test 23 | /*float[] array = {1, 0, 0, 0, 100, 24 | 0, 1, 0, 0, 100, 25 | 0, 0, 1, 0, 0, 26 | 0, 0, 0, 1, 0}; 27 | ColorMatrix colorMatrix = new ColorMatrix(array);*/ 28 | 29 | ColorMatrix colorMatrix = new ColorMatrix(); 30 | colorMatrix.setSaturation(0); 31 | 32 | ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix); 33 | 34 | paint.setColorFilter(filter); 35 | canvas.drawBitmap(bitmap, 0, 0, paint); 36 | 37 | return grayBitmap; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/jimageeditdemo/api/HahaFilter.java: -------------------------------------------------------------------------------- 1 | package com.example.jimageeditdemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Color; 5 | 6 | public class HahaFilter { 7 | //哈哈镜效果 8 | public static Bitmap changeToHaha(Bitmap bitmap){ 9 | int centerX = bitmap.getWidth() / 2; 10 | int centerY = bitmap.getHeight() / 2; 11 | float radius = Math.min(centerX*2/3, centerY*2/3); 12 | float mutiple = 2.0f; 13 | return changeToHaha(bitmap, radius, centerX, centerY, mutiple); 14 | } 15 | 16 | /** 17 | * @param bitmap 原图bitmap 18 | * @param radius 半径 19 | * @param centerX 圆心x坐标 20 | * @param centerY 圆心y坐标 21 | * @param mutiple 系数 22 | * @return 23 | */ 24 | public static Bitmap changeToHaha(Bitmap bitmap, float radius, int centerX, int centerY, float mutiple){ 25 | int width = bitmap.getWidth(); 26 | int height = bitmap.getHeight(); 27 | 28 | int[] src = new int[width*height]; 29 | int[] dst = new int[width*height]; 30 | bitmap.getPixels(src, 0, width, 0, 0, width, height); 31 | 32 | int x, y, pos, color; 33 | int R, G, B; 34 | int distance; 35 | int src_x, src_y, src_color; 36 | int real_radius = (int)(radius / mutiple); 37 | 38 | for(y=0; y mHighlightViews = new ArrayList(); 17 | HighlightView mMotionHighlightView = null; 18 | float mLastX, mLastY; 19 | int mMotionEdge; 20 | //private Bitmap bitmap; 21 | Context mContext; 22 | 23 | @Override 24 | protected void onLayout(boolean changed, int left, int top, int right, 25 | int bottom) { 26 | super.onLayout(changed, left, top, right, bottom); 27 | if (mBitmapDisplayed.getBitmap() != null) { 28 | for (HighlightView hv : mHighlightViews) { 29 | hv.mMatrix.set(getImageMatrix()); 30 | hv.invalidate(); 31 | if (hv.mIsFocused) { 32 | centerBasedOnHighlightView(hv); 33 | } 34 | } 35 | } 36 | } 37 | 38 | public CropImageView(Context context, AttributeSet attrs) { 39 | super(context, attrs); 40 | } 41 | 42 | @Override 43 | protected void zoomTo(float scale, float centerX, float centerY) { 44 | super.zoomTo(scale, centerX, centerY); 45 | for (HighlightView hv : mHighlightViews) { 46 | hv.mMatrix.set(getImageMatrix()); 47 | hv.invalidate(); 48 | } 49 | } 50 | 51 | @Override 52 | protected void zoomIn() { 53 | super.zoomIn(); 54 | for (HighlightView hv : mHighlightViews) { 55 | hv.mMatrix.set(getImageMatrix()); 56 | hv.invalidate(); 57 | } 58 | } 59 | 60 | @Override 61 | protected void zoomOut() { 62 | super.zoomOut(); 63 | for (HighlightView hv : mHighlightViews) { 64 | hv.mMatrix.set(getImageMatrix()); 65 | hv.invalidate(); 66 | } 67 | } 68 | 69 | @Override 70 | protected void postTranslate(float deltaX, float deltaY) { 71 | super.postTranslate(deltaX, deltaY); 72 | for (int i = 0; i < mHighlightViews.size(); i++) { 73 | HighlightView hv = mHighlightViews.get(i); 74 | hv.mMatrix.postTranslate(deltaX, deltaY); 75 | hv.invalidate(); 76 | } 77 | } 78 | 79 | @Override 80 | public boolean onTouchEvent(MotionEvent event) { 81 | CropActivity cropImage = (CropActivity) mContext; 82 | if (cropImage.mSaving) { 83 | return false; 84 | } 85 | 86 | switch (event.getAction()) { 87 | case MotionEvent.ACTION_DOWN: 88 | for (int i = 0; i < mHighlightViews.size(); i++) { 89 | HighlightView hv = mHighlightViews.get(i); 90 | int edge = hv.getHit(event.getX(), event.getY()); 91 | Log.e(TAG, "edge:" + edge); 92 | if (edge != HighlightView.GROW_NONE) { 93 | mMotionEdge = edge; 94 | mMotionHighlightView = hv; 95 | mLastX = event.getX(); 96 | mLastY = event.getY(); 97 | //shark 此处是区别移动和缩放,还原代码即可打开缩放功能 98 | /*mMotionHighlightView 99 | .setMode((edge == HighlightView.MOVE) ? HighlightView.ModifyMode.Move 100 | : HighlightView.ModifyMode.Grow);*/ 101 | 102 | mMotionHighlightView.setMode(HighlightView.ModifyMode.Move); 103 | break; 104 | } 105 | } 106 | break; 107 | case MotionEvent.ACTION_UP: 108 | if (mMotionHighlightView != null) { 109 | centerBasedOnHighlightView(mMotionHighlightView); 110 | mMotionHighlightView.setMode(HighlightView.ModifyMode.None); 111 | } 112 | mMotionHighlightView = null; 113 | break; 114 | case MotionEvent.ACTION_MOVE: 115 | if (mMotionHighlightView != null) { 116 | mMotionHighlightView.handleMotion(mMotionEdge, event.getX() 117 | - mLastX, event.getY() - mLastY); 118 | mLastX = event.getX(); 119 | mLastY = event.getY(); 120 | 121 | if (true) { 122 | // This section of code is optional. It has some user 123 | // benefit in that moving the crop rectangle against 124 | // the edge of the screen causes scrolling but it means 125 | // that the crop rectangle is no longer fixed under 126 | // the user's finger. 127 | ensureVisible(mMotionHighlightView); 128 | } 129 | } 130 | break; 131 | } 132 | 133 | switch (event.getAction()) { 134 | case MotionEvent.ACTION_UP: 135 | center(true, true); 136 | break; 137 | case MotionEvent.ACTION_MOVE: 138 | // if we're not zoomed then there's no point in even allowing 139 | // the user to move the image around. This call to center puts 140 | // it back to the normalized location (with false meaning don't 141 | // animate). 142 | if (getScale() == 1F) { 143 | center(true, true); 144 | } 145 | break; 146 | } 147 | 148 | return true; 149 | } 150 | 151 | // Pan the displayed image to make sure the cropping rectangle is visible. 152 | private void ensureVisible(HighlightView hv) { 153 | Rect r = hv.mDrawRect; 154 | 155 | int panDeltaX1 = Math.max(0, getLeft() - r.left); 156 | int panDeltaX2 = Math.min(0, getRight() - r.right); 157 | 158 | int panDeltaY1 = Math.max(0, getTop() - r.top); 159 | int panDeltaY2 = Math.min(0, getBottom() - r.bottom); 160 | 161 | int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2; 162 | int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2; 163 | 164 | if (panDeltaX != 0 || panDeltaY != 0) { 165 | panBy(panDeltaX, panDeltaY); 166 | } 167 | } 168 | 169 | // If the cropping rectangle's size changed significantly, change the 170 | // view's center and scale according to the cropping rectangle. 171 | private void centerBasedOnHighlightView(HighlightView hv) { 172 | Rect drawRect = hv.mDrawRect; 173 | 174 | float width = drawRect.width(); 175 | float height = drawRect.height(); 176 | 177 | float thisWidth = getWidth(); 178 | float thisHeight = getHeight(); 179 | 180 | float z1 = thisWidth / width * .6F; 181 | float z2 = thisHeight / height * .6F; 182 | 183 | float zoom = Math.min(z1, z2); 184 | zoom = zoom * this.getScale(); 185 | zoom = Math.max(1F, zoom); 186 | 187 | if ((Math.abs(zoom - getScale()) / zoom) > .1) { 188 | float[] coordinates = new float[] { hv.mCropRect.centerX(), 189 | hv.mCropRect.centerY() }; 190 | getImageMatrix().mapPoints(coordinates); 191 | zoomTo(zoom, coordinates[0], coordinates[1], 300F); 192 | } 193 | 194 | ensureVisible(hv); 195 | } 196 | 197 | @Override 198 | protected void onDraw(Canvas canvas) { 199 | super.onDraw(canvas); 200 | for (int i = 0; i < mHighlightViews.size(); i++) { 201 | mHighlightViews.get(i).draw(canvas); 202 | } 203 | } 204 | 205 | public void add(HighlightView hv) { 206 | mHighlightViews.add(hv); 207 | invalidate(); 208 | } 209 | 210 | public void remove(HighlightView hv){ 211 | if(mHighlightViews.contains(hv)){ 212 | mHighlightViews.remove(hv); 213 | } 214 | invalidate(); 215 | } 216 | 217 | 218 | 219 | } 220 | 221 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/HighlightView.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import com.example.jimageeditdemo.R; 4 | 5 | import android.graphics.Canvas; 6 | import android.graphics.Matrix; 7 | import android.graphics.Paint; 8 | import android.graphics.Path; 9 | import android.graphics.Rect; 10 | import android.graphics.RectF; 11 | import android.graphics.Region; 12 | import android.graphics.drawable.Drawable; 13 | import android.view.View; 14 | 15 | // This class is used by CropImage to display a highlighted cropping rectangle 16 | // overlayed with the image. There are two coordinate spaces in use. One is 17 | // image, another is screen. computeLayout() uses mMatrix to map from image 18 | // space to screen space. 19 | class HighlightView { 20 | 21 | @SuppressWarnings("unused") 22 | private static final String TAG = "HighlightView"; 23 | View mContext; // The View displaying the image. 24 | 25 | public static final int GROW_NONE = (1 << 0); 26 | public static final int GROW_LEFT_EDGE = (1 << 1); 27 | public static final int GROW_RIGHT_EDGE = (1 << 2); 28 | public static final int GROW_TOP_EDGE = (1 << 3); 29 | public static final int GROW_BOTTOM_EDGE = (1 << 4); 30 | public static final int MOVE = (1 << 5); 31 | 32 | public HighlightView(View ctx) { 33 | mContext = ctx; 34 | } 35 | 36 | private void init() { 37 | android.content.res.Resources resources = mContext.getResources(); 38 | mResizeDrawableWidth = 39 | resources.getDrawable(R.drawable.camera_crop_width); 40 | mResizeDrawableHeight = 41 | resources.getDrawable(R.drawable.camera_crop_height); 42 | mResizeDrawableDiagonal = 43 | resources.getDrawable(R.drawable.indicator_autocrop); 44 | } 45 | 46 | boolean mIsFocused; 47 | boolean mHidden; 48 | 49 | public boolean hasFocus() { 50 | return mIsFocused; 51 | } 52 | 53 | public void setFocus(boolean f) { 54 | mIsFocused = f; 55 | } 56 | 57 | public void setHidden(boolean hidden) { 58 | mHidden = hidden; 59 | } 60 | 61 | protected void draw(Canvas canvas) { 62 | if (mHidden) { 63 | return; 64 | } 65 | canvas.save(); 66 | Path path = new Path(); 67 | if (!hasFocus()) { 68 | 69 | mOutlinePaint.setColor(0xFF000000); 70 | canvas.drawRect(mDrawRect, mOutlinePaint); 71 | } else { 72 | Rect viewDrawingRect = new Rect(); 73 | mContext.getDrawingRect(viewDrawingRect); 74 | if (mCircle) { 75 | float width = mDrawRect.width(); 76 | float height = mDrawRect.height(); 77 | path.addCircle(mDrawRect.left + (width / 2), 78 | mDrawRect.top + (height / 2), 79 | width / 2, 80 | Path.Direction.CW); 81 | mOutlinePaint.setColor(0xFFEF04D6); 82 | } else { 83 | path.addRect(new RectF(mDrawRect), Path.Direction.CW); 84 | mOutlinePaint.setColor(0xFFFF8A00); 85 | } 86 | canvas.clipPath(path, Region.Op.DIFFERENCE); 87 | canvas.drawRect(viewDrawingRect, 88 | hasFocus() ? mFocusPaint : mNoFocusPaint); 89 | 90 | canvas.restore(); 91 | canvas.drawPath(path, mOutlinePaint); 92 | 93 | if (mMode == ModifyMode.Grow) { 94 | if (mCircle) { 95 | int width = mResizeDrawableDiagonal.getIntrinsicWidth(); 96 | int height = mResizeDrawableDiagonal.getIntrinsicHeight(); 97 | 98 | int d = (int) Math.round(Math.cos(/*45deg*/Math.PI / 4D) 99 | * (mDrawRect.width() / 2D)); 100 | int x = mDrawRect.left 101 | + (mDrawRect.width() / 2) + d - width / 2; 102 | int y = mDrawRect.top 103 | + (mDrawRect.height() / 2) - d - height / 2; 104 | mResizeDrawableDiagonal.setBounds(x, y, 105 | x + mResizeDrawableDiagonal.getIntrinsicWidth(), 106 | y + mResizeDrawableDiagonal.getIntrinsicHeight()); 107 | mResizeDrawableDiagonal.draw(canvas); 108 | } else { 109 | int left = mDrawRect.left + 1; 110 | int right = mDrawRect.right + 1; 111 | int top = mDrawRect.top + 4; 112 | int bottom = mDrawRect.bottom + 3; 113 | 114 | int widthWidth = 115 | mResizeDrawableWidth.getIntrinsicWidth() / 2; 116 | int widthHeight = 117 | mResizeDrawableWidth.getIntrinsicHeight() / 2; 118 | int heightHeight = 119 | mResizeDrawableHeight.getIntrinsicHeight() / 2; 120 | int heightWidth = 121 | mResizeDrawableHeight.getIntrinsicWidth() / 2; 122 | 123 | int xMiddle = mDrawRect.left 124 | + ((mDrawRect.right - mDrawRect.left) / 2); 125 | int yMiddle = mDrawRect.top 126 | + ((mDrawRect.bottom - mDrawRect.top) / 2); 127 | 128 | mResizeDrawableWidth.setBounds(left - widthWidth, 129 | yMiddle - widthHeight, 130 | left + widthWidth, 131 | yMiddle + widthHeight); 132 | mResizeDrawableWidth.draw(canvas); 133 | 134 | mResizeDrawableWidth.setBounds(right - widthWidth, 135 | yMiddle - widthHeight, 136 | right + widthWidth, 137 | yMiddle + widthHeight); 138 | mResizeDrawableWidth.draw(canvas); 139 | 140 | mResizeDrawableHeight.setBounds(xMiddle - heightWidth, 141 | top - heightHeight, 142 | xMiddle + heightWidth, 143 | top + heightHeight); 144 | mResizeDrawableHeight.draw(canvas); 145 | 146 | mResizeDrawableHeight.setBounds(xMiddle - heightWidth, 147 | bottom - heightHeight, 148 | xMiddle + heightWidth, 149 | bottom + heightHeight); 150 | mResizeDrawableHeight.draw(canvas); 151 | } 152 | } 153 | } 154 | } 155 | 156 | public void setMode(ModifyMode mode) { 157 | if (mode != mMode) { 158 | mMode = mode; 159 | mContext.invalidate(); 160 | } 161 | } 162 | 163 | // Determines which edges are hit by touching at (x, y). 164 | //shark All to MOVE 165 | public int getHit(float x, float y) { 166 | Rect r = computeLayout(); 167 | final float hysteresis = 20F; 168 | int retval = GROW_NONE; 169 | 170 | if (mCircle) { 171 | float distX = x - r.centerX(); 172 | float distY = y - r.centerY(); 173 | int distanceFromCenter = 174 | (int) Math.sqrt(distX * distX + distY * distY); 175 | int radius = mDrawRect.width() / 2; 176 | int delta = distanceFromCenter - radius; 177 | if (Math.abs(delta) <= hysteresis) { 178 | if (Math.abs(distY) > Math.abs(distX)) { 179 | if (distY < 0) { 180 | retval = MOVE; 181 | } else { 182 | retval = MOVE; 183 | } 184 | } else { 185 | if (distX < 0) { 186 | retval = MOVE; 187 | } else { 188 | retval = MOVE; 189 | } 190 | } 191 | } else if (distanceFromCenter < radius) { 192 | retval = MOVE; 193 | } else { 194 | retval = GROW_NONE; 195 | } 196 | } else { 197 | // verticalCheck makes sure the position is between the top and 198 | // the bottom edge (with some tolerance). Similar for horizCheck. 199 | boolean verticalCheck = (y >= r.top - hysteresis) 200 | && (y < r.bottom + hysteresis); 201 | boolean horizCheck = (x >= r.left - hysteresis) 202 | && (x < r.right + hysteresis); 203 | 204 | // Check whether the position is near some edge(s). 205 | if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) { 206 | retval |= MOVE; 207 | } 208 | if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) { 209 | retval |= MOVE; 210 | } 211 | if ((Math.abs(r.top - y) < hysteresis) && horizCheck) { 212 | retval |= MOVE; 213 | } 214 | if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) { 215 | retval |= MOVE; 216 | } 217 | 218 | // Not near any edge but inside the rectangle: move. 219 | if (retval == GROW_NONE && r.contains((int) x, (int) y)) { 220 | retval = MOVE; 221 | } 222 | } 223 | return retval; 224 | } 225 | 226 | // Handles motion (dx, dy) in screen space. 227 | // The "edge" parameter specifies which edges the user is dragging. 228 | void handleMotion(int edge, float dx, float dy) { 229 | Rect r = computeLayout(); 230 | if (edge == GROW_NONE) { 231 | return; 232 | } else if (edge == MOVE) { 233 | // Convert to image space before sending to moveBy(). 234 | moveBy(dx * (mCropRect.width() / r.width()), 235 | dy * (mCropRect.height() / r.height())); 236 | } else { 237 | if (((GROW_LEFT_EDGE | GROW_RIGHT_EDGE) & edge) == 0) { 238 | dx = 0; 239 | } 240 | 241 | if (((GROW_TOP_EDGE | GROW_BOTTOM_EDGE) & edge) == 0) { 242 | dy = 0; 243 | } 244 | 245 | // Convert to image space before sending to growBy(). 246 | float xDelta = dx * (mCropRect.width() / r.width()); 247 | float yDelta = dy * (mCropRect.height() / r.height()); 248 | growBy((((edge & GROW_LEFT_EDGE) != 0) ? -1 : 1) * xDelta, 249 | (((edge & GROW_TOP_EDGE) != 0) ? -1 : 1) * yDelta); 250 | } 251 | } 252 | 253 | // Grows the cropping rectange by (dx, dy) in image space. 254 | void moveBy(float dx, float dy) { 255 | Rect invalRect = new Rect(mDrawRect); 256 | 257 | mCropRect.offset(dx, dy); 258 | 259 | // Put the cropping rectangle inside image rectangle. 260 | mCropRect.offset( 261 | Math.max(0, mImageRect.left - mCropRect.left), 262 | Math.max(0, mImageRect.top - mCropRect.top)); 263 | 264 | mCropRect.offset( 265 | Math.min(0, mImageRect.right - mCropRect.right), 266 | Math.min(0, mImageRect.bottom - mCropRect.bottom)); 267 | 268 | mDrawRect = computeLayout(); 269 | invalRect.union(mDrawRect); 270 | invalRect.inset(-10, -10); 271 | mContext.invalidate(invalRect); 272 | } 273 | 274 | // Grows the cropping rectange by (dx, dy) in image space. 275 | void growBy(float dx, float dy) { 276 | if (mMaintainAspectRatio) { 277 | if (dx != 0) { 278 | dy = dx / mInitialAspectRatio; 279 | } else if (dy != 0) { 280 | dx = dy * mInitialAspectRatio; 281 | } 282 | } 283 | 284 | // Don't let the cropping rectangle grow too fast. 285 | // Grow at most half of the difference between the image rectangle and 286 | // the cropping rectangle. 287 | RectF r = new RectF(mCropRect); 288 | if (dx > 0F && r.width() + 2 * dx > mImageRect.width()) { 289 | float adjustment = (mImageRect.width() - r.width()) / 2F; 290 | dx = adjustment; 291 | if (mMaintainAspectRatio) { 292 | dy = dx / mInitialAspectRatio; 293 | } 294 | } 295 | if (dy > 0F && r.height() + 2 * dy > mImageRect.height()) { 296 | float adjustment = (mImageRect.height() - r.height()) / 2F; 297 | dy = adjustment; 298 | if (mMaintainAspectRatio) { 299 | dx = dy * mInitialAspectRatio; 300 | } 301 | } 302 | 303 | r.inset(-dx, -dy); 304 | 305 | // Don't let the cropping rectangle shrink too fast. 306 | final float widthCap = 25F; 307 | if (r.width() < widthCap) { 308 | r.inset(-(widthCap - r.width()) / 2F, 0F); 309 | } 310 | float heightCap = mMaintainAspectRatio 311 | ? (widthCap / mInitialAspectRatio) 312 | : widthCap; 313 | if (r.height() < heightCap) { 314 | r.inset(0F, -(heightCap - r.height()) / 2F); 315 | } 316 | 317 | // Put the cropping rectangle inside the image rectangle. 318 | if (r.left < mImageRect.left) { 319 | r.offset(mImageRect.left - r.left, 0F); 320 | } else if (r.right > mImageRect.right) { 321 | r.offset(-(r.right - mImageRect.right), 0); 322 | } 323 | if (r.top < mImageRect.top) { 324 | r.offset(0F, mImageRect.top - r.top); 325 | } else if (r.bottom > mImageRect.bottom) { 326 | r.offset(0F, -(r.bottom - mImageRect.bottom)); 327 | } 328 | 329 | mCropRect.set(r); 330 | mDrawRect = computeLayout(); 331 | mContext.invalidate(); 332 | } 333 | 334 | // Returns the cropping rectangle in image space. 335 | public Rect getCropRect() { 336 | return new Rect((int) mCropRect.left, (int) mCropRect.top, 337 | (int) mCropRect.right, (int) mCropRect.bottom); 338 | } 339 | 340 | // Maps the cropping rectangle from image space to screen space. 341 | private Rect computeLayout() { 342 | RectF r = new RectF(mCropRect.left, mCropRect.top, 343 | mCropRect.right, mCropRect.bottom); 344 | mMatrix.mapRect(r); 345 | 346 | return new Rect(Math.round(r.left), Math.round(r.top), 347 | Math.round(r.right), Math.round(r.bottom)); 348 | } 349 | 350 | public void invalidate() { 351 | mDrawRect = computeLayout(); 352 | } 353 | 354 | public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean circle, 355 | boolean maintainAspectRatio) { 356 | if (circle) { 357 | maintainAspectRatio = true; 358 | } 359 | mMatrix = new Matrix(m); 360 | 361 | mCropRect = cropRect; 362 | mImageRect = new RectF(imageRect); 363 | mMaintainAspectRatio = maintainAspectRatio; 364 | mCircle = circle; 365 | 366 | mInitialAspectRatio = mCropRect.width() / mCropRect.height(); 367 | mDrawRect = computeLayout(); 368 | 369 | mFocusPaint.setARGB(125, 50, 50, 50); 370 | mNoFocusPaint.setARGB(125, 50, 50, 50); 371 | mOutlinePaint.setStrokeWidth(3F); 372 | mOutlinePaint.setStyle(Paint.Style.STROKE); 373 | mOutlinePaint.setAntiAlias(true); 374 | 375 | mMode = ModifyMode.None; 376 | init(); 377 | } 378 | 379 | enum ModifyMode { None, Move, Grow } 380 | 381 | private ModifyMode mMode = ModifyMode.None; 382 | 383 | Rect mDrawRect; // in screen space 384 | private RectF mImageRect; // in image space 385 | RectF mCropRect; // in image space 386 | Matrix mMatrix; 387 | 388 | private boolean mMaintainAspectRatio = false; 389 | private float mInitialAspectRatio; 390 | private boolean mCircle = false; 391 | 392 | private Drawable mResizeDrawableWidth; 393 | private Drawable mResizeDrawableHeight; 394 | private Drawable mResizeDrawableDiagonal; 395 | 396 | private final Paint mFocusPaint = new Paint(); 397 | private final Paint mNoFocusPaint = new Paint(); 398 | private final Paint mOutlinePaint = new Paint(); 399 | } 400 | 401 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/ImageViewTouchBase.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Matrix; 6 | import android.graphics.RectF; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Handler; 9 | import android.util.AttributeSet; 10 | import android.util.Log; 11 | import android.view.KeyEvent; 12 | import android.widget.ImageView; 13 | 14 | abstract class ImageViewTouchBase extends ImageView { 15 | 16 | @SuppressWarnings("unused") 17 | private static final String TAG = "ImageViewTouchBase"; 18 | 19 | // This is the base transformation which is used to show the image 20 | // initially. The current computation for this shows the image in 21 | // it's entirety, letterboxing as needed. One could choose to 22 | // show the image as cropped instead. 23 | // 24 | // This matrix is recomputed when we go from the thumbnail image to 25 | // the full size image. 26 | protected Matrix mBaseMatrix = new Matrix(); 27 | 28 | // This is the supplementary transformation which reflects what 29 | // the user has done in terms of zooming and panning. 30 | // 31 | // This matrix remains the same when we go from the thumbnail image 32 | // to the full size image. 33 | protected Matrix mSuppMatrix = new Matrix(); 34 | 35 | // This is the final matrix which is computed as the concatentation 36 | // of the base matrix and the supplementary matrix. 37 | private final Matrix mDisplayMatrix = new Matrix(); 38 | 39 | // Temporary buffer used for getting the values out of a matrix. 40 | private final float[] mMatrixValues = new float[9]; 41 | 42 | // The current bitmap being displayed. 43 | protected final RotateBitmap mBitmapDisplayed = new RotateBitmap(null); 44 | 45 | int mThisWidth = -1, mThisHeight = -1; 46 | 47 | float mMaxZoom; 48 | 49 | // ImageViewTouchBase will pass a Bitmap to the Recycler if it has finished 50 | // its use of that Bitmap. 51 | public interface Recycler { 52 | public void recycle(Bitmap b); 53 | } 54 | 55 | public void setRecycler(Recycler r) { 56 | mRecycler = r; 57 | } 58 | 59 | private Recycler mRecycler; 60 | 61 | @Override 62 | protected void onLayout(boolean changed, int left, int top, 63 | int right, int bottom) { 64 | super.onLayout(changed, left, top, right, bottom); 65 | mThisWidth = right - left; 66 | mThisHeight = bottom - top; 67 | Runnable r = mOnLayoutRunnable; 68 | if (r != null) { 69 | mOnLayoutRunnable = null; 70 | r.run(); 71 | } 72 | if (mBitmapDisplayed.getBitmap() != null) { 73 | getProperBaseMatrix(mBitmapDisplayed, mBaseMatrix); 74 | setImageMatrix(getImageViewMatrix()); 75 | } 76 | } 77 | 78 | @Override 79 | public boolean onKeyDown(int keyCode, KeyEvent event) { 80 | if (keyCode == KeyEvent.KEYCODE_BACK 81 | && event.getRepeatCount() == 0) { 82 | event.startTracking(); 83 | return true; 84 | } 85 | return super.onKeyDown(keyCode, event); 86 | } 87 | 88 | @Override 89 | public boolean onKeyUp(int keyCode, KeyEvent event) { 90 | Log.d(TAG, "onKeyUp"); 91 | if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() 92 | && !event.isCanceled()) { 93 | if (getScale() > 1.0f) { 94 | // If we're zoomed in, pressing Back jumps out to show the 95 | // entire image, otherwise Back returns the user to the gallery. 96 | zoomTo(1.0f); 97 | return true; 98 | } 99 | } 100 | return super.onKeyUp(keyCode, event); 101 | } 102 | 103 | protected Handler mHandler = new Handler(); 104 | 105 | @Override 106 | public void setImageBitmap(Bitmap bitmap) { 107 | setImageBitmap(bitmap, 0); 108 | } 109 | 110 | protected void setImageBitmap(Bitmap bitmap, int rotation) { 111 | super.setImageBitmap(bitmap); 112 | 113 | Drawable d = getDrawable(); 114 | if (d != null) { 115 | d.setDither(true); 116 | } 117 | 118 | Bitmap old = mBitmapDisplayed.getBitmap(); 119 | mBitmapDisplayed.setBitmap(bitmap); 120 | mBitmapDisplayed.setRotation(rotation); 121 | 122 | if (old != null && old != bitmap && mRecycler != null) { 123 | mRecycler.recycle(old); 124 | } 125 | } 126 | 127 | public void clear() { 128 | setImageBitmapResetBase(null, true); 129 | } 130 | 131 | private Runnable mOnLayoutRunnable = null; 132 | 133 | // This function changes bitmap, reset base matrix according to the size 134 | // of the bitmap, and optionally reset the supplementary matrix. 135 | public void setImageBitmapResetBase(final Bitmap bitmap, 136 | final boolean resetSupp) { 137 | setImageRotateBitmapResetBase(new RotateBitmap(bitmap), resetSupp); 138 | } 139 | 140 | public void setImageRotateBitmapResetBase(final RotateBitmap bitmap, 141 | final boolean resetSupp) { 142 | 143 | final int viewWidth = getWidth(); 144 | 145 | if (viewWidth <= 0) { 146 | mOnLayoutRunnable = new Runnable() { 147 | public void run() { 148 | setImageRotateBitmapResetBase(bitmap, resetSupp); 149 | } 150 | }; 151 | return; 152 | } 153 | //setImageBitmap(null); 154 | if (bitmap.getBitmap() != null) { 155 | 156 | getProperBaseMatrix(bitmap, mBaseMatrix); 157 | setImageBitmap(bitmap.getBitmap(), bitmap.getRotation()); 158 | 159 | } else { 160 | mBaseMatrix.reset(); 161 | setImageBitmap(null); 162 | } 163 | 164 | if (resetSupp) { 165 | mSuppMatrix.reset(); 166 | } 167 | setImageMatrix(getImageViewMatrix()); 168 | mMaxZoom = maxZoom(); 169 | } 170 | // Center as much as possible in one or both axis. Centering is 171 | // defined as follows: if the image is scaled down below the 172 | // view's dimensions then center it (literally). If the image 173 | // is scaled larger than the view and is translated out of view 174 | // then translate it back into view (i.e. eliminate black bars). 175 | protected void center(boolean horizontal, boolean vertical) { 176 | Log.d(TAG, "center"); 177 | if (mBitmapDisplayed.getBitmap() == null) { 178 | return; 179 | } 180 | 181 | Matrix m = getImageViewMatrix(); 182 | 183 | RectF rect = new RectF(0, 0, 184 | mBitmapDisplayed.getBitmap().getWidth(), 185 | mBitmapDisplayed.getBitmap().getHeight()); 186 | 187 | m.mapRect(rect); 188 | 189 | float height = rect.height(); 190 | float width = rect.width(); 191 | 192 | float deltaX = 0, deltaY = 0; 193 | 194 | if (vertical) { 195 | int viewHeight = getHeight(); 196 | if (height < viewHeight) { 197 | deltaY = (viewHeight - height) / 2 - rect.top; 198 | } else if (rect.top > 0) { 199 | deltaY = -rect.top; 200 | } else if (rect.bottom < viewHeight) { 201 | deltaY = getHeight() - rect.bottom; 202 | } 203 | } 204 | 205 | if (horizontal) { 206 | int viewWidth = getWidth(); 207 | if (width < viewWidth) { 208 | deltaX = (viewWidth - width) / 2 - rect.left; 209 | } else if (rect.left > 0) { 210 | deltaX = -rect.left; 211 | } else if (rect.right < viewWidth) { 212 | deltaX = viewWidth - rect.right; 213 | } 214 | } 215 | 216 | postTranslate(deltaX, deltaY); 217 | setImageMatrix(getImageViewMatrix()); 218 | } 219 | 220 | public ImageViewTouchBase(Context context) { 221 | super(context); 222 | init(); 223 | } 224 | 225 | public ImageViewTouchBase(Context context, AttributeSet attrs) { 226 | super(context, attrs); 227 | init(); 228 | } 229 | 230 | private void init() { 231 | setScaleType(ImageView.ScaleType.MATRIX); 232 | } 233 | 234 | protected float getValue(Matrix matrix, int whichValue) { 235 | matrix.getValues(mMatrixValues); 236 | return mMatrixValues[whichValue]; 237 | } 238 | 239 | // Get the scale factor out of the matrix. 240 | protected float getScale(Matrix matrix) { 241 | Log.d(TAG, "getScale(Matrix matrix)"); 242 | return getValue(matrix, Matrix.MSCALE_X); 243 | } 244 | 245 | protected float getScale() { 246 | Log.d(TAG, "getScale"); 247 | return getScale(mSuppMatrix); 248 | } 249 | 250 | // Setup the base matrix so that the image is centered and scaled properly. 251 | private void getProperBaseMatrix(RotateBitmap bitmap, Matrix matrix) { 252 | Log.d(TAG, "getProperBaseMatrix"); 253 | float viewWidth = getWidth(); 254 | float viewHeight = getHeight(); 255 | 256 | float w = bitmap.getWidth(); 257 | float h = bitmap.getHeight(); 258 | matrix.reset(); 259 | 260 | // We limit up-scaling to 3x otherwise the result may look bad if it's 261 | // a small icon. 262 | float widthScale = Math.min(viewWidth / w, 3.0f); 263 | float heightScale = Math.min(viewHeight / h, 3.0f); 264 | float scale = Math.min(widthScale, heightScale); 265 | 266 | matrix.postConcat(bitmap.getRotateMatrix()); 267 | matrix.postScale(scale, scale); 268 | 269 | matrix.postTranslate( 270 | (viewWidth - w * scale) / 2F, 271 | (viewHeight - h * scale) / 2F); 272 | } 273 | 274 | // Combine the base matrix and the supp matrix to make the final matrix. 275 | protected Matrix getImageViewMatrix() { 276 | // The final matrix is computed as the concatentation of the base matrix 277 | // and the supplementary matrix. 278 | Log.d(TAG, "getImageViewMatrix"); 279 | mDisplayMatrix.set(mBaseMatrix); 280 | mDisplayMatrix.postConcat(mSuppMatrix); 281 | return mDisplayMatrix; 282 | } 283 | 284 | static final float SCALE_RATE = 1.25F; 285 | 286 | // Sets the maximum zoom, which is a scale relative to the base matrix. It 287 | // is calculated to show the image at 400% zoom regardless of screen or 288 | // image orientation. If in the future we decode the full 3 megapixel image, 289 | // rather than the current 1024x768, this should be changed down to 200%. 290 | protected float maxZoom() { 291 | if (mBitmapDisplayed.getBitmap() == null) { 292 | return 1F; 293 | } 294 | 295 | float fw = (float) mBitmapDisplayed.getWidth() / (float) mThisWidth; 296 | float fh = (float) mBitmapDisplayed.getHeight() / (float) mThisHeight; 297 | float max = Math.max(fw, fh) * 4; 298 | return max; 299 | } 300 | 301 | protected void zoomTo(float scale, float centerX, float centerY) { 302 | if (scale > mMaxZoom) { 303 | scale = mMaxZoom; 304 | } 305 | 306 | float oldScale = getScale(); 307 | float deltaScale = scale / oldScale; 308 | 309 | mSuppMatrix.postScale(deltaScale, deltaScale, centerX, centerY); 310 | setImageMatrix(getImageViewMatrix()); 311 | center(true, true); 312 | } 313 | 314 | protected void zoomTo(final float scale, final float centerX, 315 | final float centerY, final float durationMs) { 316 | final float incrementPerMs = (scale - getScale()) / durationMs; 317 | final float oldScale = getScale(); 318 | final long startTime = System.currentTimeMillis(); 319 | 320 | mHandler.post(new Runnable() { 321 | public void run() { 322 | long now = System.currentTimeMillis(); 323 | float currentMs = Math.min(durationMs, now - startTime); 324 | float target = oldScale + (incrementPerMs * currentMs); 325 | zoomTo(target, centerX, centerY); 326 | 327 | if (currentMs < durationMs) { 328 | mHandler.post(this); 329 | } 330 | } 331 | }); 332 | } 333 | 334 | protected void zoomTo(float scale) { 335 | float cx = getWidth() / 2F; 336 | float cy = getHeight() / 2F; 337 | 338 | zoomTo(scale, cx, cy); 339 | } 340 | 341 | protected void zoomToPoint(float scale, float pointX, float pointY) { 342 | float cx = getWidth() / 2F; 343 | float cy = getHeight() / 2F; 344 | 345 | panBy(cx - pointX, cy - pointY); 346 | zoomTo(scale, cx, cy); 347 | } 348 | 349 | protected void zoomIn() { 350 | zoomIn(SCALE_RATE); 351 | } 352 | 353 | protected void zoomOut() { 354 | zoomOut(SCALE_RATE); 355 | } 356 | 357 | protected void zoomIn(float rate) { 358 | if (getScale() >= mMaxZoom) { 359 | return; // Don't let the user zoom into the molecular level. 360 | } 361 | if (mBitmapDisplayed.getBitmap() == null) { 362 | return; 363 | } 364 | 365 | float cx = getWidth() / 2F; 366 | float cy = getHeight() / 2F; 367 | 368 | mSuppMatrix.postScale(rate, rate, cx, cy); 369 | setImageMatrix(getImageViewMatrix()); 370 | } 371 | 372 | protected void zoomOut(float rate) { 373 | if (mBitmapDisplayed.getBitmap() == null) { 374 | return; 375 | } 376 | 377 | float cx = getWidth() / 2F; 378 | float cy = getHeight() / 2F; 379 | 380 | // Zoom out to at most 1x. 381 | Matrix tmp = new Matrix(mSuppMatrix); 382 | tmp.postScale(1F / rate, 1F / rate, cx, cy); 383 | 384 | if (getScale(tmp) < 1F) { 385 | mSuppMatrix.setScale(1F, 1F, cx, cy); 386 | } else { 387 | mSuppMatrix.postScale(1F / rate, 1F / rate, cx, cy); 388 | } 389 | setImageMatrix(getImageViewMatrix()); 390 | center(true, true); 391 | } 392 | 393 | protected void postTranslate(float dx, float dy) { 394 | mSuppMatrix.postTranslate(dx, dy); 395 | } 396 | 397 | protected void panBy(float dx, float dy) { 398 | postTranslate(dx, dy); 399 | setImageMatrix(getImageViewMatrix()); 400 | } 401 | } 402 | 403 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/MonitoredActivity.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import java.util.ArrayList; 4 | 5 | import android.app.Activity; 6 | import android.os.Bundle; 7 | 8 | public class MonitoredActivity extends Activity { 9 | 10 | private final ArrayList mListeners = 11 | new ArrayList(); 12 | 13 | public static interface LifeCycleListener { 14 | public void onActivityCreated(MonitoredActivity activity); 15 | public void onActivityDestroyed(MonitoredActivity activity); 16 | public void onActivityStarted(MonitoredActivity activity); 17 | public void onActivityStopped(MonitoredActivity activity); 18 | } 19 | 20 | public static class LifeCycleAdapter implements LifeCycleListener { 21 | public void onActivityCreated(MonitoredActivity activity) { 22 | } 23 | 24 | public void onActivityDestroyed(MonitoredActivity activity) { 25 | } 26 | 27 | public void onActivityStarted(MonitoredActivity activity) { 28 | } 29 | 30 | public void onActivityStopped(MonitoredActivity activity) { 31 | } 32 | } 33 | 34 | public void addLifeCycleListener(LifeCycleListener listener) { 35 | if (mListeners.contains(listener)) return; 36 | mListeners.add(listener); 37 | } 38 | 39 | public void removeLifeCycleListener(LifeCycleListener listener) { 40 | mListeners.remove(listener); 41 | } 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | for (LifeCycleListener listener : mListeners) { 47 | listener.onActivityCreated(this); 48 | } 49 | } 50 | 51 | @Override 52 | protected void onDestroy() { 53 | super.onDestroy(); 54 | for (LifeCycleListener listener : mListeners) { 55 | listener.onActivityDestroyed(this); 56 | } 57 | } 58 | 59 | @Override 60 | protected void onStart() { 61 | super.onStart(); 62 | for (LifeCycleListener listener : mListeners) { 63 | listener.onActivityStarted(this); 64 | } 65 | } 66 | 67 | @Override 68 | protected void onStop() { 69 | super.onStop(); 70 | for (LifeCycleListener listener : mListeners) { 71 | listener.onActivityStopped(this); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/RotateBitmap.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.Matrix; 5 | 6 | public class RotateBitmap { 7 | public static final String TAG = "RotateBitmap"; 8 | private Bitmap mBitmap; 9 | private int mRotation; 10 | 11 | public RotateBitmap(){ 12 | mRotation = 0; 13 | } 14 | public RotateBitmap(Bitmap bitmap) { 15 | mBitmap = bitmap; 16 | mRotation = 0; 17 | } 18 | 19 | public RotateBitmap(Bitmap bitmap, int rotation) { 20 | mBitmap = bitmap; 21 | mRotation = rotation % 360; 22 | } 23 | 24 | public void setRotation(int rotation) { 25 | mRotation = rotation; 26 | } 27 | 28 | public int getRotation() { 29 | return mRotation; 30 | } 31 | 32 | public Bitmap getBitmap() { 33 | return mBitmap; 34 | } 35 | 36 | public void setBitmap(Bitmap bitmap) { 37 | mBitmap = bitmap; 38 | } 39 | 40 | public Matrix getRotateMatrix() { 41 | // By default this is an identity matrix. 42 | Matrix matrix = new Matrix(); 43 | if (mRotation != 0) { 44 | // We want to do the rotation at origin, but since the bounding 45 | // rectangle will be changed after rotation, so the delta values 46 | // are based on old & new width/height respectively. 47 | int cx = mBitmap.getWidth() / 2; 48 | int cy = mBitmap.getHeight() / 2; 49 | matrix.preTranslate(-cx, -cy); 50 | matrix.postRotate(mRotation); 51 | matrix.postTranslate(getWidth() / 2, getHeight() / 2); 52 | } 53 | return matrix; 54 | } 55 | 56 | public boolean isOrientationChanged() { 57 | return (mRotation / 90) % 2 != 0; 58 | } 59 | 60 | public int getHeight() { 61 | if (isOrientationChanged()) { 62 | return mBitmap.getWidth(); 63 | } else { 64 | return mBitmap.getHeight(); 65 | } 66 | } 67 | 68 | public int getWidth() { 69 | if (isOrientationChanged()) { 70 | return mBitmap.getHeight(); 71 | } else { 72 | return mBitmap.getWidth(); 73 | } 74 | } 75 | 76 | public void recycle() { 77 | if (mBitmap != null) { 78 | mBitmap.recycle(); 79 | mBitmap = null; 80 | } 81 | } 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/TakePicActivity.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.view.Display; 11 | import android.view.View; 12 | import android.view.View.OnClickListener; 13 | import android.widget.Button; 14 | 15 | import com.example.jimageeditdemo.R; 16 | import com.pmmq.pmmqproject.config.Constant; 17 | import com.pmmq.pmmqproject.ui.tag.PreViewActivity; 18 | import com.pmmq.pmmqproject.util.FileUtils; 19 | import com.pmmq.pmmqproject.util.Logger; 20 | 21 | import java.io.File; 22 | import java.text.SimpleDateFormat; 23 | import java.util.Date; 24 | 25 | /** 26 | * @author shark 27 | * @ClassName: TakePicActivity 28 | * @Description: 照片选取 29 | * @date 2014年11月26日 上午10:53:58 30 | */ 31 | public class TakePicActivity extends Activity implements OnClickListener { 32 | private String TAG = "TakePicActivity"; 33 | //照片存储地址,这个照片没有添加标签 34 | public static final String IMAGE_SAVE = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + "/Camera"; 35 | public final static String IMAGE_URI = "iamge_uri"; 36 | public final static String CROP_IMAGE_URI = "crop_image_uri"; 37 | 38 | public Uri mCameraImageUri; 39 | // public Uri mImageUri; 40 | 41 | public final static int REQ_CODE_GALLERY = 201; 42 | public final static int REQ_CODE_CAMERA = 203; 43 | public final static int REQ_CODE_PHOTO_CROP = 102; 44 | 45 | private Button mSelectBtn; 46 | // private ImageView mImageView; 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | setContentView(R.layout.activity_take_pic); 52 | 53 | 54 | //创建App缓存文件夹 55 | Constant.CACHEPATH = new FileUtils(this).makeAppDir(); 56 | Logger.d(TAG, "Constant.CACHEPATH = " + Constant.CACHEPATH); 57 | 58 | Display display = getWindowManager().getDefaultDisplay(); 59 | Constant.displayWidth = display.getWidth(); 60 | Constant.displayHeight = display.getHeight(); 61 | Logger.d(TAG, "Constant.displayWidth = " + Constant.displayWidth + "-- Constant.displayHeight = " + Constant.displayHeight); 62 | Constant.scale = getResources().getDisplayMetrics().density; 63 | Logger.d(TAG, "scale = " + Constant.scale); 64 | 65 | initViews(); 66 | } 67 | 68 | private void initViews() { 69 | // mImageView = (ImageView)findViewById(R.id.jimageview); 70 | mSelectBtn = (Button) findViewById(R.id.selectpic); 71 | mSelectBtn.setOnClickListener(this); 72 | } 73 | 74 | @Override 75 | public void onClick(View v) { 76 | // TODO Auto-generated method stub 77 | switch (v.getId()) { 78 | case R.id.selectpic: 79 | showPostMenu(); 80 | break; 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | //显示出选择菜单 87 | private void showPostMenu() { 88 | new AlertDialog.Builder(this).setItems(new String[]{"拍照", "相册"}, new DialogInterface.OnClickListener() { 89 | public void onClick(DialogInterface paramDialogInterface, int paramInt) { 90 | if (paramInt == 0) { 91 | Intent localIntent1 = new Intent("android.media.action.IMAGE_CAPTURE"); 92 | //设置相机图片的输出路径 93 | mCameraImageUri = Uri.fromFile(new File(IMAGE_SAVE, new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date()) + ".jpg")); 94 | localIntent1.putExtra("output", mCameraImageUri); 95 | Logger.d(TAG, "mCameraImageUri:" + mCameraImageUri); 96 | TakePicActivity.this.startActivityForResult(localIntent1, REQ_CODE_CAMERA); 97 | return; 98 | } else { 99 | Intent localIntent2 = new Intent(); 100 | localIntent2.setType("image/*"); 101 | localIntent2.setAction("android.intent.action.GET_CONTENT"); 102 | TakePicActivity.this.startActivityForResult(Intent.createChooser(localIntent2, "选择照片"), REQ_CODE_GALLERY); 103 | } 104 | } 105 | }).show(); 106 | } 107 | 108 | @Override 109 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 110 | // TODO Auto-generated method stub 111 | super.onActivityResult(requestCode, resultCode, data); 112 | Logger.d(TAG, "onActivityResult "); 113 | 114 | if (resultCode == RESULT_OK) { 115 | if (requestCode == REQ_CODE_GALLERY) { 116 | // 从相册返回 117 | Uri localUri = data.getData(); 118 | if (localUri == null) { 119 | return; 120 | } 121 | readLocalImage(localUri); 122 | } else if (requestCode == REQ_CODE_CAMERA) { 123 | // 从相机返回,从设置相机图片的输出路径中提取数据 124 | Logger.d(TAG, "mCameraImageUri:" + mCameraImageUri); 125 | readLocalImage(mCameraImageUri); 126 | 127 | } else if (requestCode == REQ_CODE_PHOTO_CROP) { 128 | String imagePath = data.getStringExtra("tag_image_path"); 129 | Intent intent = new Intent(this, PreViewActivity.class); 130 | intent.putExtra("tag_image_path", imagePath); 131 | startActivity(intent); 132 | 133 | } 134 | } 135 | } 136 | 137 | //选择照片后进行图片裁剪 138 | private void readLocalImage(Uri uri) { 139 | if (uri != null) { 140 | startPhotoCrop(uri, null, REQ_CODE_PHOTO_CROP); // 图片裁剪 141 | } 142 | } 143 | 144 | /** 145 | * 开始裁剪 146 | * 147 | * @param uri 148 | * @param duplicatePath 149 | * @param reqCode 150 | * @return void 151 | * @Title: startPhotoCrop 152 | * @date 2012-12-12 上午11:15:38 153 | */ 154 | private void startPhotoCrop(Uri uri, String duplicatePath, int reqCode) { 155 | 156 | 157 | // Uri duplicateUri = preCrop(uri,duplicatePath); 158 | 159 | Intent intent = new Intent(this, CropActivity.class);//跳转到裁剪界面 160 | intent.putExtra(IMAGE_URI, uri); 161 | startActivityForResult(intent, reqCode); 162 | 163 | /**intent.setDataAndType(uri, "image/*"); 164 | intent.putExtra("crop", "true"); 165 | intent.putExtra("outputFormat", "JPEG"); 166 | // aspectX aspectY 是宽高的比例 167 | intent.putExtra("aspectX", 1); 168 | intent.putExtra("aspectY", 1); 169 | // outputX outputY 是裁剪图片宽高 170 | intent.putExtra("outputX", reqCode == REQ_CODE_BG_CROP ? BG_CROP_WIDTH 171 | : AVATAR_CROP_WIDTH); 172 | intent.putExtra("outputY", reqCode == REQ_CODE_BG_CROP ? BG_CROP_HEIGHT 173 | : AVATAR_CROP_HEIGHT); 174 | intent.putExtra(MediaStore.EXTRA_OUTPUT, duplicateUri); 175 | intent.putExtra("return-data", true);*/ 176 | 177 | } 178 | 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/TouchImageView.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Bitmap.Config; 6 | import android.graphics.Canvas; 7 | import android.graphics.Matrix; 8 | import android.graphics.PointF; 9 | import android.util.DisplayMetrics; 10 | import android.view.MotionEvent; 11 | import android.widget.ImageView; 12 | 13 | /** 14 | * 可移动、缩放、旋转的ImageView 15 | * 16 | * @author 17 | * @ClassName: TouchImageView 18 | * @Description: TODO 19 | * @date 2014年11月28日 下午4:52:44 20 | */ 21 | public class TouchImageView extends ImageView { 22 | 23 | float x_down = 0; 24 | float y_down = 0; 25 | PointF start = new PointF(); 26 | PointF mid = new PointF(); 27 | float oldDist = 1f; 28 | float oldRotation = 0; 29 | Matrix matrix = new Matrix(); 30 | Matrix matrix1 = new Matrix(); 31 | Matrix savedMatrix = new Matrix(); 32 | 33 | private static final int NONE = 0; 34 | private static final int DRAG = 1; 35 | private static final int ZOOM = 2; 36 | int mode = NONE; 37 | 38 | boolean matrixCheck = false; 39 | 40 | int widthScreen; 41 | int heightScreen; 42 | 43 | Bitmap gintama; 44 | 45 | public TouchImageView(Activity activity, Bitmap resBitmap) { 46 | super(activity); 47 | // gintama = BitmapFactory.decodeResource(getResources(), resId); 48 | gintama = resBitmap; 49 | DisplayMetrics dm = new DisplayMetrics(); 50 | activity.getWindowManager().getDefaultDisplay().getMetrics(dm); 51 | widthScreen = dm.widthPixels; 52 | heightScreen = dm.heightPixels; 53 | 54 | matrix = new Matrix(); 55 | } 56 | 57 | protected void onDraw(Canvas canvas) { 58 | canvas.save(); 59 | canvas.drawBitmap(gintama, matrix, null); 60 | canvas.restore(); 61 | } 62 | 63 | public boolean onTouchEvent(MotionEvent event) { 64 | switch (event.getAction() & MotionEvent.ACTION_MASK) { 65 | case MotionEvent.ACTION_DOWN: 66 | mode = DRAG; 67 | x_down = event.getX(); 68 | y_down = event.getY(); 69 | savedMatrix.set(matrix); 70 | break; 71 | case MotionEvent.ACTION_POINTER_DOWN: 72 | mode = ZOOM; 73 | oldDist = spacing(event); 74 | oldRotation = rotation(event); 75 | savedMatrix.set(matrix); 76 | midPoint(mid, event); 77 | break; 78 | case MotionEvent.ACTION_MOVE: 79 | if (mode == ZOOM) { 80 | matrix1.set(savedMatrix); 81 | float rotation = rotation(event) - oldRotation; 82 | float newDist = spacing(event); 83 | float scale = newDist / oldDist; 84 | matrix1.postScale(scale, scale, mid.x, mid.y);// 縮放 85 | matrix1.postRotate(rotation, mid.x, mid.y);// 旋轉 86 | matrixCheck = matrixCheck(); 87 | if (matrixCheck == false) { 88 | matrix.set(matrix1); 89 | invalidate(); 90 | } 91 | } else if (mode == DRAG) { 92 | matrix1.set(savedMatrix); 93 | matrix1.postTranslate(event.getX() - x_down, event.getY() 94 | - y_down);// 平移 95 | matrixCheck = matrixCheck(); 96 | matrixCheck = matrixCheck(); 97 | if (matrixCheck == false) { 98 | matrix.set(matrix1); 99 | invalidate(); 100 | } 101 | } 102 | break; 103 | case MotionEvent.ACTION_UP: 104 | case MotionEvent.ACTION_POINTER_UP: 105 | mode = NONE; 106 | break; 107 | } 108 | return true; 109 | } 110 | 111 | private boolean matrixCheck() { 112 | /*float[] f = new float[9]; 113 | matrix1.getValues(f); 114 | // 图片4个顶点的坐标 115 | float x1 = f[0] * 0 + f[1] * 0 + f[2]; 116 | float y1 = f[3] * 0 + f[4] * 0 + f[5]; 117 | float x2 = f[0] * gintama.getWidth() + f[1] * 0 + f[2]; 118 | float y2 = f[3] * gintama.getWidth() + f[4] * 0 + f[5]; 119 | float x3 = f[0] * 0 + f[1] * gintama.getHeight() + f[2]; 120 | float y3 = f[3] * 0 + f[4] * gintama.getHeight() + f[5]; 121 | float x4 = f[0] * gintama.getWidth() + f[1] * gintama.getHeight() + f[2]; 122 | float y4 = f[3] * gintama.getWidth() + f[4] * gintama.getHeight() + f[5]; 123 | // 图片现宽度 124 | double width = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); 125 | // 缩放比率判断 126 | if (width < widthScreen / 3 || width > widthScreen * 3) { 127 | return true; 128 | } 129 | // 出界判断 130 | if ((x1 < widthScreen / 3 && x2 < widthScreen / 3 131 | && x3 < widthScreen / 3 && x4 < widthScreen / 3) 132 | || (x1 > widthScreen * 2 / 3 && x2 > widthScreen * 2 / 3 133 | && x3 > widthScreen * 2 / 3 && x4 > widthScreen * 2 / 3) 134 | || (y1 < heightScreen / 3 && y2 < heightScreen / 3 135 | && y3 < heightScreen / 3 && y4 < heightScreen / 3) 136 | || (y1 > heightScreen * 2 / 3 && y2 > heightScreen * 2 / 3 137 | && y3 > heightScreen * 2 / 3 && y4 > heightScreen * 2 / 3)) { 138 | return true; 139 | } */ 140 | return false; 141 | } 142 | 143 | // 触碰两点间距离 144 | private float spacing(MotionEvent event) { 145 | float x = event.getX(0) - event.getX(1); 146 | float y = event.getY(0) - event.getY(1); 147 | // return FloatMath.sqrt(x * x + y * y); 148 | return (float) Math.sqrt(x * x + y * y); 149 | } 150 | 151 | // 取手势中心点 152 | private void midPoint(PointF point, MotionEvent event) { 153 | float x = event.getX(0) + event.getX(1); 154 | float y = event.getY(0) + event.getY(1); 155 | point.set(x / 2, y / 2); 156 | } 157 | 158 | // 取旋转角度 159 | private float rotation(MotionEvent event) { 160 | double delta_x = (event.getX(0) - event.getX(1)); 161 | double delta_y = (event.getY(0) - event.getY(1)); 162 | double radians = Math.atan2(delta_y, delta_x); 163 | return (float) Math.toDegrees(radians); 164 | } 165 | 166 | // 将移动,缩放以及旋转后的图层保存为新图片 167 | // 本例中沒有用到該方法,需要保存圖片的可以參考 168 | public Bitmap CreatNewPhoto() { 169 | Bitmap bitmap = Bitmap.createBitmap(widthScreen, widthScreen, 170 | Config.ARGB_8888); // 背景图片 171 | Canvas canvas = new Canvas(bitmap); // 新建画布 172 | canvas.drawBitmap(gintama, matrix, null); // 画图片 173 | canvas.save(Canvas.ALL_SAVE_FLAG); // 保存画布 174 | canvas.restore(); 175 | return bitmap; 176 | } 177 | 178 | 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/WaterMarkActivity.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Bitmap.Config; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.Canvas; 9 | import android.graphics.Matrix; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.os.Handler; 13 | import android.view.View; 14 | import android.view.View.OnClickListener; 15 | import android.widget.Button; 16 | import android.widget.ImageView; 17 | import android.widget.RelativeLayout; 18 | import android.widget.RelativeLayout.LayoutParams; 19 | 20 | import com.example.jimageeditdemo.R; 21 | import com.pmmq.pmmqproject.config.Constant; 22 | import com.pmmq.pmmqproject.ui.tag.AddTagActivity; 23 | import com.pmmq.pmmqproject.util.Logger; 24 | 25 | import java.io.File; 26 | import java.io.FileOutputStream; 27 | import java.io.IOException; 28 | import java.io.OutputStream; 29 | 30 | /** 31 | * @author shark 32 | * @ClassName: WaterMarkActivity 33 | * @Description: 添加水印,有两种水印方式:1.与目标图片叠加(布局中已隐藏) 2.贴纸形式,可以移动、缩放、旋转 34 | * @date 2014年11月26日 上午10:52:45 35 | */ 36 | public class WaterMarkActivity extends Activity implements OnClickListener { 37 | 38 | private String TAG = "WaterMarkActivity"; 39 | 40 | public final static int REQ_CODE = 211; 41 | 42 | private RelativeLayout mRootLayout; 43 | private ImageView mImageView; 44 | private ImageView mWatermark1; 45 | private ImageView mWatermark2; 46 | private ImageView mWatermark3; 47 | private Button mNextBtn; 48 | private ImageView mWatermark4; 49 | private ImageView mWatermark5; 50 | private ImageView mWatermark6; 51 | 52 | private final Handler mHandler = new Handler(); 53 | 54 | private Uri mImageUri; //目标图片的Uri 55 | private String mImagePath; //目标图片的路径 56 | 57 | private TouchImageView mWaterMarkView = null; 58 | 59 | private int[] mMarkRes = { 60 | R.drawable.wm_1, 61 | R.drawable.wm_2, 62 | R.drawable.wm_3 63 | }; 64 | 65 | private int[] mMarkRes_2 = { 66 | R.drawable.wm_5, 67 | R.drawable.wm_6 68 | }; 69 | 70 | @Override 71 | protected void onCreate(Bundle savedInstanceState) { 72 | // TODO Auto-generated method stub 73 | super.onCreate(savedInstanceState); 74 | setContentView(R.layout.activity_water_mark); 75 | 76 | //裁剪后传过来的图片路径 77 | mImagePath = getIntent().getStringExtra(TakePicActivity.CROP_IMAGE_URI); 78 | //裁剪后的uri 79 | mImageUri = Uri.parse(mImagePath); 80 | Logger.w(TAG, "imagePath:" + mImagePath); 81 | Logger.w(TAG, "mImageUri:" + mImageUri); 82 | initView(); 83 | 84 | } 85 | 86 | private void initView() { 87 | mRootLayout = (RelativeLayout) findViewById(R.id.wm_image_layout); 88 | mImageView = (ImageView) findViewById(R.id.wm_image); 89 | 90 | int width = getWindowManager().getDefaultDisplay().getWidth();//获取屏幕高度 91 | //设置图片显示宽高为屏幕宽度 92 | LayoutParams params = new LayoutParams(width, width); 93 | mImageView.setLayoutParams(params); 94 | if (mImageUri != null) { 95 | mImageView.setImageURI(mImageUri); 96 | } 97 | 98 | mWatermark1 = (ImageView) findViewById(R.id.wm_mark1); 99 | mWatermark2 = (ImageView) findViewById(R.id.wm_mark2); 100 | mWatermark3 = (ImageView) findViewById(R.id.wm_mark3); 101 | mWatermark1.setOnClickListener(this); 102 | mWatermark2.setOnClickListener(this); 103 | mWatermark3.setOnClickListener(this); 104 | 105 | mWatermark4 = (ImageView) findViewById(R.id.wm_mark4); 106 | mWatermark5 = (ImageView) findViewById(R.id.wm_mark5); 107 | mWatermark6 = (ImageView) findViewById(R.id.wm_mark6); 108 | mWatermark4.setOnClickListener(this); 109 | mWatermark5.setOnClickListener(this); 110 | mWatermark6.setOnClickListener(this); 111 | 112 | mNextBtn = (Button) findViewById(R.id.wm_next_btn); 113 | mNextBtn.setOnClickListener(this); 114 | 115 | } 116 | 117 | @Override 118 | public void onClick(View v) { 119 | // TODO Auto-generated method stub 120 | switch (v.getId()) { 121 | case R.id.wm_mark1: //水印方式1,隐藏中 122 | addWaterMark(0); 123 | break; 124 | case R.id.wm_mark2: 125 | addWaterMark(1); 126 | break; 127 | case R.id.wm_mark3: 128 | addWaterMark(2); 129 | break; 130 | case R.id.wm_mark4: 131 | addWaterMark_2(10); //空 ,不添加水印 132 | break; 133 | case R.id.wm_mark5: 134 | addWaterMark_2(0); //水印方式2 135 | break; 136 | case R.id.wm_mark6: 137 | addWaterMark_2(1); 138 | break; 139 | case R.id.wm_next_btn: 140 | goToNextActivity(); 141 | break; 142 | default: 143 | break; 144 | } 145 | } 146 | 147 | //添加水印贴纸,可以移动、缩放、旋转 148 | private void addWaterMark_2(int i) { 149 | 150 | if (i > mMarkRes_2.length) { //空 ,不添加水印 151 | if (mWaterMarkView != null) { 152 | mRootLayout.removeView(mWaterMarkView); 153 | mWaterMarkView = null; 154 | } 155 | } else { 156 | if (mWaterMarkView != null) { 157 | mRootLayout.removeView(mWaterMarkView); 158 | } 159 | //设置图片显示宽高为屏幕宽度 160 | LayoutParams params = new LayoutParams(Constant.displayWidth, Constant.displayWidth); 161 | 162 | Bitmap watermark = BitmapFactory.decodeResource(getResources(), mMarkRes_2[i]); 163 | 164 | int ww = watermark.getWidth(); 165 | int wh = watermark.getHeight(); 166 | Logger.w(TAG, "watermark ww:" + ww); 167 | Logger.w(TAG, "watermark wh:" + wh); 168 | 169 | //如果水印图片太大则压缩 170 | if (ww > Constant.displayWidth || wh > Constant.displayWidth) { 171 | // 缩放图片的尺寸 172 | float scaleWidth = (float) Constant.displayWidth / ww; 173 | float scaleHeight = (float) Constant.displayWidth / wh; 174 | float scale = Math.min(scaleWidth, scaleHeight) * (float) 0.8; //屏幕宽度的80% 175 | Matrix matrix = new Matrix(); 176 | matrix.postScale(scale, scale); 177 | // 产生缩放后的Bitmap对象 178 | watermark = Bitmap.createBitmap(watermark, 0, 0, ww, wh, matrix, false); 179 | } 180 | 181 | TouchImageView touchImageView = new TouchImageView(this, watermark); 182 | mRootLayout.addView(touchImageView, params); 183 | mWaterMarkView = touchImageView; 184 | } 185 | } 186 | 187 | /** 188 | * 从TouchImageView中获取图片Bitmap 189 | * 190 | * @return Bitmap 191 | */ 192 | private Bitmap getWaterMarkImage() { 193 | Bitmap photo = BitmapFactory.decodeFile(mImagePath); 194 | if (mWaterMarkView != null) { 195 | Bitmap mark = mWaterMarkView.CreatNewPhoto(); 196 | Bitmap a = createBitmap(photo, mark); 197 | 198 | photo.recycle(); 199 | mark.recycle(); 200 | return a; 201 | } else { 202 | return photo; 203 | } 204 | 205 | } 206 | 207 | //添加水印,方式1,图片叠加 208 | private void addWaterMark(int i) { 209 | Bitmap photo = BitmapFactory.decodeFile(mImagePath); 210 | Bitmap mark = BitmapFactory.decodeResource(this.getResources(), mMarkRes[i]); 211 | Bitmap a = createBitmap(photo, mark); 212 | mImageView.setImageBitmap(a); 213 | photo.recycle(); 214 | mark.recycle(); 215 | // a.recycle(); 216 | // saveMyBitmap(a); 217 | } 218 | 219 | /** 220 | * @param src 221 | * @param watermark 222 | * @return 223 | */ 224 | private Bitmap createBitmap(Bitmap src, Bitmap watermark) { 225 | if (src == null) { 226 | return null; 227 | } 228 | int w = src.getWidth(); 229 | int h = src.getHeight(); 230 | Logger.d(TAG, "createBitmap w:" + w); 231 | Logger.d(TAG, "createBitmap h:" + h); 232 | int ww = watermark.getWidth(); 233 | int wh = watermark.getHeight(); 234 | Logger.d(TAG, "watermark ww:" + ww); 235 | Logger.d(TAG, "watermark wh:" + wh); 236 | 237 | // 缩放图片的尺寸 238 | float scaleWidth = (float) w / ww; 239 | float scaleHeight = (float) h / wh; 240 | Logger.d(TAG, "watermark scaleWidth:" + scaleWidth); 241 | Logger.d(TAG, "watermark scaleHeight:" + scaleHeight); 242 | 243 | Matrix matrix = new Matrix(); 244 | matrix.postScale(scaleWidth, scaleHeight); 245 | // 产生缩放后的Bitmap对象 246 | Bitmap resizeBitmap = Bitmap.createBitmap(watermark, 0, 0, ww, wh, matrix, false); 247 | Logger.d(TAG, "resizeBitmap ww:" + resizeBitmap.getWidth()); 248 | Logger.d(TAG, "resizeBitmap wh:" + resizeBitmap.getHeight()); 249 | 250 | 251 | //create the new blank bitmap 252 | Bitmap newb = Bitmap.createBitmap(w, h, Config.ARGB_8888); 253 | //创建一个新的和SRC长度宽度一样的位图 254 | Canvas cv = new Canvas(newb); 255 | //draw src into 256 | cv.drawBitmap(src, 0, 0, null);//在 0,0坐标开始画入src 257 | //draw watermark into 258 | cv.drawBitmap(resizeBitmap, 0, 0, null);//在src的右下角画入水印 259 | //save all clip 260 | cv.save(Canvas.ALL_SAVE_FLAG);//保存 261 | //store 262 | cv.restore();//存储 263 | 264 | resizeBitmap.recycle(); 265 | return newb; 266 | } 267 | 268 | /** 269 | * 将Bitmap放入缓存, 270 | * 271 | * @param bitmap 272 | * @param filePath 273 | * @return void 274 | * @Title: saveDrawableToCache 275 | * @date 2012-12-14 上午9:27:38 276 | */ 277 | private void saveDrawableToCache(Bitmap bitmap, String filePath) { 278 | 279 | try { 280 | File file = new File(filePath); 281 | 282 | file.createNewFile(); 283 | 284 | OutputStream outStream = new FileOutputStream(file); 285 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); 286 | outStream.flush(); 287 | outStream.close(); 288 | 289 | } catch (IOException e) { 290 | 291 | e.printStackTrace(); 292 | } 293 | } 294 | 295 | /** 296 | * 下一步 297 | */ 298 | private void goToNextActivity() { 299 | //保存图片 300 | // final Bitmap photo = ((BitmapDrawable)mImageView.getDrawable()).getBitmap(); 301 | 302 | final Bitmap photo = getWaterMarkImage(); 303 | 304 | final String wmImagePath = mImagePath + "_water_mark"; 305 | Logger.w(TAG, "goToNextActivity wmImagePath:" + wmImagePath); 306 | mHandler.post(new Runnable() { 307 | 308 | @Override 309 | public void run() { 310 | // TODO Auto-generated method stub 311 | 312 | saveDrawableToCache(photo, wmImagePath); 313 | // photo.recycle(); 314 | } 315 | 316 | }); 317 | 318 | Intent intent = new Intent(this, AddTagActivity.class); 319 | intent.putExtra(TakePicActivity.CROP_IMAGE_URI, wmImagePath); 320 | startActivityForResult(intent, REQ_CODE); 321 | } 322 | 323 | @Override 324 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 325 | // TODO Auto-generated method stub 326 | super.onActivityResult(requestCode, resultCode, data); 327 | Logger.d(TAG, "onActivityResult "); 328 | 329 | if (resultCode == RESULT_OK) { 330 | if (requestCode == REQ_CODE) { 331 | String imagePath = data.getStringExtra("tag_image_path"); 332 | Intent intent = new Intent(); 333 | intent.putExtra("tag_image_path", imagePath); 334 | setResult(RESULT_OK, intent); 335 | finish(); 336 | } 337 | } 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/picture/WaterMarkActivity_ImageFilter.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.picture; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.Activity; 5 | import android.content.Intent; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.drawable.BitmapDrawable; 9 | import android.graphics.drawable.Drawable; 10 | import android.net.Uri; 11 | import android.os.Build; 12 | import android.os.Bundle; 13 | import android.os.Handler; 14 | import android.view.View; 15 | import android.view.View.OnClickListener; 16 | import android.widget.Button; 17 | import android.widget.ImageView; 18 | import android.widget.LinearLayout; 19 | 20 | import com.example.jimageeditdemo.R; 21 | import com.example.jimageeditdemo.api.BitmapFilter; 22 | import com.pmmq.pmmqproject.ui.tag.AddTagActivity; 23 | import com.pmmq.pmmqproject.util.Logger; 24 | 25 | import java.io.File; 26 | import java.io.FileOutputStream; 27 | import java.io.IOException; 28 | import java.io.OutputStream; 29 | 30 | /** 31 | * @author shark 32 | * @ClassName: WaterMarkActivity 33 | * @Description: 添加水印,有两种水印方式:1.与目标图片叠加(布局中已隐藏) 2.贴纸形式,可以移动、缩放、旋转 34 | * @date 2014年11月26日 上午10:52:45 35 | */ 36 | public class WaterMarkActivity_ImageFilter extends Activity implements OnClickListener { 37 | private Bitmap originalBitmap; 38 | private Bitmap sBitmap; 39 | private Button original_btn, button_change_to_gray, button_change_to_old, 40 | button_change_to_ice, button_change_to_carton, button_change_to_soft, 41 | button_change_to_eclosion, button_change_to_light, button_change_to_haha; 42 | 43 | private ImageView mImageView;//显示图片的 44 | private Button mNextBtn;//下一步 45 | 46 | private String TAG = "WaterMarkActivity"; 47 | 48 | public final static int REQ_CODE = 211; 49 | 50 | private final Handler mHandler = new Handler(); 51 | 52 | private Uri mImageUri; //目标图片的Uri 53 | private String mImagePath; //目标图片的路径 54 | 55 | private TouchImageView mWaterMarkView = null; 56 | 57 | 58 | @Override 59 | protected void onCreate(Bundle savedInstanceState) { 60 | // TODO Auto-generated method stub 61 | super.onCreate(savedInstanceState); 62 | setContentView(R.layout.activity_water_mark_image_filter); 63 | 64 | //裁剪后传过来的图片路径 65 | mImagePath = getIntent().getStringExtra(TakePicActivity.CROP_IMAGE_URI); 66 | //裁剪后的uri 67 | mImageUri = Uri.parse(mImagePath); 68 | originalBitmap = BitmapFactory.decodeFile(mImagePath); 69 | initView(); 70 | 71 | } 72 | 73 | private void initView() { 74 | findViewById(R.id.original_btn).setOnClickListener(this);//原始照片 75 | 76 | original_btn = (Button) findViewById(R.id.original_btn); 77 | button_change_to_gray = (Button) findViewById(R.id.button_change_to_gray); 78 | button_change_to_old = (Button) findViewById(R.id.button_change_to_old); 79 | button_change_to_ice = (Button) findViewById(R.id.button_change_to_ice); 80 | button_change_to_carton = (Button) findViewById(R.id.button_change_to_carton); 81 | button_change_to_soft = (Button) findViewById(R.id.button_change_to_soft); 82 | button_change_to_eclosion = (Button) findViewById(R.id.button_change_to_eclosion); 83 | button_change_to_light = (Button) findViewById(R.id.button_change_to_light); 84 | button_change_to_haha = (Button) findViewById(R.id.button_change_to_haha); 85 | 86 | original_btn.setOnClickListener(this); 87 | button_change_to_gray.setOnClickListener(this); 88 | button_change_to_old.setOnClickListener(this); 89 | button_change_to_ice.setOnClickListener(this); 90 | button_change_to_carton.setOnClickListener(this); 91 | button_change_to_soft.setOnClickListener(this); 92 | button_change_to_eclosion.setOnClickListener(this); 93 | button_change_to_light.setOnClickListener(this); 94 | button_change_to_haha.setOnClickListener(this); 95 | 96 | // originalBitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.huishu); 97 | 98 | mImageView = (ImageView) findViewById(R.id.wm_image); 99 | 100 | int width = getWindowManager().getDefaultDisplay().getWidth();//获取屏幕高度 101 | //设置图片显示宽高为屏幕宽度 102 | LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, width); 103 | mImageView.setLayoutParams(params); 104 | mImageView.setImageBitmap(originalBitmap); 105 | // if (mImageUri != null) { 106 | // mImageView.setImageURI(mImageUri); 107 | // } 108 | mNextBtn = (Button) findViewById(R.id.wm_next_btn); 109 | mNextBtn.setOnClickListener(this); 110 | 111 | initFilter(); 112 | } 113 | 114 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN) 115 | private void initFilter() { 116 | //无滤镜效果 117 | Drawable bd = new BitmapDrawable(getResources(), originalBitmap); 118 | original_btn.setBackground(bd); 119 | 120 | //黑白效果 121 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.GRAY_STYLE); 122 | bd = new BitmapDrawable(getResources(), sBitmap); 123 | button_change_to_gray.setBackground(bd); 124 | 125 | 126 | //怀旧效果 127 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.OLD_STYLE); 128 | bd = new BitmapDrawable(getResources(), sBitmap); 129 | button_change_to_old.setBackground(bd); 130 | 131 | //冰冻效果 132 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.ICE_STYLE); 133 | bd = new BitmapDrawable(getResources(), sBitmap); 134 | button_change_to_ice.setBackground(bd); 135 | 136 | //连环画效果 137 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.CARTON_STYLE); 138 | bd = new BitmapDrawable(getResources(), sBitmap); 139 | button_change_to_carton.setBackground(bd); 140 | 141 | //柔滑美白 142 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.SOFTNESS_STYLE); 143 | bd = new BitmapDrawable(getResources(), sBitmap); 144 | button_change_to_soft.setBackground(bd); 145 | 146 | //羽化效果 147 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.ECLOSION_STYLE); 148 | bd = new BitmapDrawable(getResources(), sBitmap); 149 | button_change_to_eclosion.setBackground(bd); 150 | 151 | //光照效果 152 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.LIGHT_STYLE); 153 | bd = new BitmapDrawable(getResources(), sBitmap); 154 | button_change_to_light.setBackground(bd); 155 | //哈哈镜效果 156 | sBitmap = BitmapFilter.changeStyle(originalBitmap, BitmapFilter.HAHA_STYLE); 157 | bd = new BitmapDrawable(getResources(), sBitmap); 158 | button_change_to_haha.setBackground(bd); 159 | 160 | } 161 | 162 | @Override 163 | public void onDestroy() { 164 | super.onDestroy(); 165 | if (sBitmap != null) { 166 | sBitmap.recycle(); 167 | sBitmap = null; 168 | } 169 | } 170 | 171 | int styleNo = BitmapFilter.GRAY_STYLE; 172 | 173 | @Override 174 | public void onClick(View v) { 175 | // TODO Auto-generated method stub 176 | // if (sBitmap != null) { 177 | // sBitmap.recycle(); 178 | // sBitmap = null; 179 | // } 180 | 181 | switch (v.getId()) { 182 | case R.id.wm_next_btn: 183 | goToNextActivity(); 184 | break; 185 | case R.id.original_btn: 186 | mImageView.setImageBitmap(originalBitmap); 187 | return; 188 | case R.id.button_change_to_gray: 189 | styleNo = BitmapFilter.GRAY_STYLE; 190 | break; 191 | 192 | case R.id.button_change_to_old: 193 | styleNo = BitmapFilter.OLD_STYLE; 194 | break; 195 | case R.id.button_change_to_ice: 196 | styleNo = BitmapFilter.ICE_STYLE; 197 | break; 198 | case R.id.button_change_to_carton: 199 | //连环画效果 200 | styleNo = BitmapFilter.CARTON_STYLE; 201 | break; 202 | 203 | case R.id.button_change_to_soft: 204 | //羽化效果 205 | styleNo = BitmapFilter.SOFTNESS_STYLE; 206 | break; 207 | case R.id.button_change_to_eclosion: 208 | styleNo = BitmapFilter.ECLOSION_STYLE; 209 | break; 210 | case R.id.button_change_to_light: 211 | styleNo = BitmapFilter.LIGHT_STYLE; 212 | break; 213 | case R.id.button_change_to_haha: 214 | //哈哈镜效果 215 | styleNo = BitmapFilter.HAHA_STYLE; 216 | break; 217 | //下面几个效果暂时不用 218 | // case R.id.button_change_to_block: 219 | // //版画效果 220 | // styleNo = BitmapFilter.BLOCK_STYLE; 221 | // break; 222 | // case R.id.button_change_to_oid: 223 | // //油画效果 224 | // styleNo = BitmapFilter.OIL_STYLE; 225 | // break; 226 | // case R.id.button_change_to_molten: 227 | // //铸融效果 228 | // styleNo = BitmapFilter.MOLTEN_STYLE; 229 | // break; 230 | // case R.id.button_change_to_invert: 231 | // //反色效果 232 | // styleNo = BitmapFilter.INVERT_STYLE; 233 | // break; 234 | // case R.id.button_change_to_relief: 235 | // //浮雕 236 | // styleNo = BitmapFilter.RELIEF_STYLE; 237 | // break; 238 | 239 | } 240 | sBitmap = BitmapFilter.changeStyle(originalBitmap, styleNo); 241 | mImageView.setImageBitmap(sBitmap); 242 | } 243 | 244 | 245 | /** 246 | * 将Bitmap放入缓存, 247 | * 248 | * @param bitmap 249 | * @param filePath 250 | * @return void 251 | * @Title: saveDrawableToCache 252 | * @date 2012-12-14 上午9:27:38 253 | */ 254 | private void saveDrawableToCache(Bitmap bitmap, String filePath) { 255 | try { 256 | File file = new File(filePath); 257 | file.createNewFile(); 258 | OutputStream outStream = new FileOutputStream(file); 259 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); 260 | outStream.flush(); 261 | outStream.close(); 262 | 263 | } catch (IOException e) { 264 | e.printStackTrace(); 265 | } 266 | } 267 | 268 | /** 269 | * 下一步 270 | */ 271 | private void goToNextActivity() { 272 | //保存图片 273 | // final Bitmap photo = ((BitmapDrawable)mImageView.getDrawable()).getBitmap(); 274 | 275 | // final Bitmap photo = getWaterMarkImage(); 276 | 277 | final String wmImagePath = mImagePath + "_water_mark"; 278 | Logger.w(TAG, "goToNextActivity wmImagePath:" + wmImagePath); 279 | mHandler.post(new Runnable() { 280 | 281 | @Override 282 | public void run() { 283 | // TODO Auto-generated method stub 284 | 285 | // saveDrawableToCache(photo, wmImagePath); 286 | saveDrawableToCache(sBitmap, wmImagePath); 287 | // photo.recycle(); 288 | } 289 | 290 | }); 291 | 292 | Intent intent = new Intent(this, AddTagActivity.class); 293 | intent.putExtra(TakePicActivity.CROP_IMAGE_URI, wmImagePath); 294 | startActivityForResult(intent, REQ_CODE); 295 | } 296 | 297 | @Override 298 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 299 | // TODO Auto-generated method stub 300 | super.onActivityResult(requestCode, resultCode, data); 301 | Logger.d(TAG, "onActivityResult "); 302 | 303 | if (resultCode == RESULT_OK) { 304 | if (requestCode == REQ_CODE) { 305 | String imagePath = data.getStringExtra("tag_image_path"); 306 | originalBitmap = BitmapFactory.decodeFile(imagePath); 307 | initView(); 308 | Intent intent = new Intent(); 309 | intent.putExtra("tag_image_path", imagePath); 310 | setResult(RESULT_OK, intent); 311 | finish(); 312 | } 313 | } 314 | } 315 | 316 | 317 | } 318 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/EmojiconTextView.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import android.content.Context; 4 | import android.text.SpannableStringBuilder; 5 | import android.util.AttributeSet; 6 | import android.widget.TextView; 7 | 8 | public class EmojiconTextView extends TextView { 9 | private int TextSize; 10 | 11 | public EmojiconTextView(Context paramContext) { 12 | super(paramContext); 13 | a(null); 14 | } 15 | 16 | public EmojiconTextView(Context paramContext, AttributeSet paramAttributeSet) { 17 | super(paramContext, paramAttributeSet); 18 | a(paramAttributeSet); 19 | } 20 | 21 | public EmojiconTextView(Context paramContext, 22 | AttributeSet paramAttributeSet, int paramInt) { 23 | super(paramContext, paramAttributeSet, paramInt); 24 | a(paramAttributeSet); 25 | } 26 | 27 | private void a(AttributeSet paramAttributeSet) { 28 | if (paramAttributeSet == null){ 29 | this.TextSize = (int) getTextSize(); 30 | }else{ 31 | // TypedArray localTypedArray = getContext().obtainStyledAttributes(paramAttributeSet, Emojicon); 32 | // this.TextSize = (int) localTypedArray.getDimension(0, getTextSize()); 33 | // localTypedArray.recycle(); 34 | } 35 | setText(getText()); 36 | } 37 | 38 | public void setEmojiconSize(int paramInt) { 39 | this.TextSize = paramInt; 40 | } 41 | 42 | public void setText(CharSequence mCharSequence, TextView.BufferType mBufferType) { 43 | SpannableStringBuilder localSpannableStringBuilder = new SpannableStringBuilder(mCharSequence); 44 | // uv.a(getContext(), localSpannableStringBuilder, this.TextSize); 45 | super.setText(localSpannableStringBuilder, mBufferType); 46 | } 47 | 48 | // public static final int[] Emojicon = { 2130772074 }; 49 | // public static final int Emojicon_emojiconSize; 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/PreViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import com.example.jimageeditdemo.R; 4 | import com.pmmq.pmmqproject.ui.picture.TakePicActivity; 5 | import com.pmmq.pmmqproject.util.Logger; 6 | 7 | import android.app.Activity; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.widget.ImageView; 11 | 12 | public class PreViewActivity extends Activity{ 13 | 14 | private String TAG = "PreViewActivity"; 15 | 16 | private Uri mImageUri; //目标图片的Uri 17 | private String mImagePath; //目标图片的路径 18 | 19 | private ImageView mImageView; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | // TODO Auto-generated method stub 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_pre_view); 26 | 27 | mImagePath = getIntent().getStringExtra("tag_image_path"); 28 | mImageUri = Uri.parse(mImagePath); 29 | Logger.d(TAG, "imagePath:" + mImagePath); 30 | Logger.d(TAG, "mImageUri:" + mImageUri); 31 | 32 | initView(); 33 | 34 | } 35 | 36 | private void initView(){ 37 | mImageView = (ImageView)findViewById(R.id.pv_image); 38 | if(mImageUri != null){ 39 | mImageView.setImageURI(mImageUri); 40 | } 41 | 42 | } 43 | 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/ShowTagActivity.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import android.app.Activity; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.view.View.OnClickListener; 8 | import android.widget.ImageView; 9 | import android.widget.RelativeLayout; 10 | import android.widget.RelativeLayout.LayoutParams; 11 | import android.widget.Toast; 12 | 13 | import com.example.jimageeditdemo.R; 14 | import com.pmmq.pmmqproject.config.Constant; 15 | import com.pmmq.pmmqproject.ui.picture.TakePicActivity; 16 | import com.pmmq.pmmqproject.ui.tag.TagView.TagViewListener; 17 | import com.pmmq.pmmqproject.util.Logger; 18 | 19 | import org.json.JSONArray; 20 | import org.json.JSONException; 21 | import org.json.JSONObject; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | public class ShowTagActivity extends Activity implements OnClickListener, TagViewListener { 27 | private String TAG = "ShowTagActivity"; 28 | 29 | private static int IMAGEDISPLAYWIDTH = 300; //此处是image的显示宽高,标签的坐标是在图片中的比例 30 | 31 | private Uri mImageUri; //目标图片的Uri 32 | private String mImagePath; //目标图片的路径 33 | 34 | private ImageView mImageView; 35 | private RelativeLayout mImageRootLayout; 36 | 37 | private List tagViews = new ArrayList(); 38 | private List tagInfoList = new ArrayList(); 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | // TODO Auto-generated method stub 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_show_tag); 45 | 46 | mImagePath = getIntent().getStringExtra(TakePicActivity.CROP_IMAGE_URI); 47 | mImageUri = Uri.parse(mImagePath); 48 | Logger.d(TAG, "imagePath:" + mImagePath); 49 | Logger.d(TAG, "mImageUri:" + mImageUri); 50 | 51 | String tagInfoListStr = getIntent().getStringExtra("tagInfoList"); 52 | Logger.w(TAG, "tagInfoListStr.toString():" + tagInfoListStr.toString()); 53 | parseInfoData(tagInfoListStr); 54 | 55 | initView(); 56 | 57 | addTagView(); 58 | } 59 | 60 | private void initView() { 61 | mImageView = (ImageView) findViewById(R.id.st_image); 62 | mImageView.setOnClickListener(this); 63 | mImageRootLayout = (RelativeLayout) findViewById(R.id.st_image_layout); 64 | 65 | if (mImageUri != null) { 66 | mImageView.setImageURI(mImageUri); 67 | } 68 | 69 | } 70 | 71 | private void addTagView() { 72 | 73 | for (TagInfo tagInfo : tagInfoList) { 74 | TagView tagView = null; 75 | 76 | //标签的坐标pic_x、pic_y是在图片中的比例,所以要根据显示的图片大小计算出准确位置 77 | double pointX = tagInfo.pic_x * IMAGEDISPLAYWIDTH * Constant.scale; 78 | double pointY = tagInfo.pic_y * IMAGEDISPLAYWIDTH * Constant.scale; 79 | 80 | switch (tagInfo.direct) { 81 | case Left: 82 | tagView = new TagViewLeft(this, null); 83 | 84 | tagInfo.leftMargin = (int) (pointX - 15 * Constant.scale); //根据屏幕密度计算使动画中心在点击点,15dp是margin 85 | tagInfo.topMargin = (int) (pointY - 15 * Constant.scale); 86 | tagInfo.rightMargin = 0; 87 | tagInfo.bottomMargin = 0; 88 | break; 89 | case Right: 90 | tagView = new TagViewRight(this, null); 91 | 92 | tagInfo.leftMargin = 0; 93 | tagInfo.topMargin = (int) (pointY - 15 * Constant.scale); 94 | tagInfo.rightMargin = (int) (IMAGEDISPLAYWIDTH * Constant.scale) - (int) pointX - (int) (15 * Constant.scale); 95 | tagInfo.bottomMargin = 0; 96 | break; 97 | } 98 | 99 | tagView.setData(tagInfo); 100 | tagView.setTagViewListener(this); 101 | RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( 102 | LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 103 | params.setMargins(tagInfo.leftMargin, tagInfo.topMargin, tagInfo.rightMargin, tagInfo.bottomMargin); 104 | mImageRootLayout.addView(tagView, params); 105 | tagViews.add(tagView); 106 | } 107 | } 108 | 109 | @Override 110 | public void onClick(View v) { 111 | // TODO Auto-generated method stub 112 | switch (v.getId()) { 113 | case R.id.st_image: 114 | showOrHideTagView(); 115 | break; 116 | 117 | default: 118 | break; 119 | } 120 | } 121 | 122 | /** 123 | * 显示隐藏标签 124 | */ 125 | private void showOrHideTagView() { 126 | for (TagView tagView : tagViews) { 127 | if (tagView.isShow) { 128 | tagView.setVisibility(View.GONE); 129 | } else { 130 | tagView.setVisibility(View.VISIBLE); 131 | } 132 | } 133 | } 134 | 135 | private void parseInfoData(String infoStr) { 136 | 137 | try { 138 | JSONArray jsonArray = new JSONArray(infoStr); 139 | 140 | for (int i = 0; i < jsonArray.length(); i++) { 141 | JSONObject infoObject = jsonArray.getJSONObject(i); 142 | TagInfo tagInfo = new TagInfo().getInstance(infoObject); 143 | tagInfoList.add(tagInfo); 144 | } 145 | Logger.w(TAG, "tagInfoList.toString():" + tagInfoList.toString()); 146 | 147 | } catch (JSONException e) { 148 | // TODO Auto-generated catch block 149 | e.printStackTrace(); 150 | } 151 | } 152 | 153 | @Override 154 | public void onTagViewClicked(View view, TagInfo info) { 155 | // TODO Auto-generated method stub 156 | Toast.makeText(this, info.bname, Toast.LENGTH_SHORT).show(); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/TagInfo.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import java.io.Serializable; 4 | 5 | import org.json.JSONObject; 6 | 7 | import android.os.Parcel; 8 | import android.os.Parcelable; 9 | 10 | public final class TagInfo implements Parcelable, Serializable { 11 | private static final long serialVersionUID = -2939266917839493174L; 12 | public String bname = ""; 13 | public long bid = 0L; 14 | public double pic_x = 0.0D; //点击点在图片中的位置,百分比 15 | public double pic_y = 0.0D; //点击点在图片中的位置,百分比 16 | public Direction direct = Direction.Left; 17 | public Type type = Type.Undefined; 18 | 19 | public int leftMargin; 20 | public int topMargin; 21 | public int rightMargin; 22 | public int bottomMargin; 23 | 24 | public enum Direction { 25 | Left("left"), Right("right"); 26 | 27 | private Direction(String valString) { 28 | this.valueString = valString; 29 | } 30 | 31 | public static int size(){ 32 | return Direction.values().length; 33 | } 34 | 35 | public String valueString; 36 | 37 | public String toString(){ 38 | return valueString; 39 | } 40 | 41 | public static Direction valueof(String vaString){ 42 | if(vaString.equals("left")){ 43 | return Direction.Left; 44 | }else if(vaString.equals("right")){ 45 | return Direction.Right; 46 | }else{ 47 | return null; 48 | } 49 | } 50 | } 51 | 52 | public enum Type { 53 | Undefined("undefined"),Exists("exists"),CustomPoint("custom_point"),OfficalPoint("offical_point"); 54 | 55 | private Type(String typeString) { 56 | this.valueString = typeString; 57 | } 58 | 59 | public static int size(){ 60 | return Type.values().length; 61 | } 62 | 63 | public String valueString; 64 | 65 | public String toString(){ 66 | return valueString; 67 | } 68 | 69 | public static Type valueof(String vaString){ 70 | if(vaString.equals("undefined")){ 71 | return Type.Undefined; 72 | }else if(vaString.equals("exists")){ 73 | return Type.Exists; 74 | }else if(vaString.equals("custom_point")){ 75 | return Type.CustomPoint; 76 | }else if(vaString.equals("offical_point")){ 77 | return Type.OfficalPoint; 78 | }else{ 79 | return null; 80 | } 81 | } 82 | } 83 | 84 | public TagInfo() { 85 | } 86 | 87 | private TagInfo(Parcel paramParcel) { 88 | this.bname = paramParcel.readString(); 89 | this.bid = paramParcel.readLong(); 90 | this.pic_x = paramParcel.readDouble(); 91 | this.pic_y = paramParcel.readDouble(); 92 | this.direct = Direction.valueof(paramParcel.readString()); 93 | this.type = Type.valueof(paramParcel.readString()); 94 | } 95 | 96 | public TagInfo(JSONObject paramJSONObject) { 97 | String str = null; 98 | try { 99 | this.bid = paramJSONObject.getLong("bid"); 100 | this.bname = paramJSONObject.getString("bname"); 101 | this.pic_x = paramJSONObject.getDouble("pic_x"); 102 | this.pic_y = paramJSONObject.getDouble("pic_y"); 103 | this.direct = Direction.valueof(paramJSONObject.getString("direct")); 104 | if(null == direct){ 105 | throw new RuntimeException("taginfo no direction"); 106 | } 107 | this.type = Type.Undefined; 108 | if (!paramJSONObject.has("type")) { 109 | return; 110 | } 111 | str = paramJSONObject.getString("type"); 112 | if (str.equals("exists")) { 113 | this.type = Type.Exists; 114 | return; 115 | } 116 | if (str.equals("custom_point")) { 117 | this.type = Type.CustomPoint; 118 | return; 119 | } 120 | if (str.equals("offical_point")) { 121 | this.type = Type.OfficalPoint; 122 | } 123 | } catch (Exception e) { 124 | e.printStackTrace(); 125 | } 126 | } 127 | 128 | public TagInfo getInstance(JSONObject paramJSONObject) { 129 | return new TagInfo(paramJSONObject); 130 | } 131 | 132 | public final JSONObject getjson() { 133 | JSONObject jsonobject = new JSONObject(); 134 | try { 135 | jsonobject.put("bid", bid); 136 | jsonobject.put("bname", bname); 137 | jsonobject.put("pic_x", String.valueOf(pic_x)); 138 | jsonobject.put("pic_y", String.valueOf(pic_y)); 139 | jsonobject.put("direct", direct.toString()); 140 | jsonobject.put("type", type.toString()); 141 | return jsonobject; 142 | } catch (Exception localException) { 143 | localException.printStackTrace(); 144 | } 145 | return jsonobject; 146 | } 147 | 148 | public final int describeContents() { 149 | return 0; 150 | } 151 | 152 | public final void writeToParcel(Parcel parcel, int i) { 153 | parcel.writeString(bname); 154 | parcel.writeLong(bid); 155 | parcel.writeDouble(pic_x); 156 | parcel.writeDouble(pic_y); 157 | parcel.writeString(direct.toString()); 158 | parcel.writeString(type.toString()); 159 | } 160 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/TagView.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import com.example.jimageeditdemo.R; 4 | 5 | import android.content.Context; 6 | import android.os.Handler; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | import android.view.animation.Animation; 10 | import android.view.animation.Animation.AnimationListener; 11 | import android.view.animation.AnimationUtils; 12 | import android.widget.ImageView; 13 | import android.widget.RelativeLayout; 14 | import android.widget.TextView; 15 | 16 | public class TagView extends RelativeLayout implements View.OnClickListener { 17 | public Animation blackAnimation1; 18 | public Animation blackAnimation2; 19 | public Animation whiteAnimation; 20 | 21 | protected TextView textview;//文字描述显示View 22 | public ImageView blackIcon1;//黑色圆圈View 23 | public ImageView blackIcon2;//黑色圆圈View 24 | protected ImageView brandIcon;//白色圆圈View 25 | protected ImageView geoIcon;//白色定位圆圈View 26 | public ImageView viewPointer;//指向brandIcon或者geoIcon,根据设置的类型的不同 27 | 28 | public boolean isShow = false; 29 | private TagViewListener listener; 30 | private Handler handler = new Handler(); 31 | 32 | public interface TagViewListener { 33 | public void onTagViewClicked(View view, TagInfo info); 34 | } 35 | 36 | public TagView(Context context) { 37 | this(context, null); 38 | } 39 | 40 | public TagView(Context context, AttributeSet attrs) { 41 | super(context, attrs); 42 | this.blackAnimation1 = AnimationUtils.loadAnimation(context, R.anim.black_anim); 43 | this.blackAnimation2 = AnimationUtils.loadAnimation(context, R.anim.black_anim); 44 | this.whiteAnimation = AnimationUtils.loadAnimation(context, R.anim.white_anim); 45 | this.setOnClickListener(this); 46 | } 47 | 48 | public final void clearAnim() { 49 | this.blackIcon1.clearAnimation(); 50 | this.blackIcon2.clearAnimation(); 51 | this.viewPointer.clearAnimation(); 52 | this.isShow = false; 53 | } 54 | 55 | public final void startBlackAnimation1(final ImageView imageView) { 56 | blackAnimation1.setAnimationListener(new AnimationListener() { 57 | @Override 58 | public void onAnimationStart(Animation animation) { 59 | } 60 | @Override 61 | public void onAnimationRepeat(Animation animation) { 62 | } 63 | @Override 64 | public void onAnimationEnd(Animation animation) { 65 | if (!isShow) { 66 | return; 67 | } 68 | handler.postDelayed(new Runnable() { 69 | @Override 70 | public void run() { 71 | imageView.clearAnimation(); 72 | blackAnimation1.reset(); 73 | startBlackAnimation2(blackIcon2); 74 | } 75 | }, 10); 76 | } 77 | }); 78 | imageView.clearAnimation(); 79 | imageView.startAnimation(blackAnimation1); 80 | } 81 | 82 | public final void startBlackAnimation2(final ImageView imageView) { 83 | blackAnimation2.setAnimationListener(new AnimationListener() { 84 | @Override 85 | public void onAnimationStart(Animation animation) { 86 | } 87 | @Override 88 | public void onAnimationRepeat(Animation animation) { 89 | } 90 | @Override 91 | public void onAnimationEnd(Animation animation) { 92 | if (!isShow) { 93 | return; 94 | } 95 | handler.postDelayed(new Runnable() { 96 | 97 | @Override 98 | public void run() { 99 | imageView.clearAnimation(); 100 | blackAnimation2.reset(); 101 | startWhiteAnimation(viewPointer); 102 | } 103 | }, 10); 104 | } 105 | }); 106 | imageView.clearAnimation(); 107 | imageView.startAnimation(blackAnimation2); 108 | } 109 | 110 | public final void startWhiteAnimation(final ImageView imageView) { 111 | whiteAnimation.setAnimationListener(new AnimationListener() { 112 | @Override 113 | public void onAnimationStart(Animation animation) { 114 | } 115 | @Override 116 | public void onAnimationRepeat(Animation animation) { 117 | } 118 | @Override 119 | public void onAnimationEnd(Animation animation) { 120 | if (!isShow) { 121 | return; 122 | } 123 | handler.postDelayed(new Runnable() { 124 | @Override 125 | public void run() { 126 | imageView.clearAnimation(); 127 | whiteAnimation.reset(); 128 | startBlackAnimation1(blackIcon1); 129 | } 130 | }, 10); 131 | } 132 | }); 133 | imageView.clearAnimation(); 134 | imageView.startAnimation(whiteAnimation); 135 | } 136 | 137 | protected final void setVisible() { 138 | if ((textview != null) && (taginfo != null)) { 139 | if (TagInfo.Type.CustomPoint != taginfo.type && TagInfo.Type.OfficalPoint != taginfo.type) { 140 | this.viewPointer = this.brandIcon; 141 | this.geoIcon.setVisibility(View.VISIBLE); 142 | this.brandIcon.setVisibility(View.GONE); 143 | } else { 144 | this.viewPointer = this.geoIcon; 145 | this.geoIcon.setVisibility(View.GONE); 146 | this.brandIcon.setVisibility(View.VISIBLE); 147 | } 148 | textview.setText(taginfo.bname); 149 | textview.setVisibility(View.VISIBLE); 150 | } 151 | clearAnim(); 152 | show(); 153 | } 154 | 155 | public void show() { 156 | if (this.isShow) { 157 | return; 158 | } 159 | this.isShow = true; 160 | startWhiteAnimation(viewPointer); 161 | } 162 | 163 | private TagInfo taginfo; 164 | 165 | public void setData(TagInfo mTagInfo) { 166 | this.taginfo = mTagInfo; 167 | setVisible(); 168 | } 169 | 170 | public TagInfo getData() { 171 | return taginfo; 172 | } 173 | 174 | public void setTagViewListener(TagViewListener listener) { 175 | this.listener = listener; 176 | } 177 | 178 | @Override 179 | public void onClick(View view) { 180 | if (null != listener) { 181 | listener.onTagViewClicked(view, taginfo); 182 | } 183 | } 184 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/TagViewLeft.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import com.example.jimageeditdemo.R; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | public class TagViewLeft extends TagView { 13 | public TagViewLeft(Context paramContext) { 14 | this(paramContext, null); 15 | } 16 | 17 | public TagViewLeft(Context paramContext, AttributeSet paramAttributeSet) { 18 | super(paramContext, paramAttributeSet); 19 | LayoutInflater.from(paramContext).inflate(R.layout.tag_view_left, this); 20 | this.textview = ((TextView) findViewById(R.id.text)); 21 | this.textview.getBackground().setAlpha(178); 22 | this.textview.setVisibility(View.VISIBLE); 23 | this.blackIcon1 = ((ImageView) findViewById(R.id.blackIcon1)); 24 | this.blackIcon2 = ((ImageView) findViewById(R.id.blackIcon2)); 25 | this.brandIcon = ((ImageView) findViewById(R.id.brandIcon)); 26 | this.geoIcon = ((ImageView) findViewById(R.id.geoIcon)); 27 | // this.brandIcon.setVisibility(View.GONE); 28 | this.viewPointer = brandIcon; 29 | setVisible(); 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/ui/tag/TagViewRight.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.ui.tag; 2 | 3 | import com.example.jimageeditdemo.R; 4 | 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | public class TagViewRight extends TagView { 13 | public TagViewRight(Context paramContext) { 14 | this(paramContext, null); 15 | } 16 | 17 | public TagViewRight(Context paramContext, AttributeSet paramAttributeSet) { 18 | super(paramContext, paramAttributeSet); 19 | LayoutInflater.from(paramContext).inflate(R.layout.tag_view_right, this); 20 | this.textview = ((TextView) findViewById(R.id.text)); 21 | this.textview.getBackground().setAlpha(178); 22 | this.textview.setVisibility(View.VISIBLE); 23 | this.blackIcon1 = ((ImageView) findViewById(R.id.blackIcon1)); 24 | this.blackIcon2 = ((ImageView) findViewById(R.id.blackIcon2)); 25 | this.brandIcon = ((ImageView) findViewById(R.id.brandIcon)); 26 | this.geoIcon = ((ImageView) findViewById(R.id.geoIcon)); 27 | // this.brandIcon.setVisibility(View.GONE); 28 | this.viewPointer = brandIcon; 29 | setVisible(); 30 | } 31 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/util/BitmapLoader.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.util; 2 | 3 | import android.content.ContentResolver; 4 | import android.content.Context; 5 | import android.content.res.Resources; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.BitmapFactory.Options; 9 | import android.location.Location; 10 | import android.media.ExifInterface; 11 | import android.net.Uri; 12 | import android.text.TextUtils; 13 | import android.widget.ImageView; 14 | import java.io.FileNotFoundException; 15 | import java.io.IOException; 16 | 17 | public class BitmapLoader 18 | { 19 | /* public static int calculateInSampleSize(BitmapFactory.Options paramOptions, int paramInt1, int paramInt2) 20 | { 21 | int i = paramOptions.outHeight; 22 | int j = paramOptions.outWidth; 23 | int k = 1; 24 | if ((i > paramInt2) || (j > paramInt1)) 25 | { 26 | int l = i / 2; 27 | int i1 = j / 2; 28 | while ((l / k > paramInt2) && (i1 / k > paramInt1)) 29 | k *= 2; 30 | } 31 | return k; 32 | }*/ 33 | /** 34 | * 计算压缩比例值 35 | * @param options 解析图片的配置信息 36 | * @param reqWidth 所需图片压缩尺寸最小宽度 37 | * @param reqHeight 所需图片压缩尺寸最小高度 38 | * @return 39 | */ 40 | public static int calculateInSampleSize(BitmapFactory.Options options, 41 | int reqWidth, int reqHeight) { 42 | // 保存图片原宽高值 43 | final int height = options. outHeight; 44 | final int width = options. outWidth; 45 | // 初始化压缩比例为1 46 | int inSampleSize = 1; 47 | 48 | // 当图片宽高值任何一个大于所需压缩图片宽高值时,进入循环计算系统 49 | if (height > reqHeight || width > reqWidth) { 50 | 51 | final int halfHeight = height / 2; 52 | final int halfWidth = width / 2; 53 | 54 | // 压缩比例值每次循环两倍增加, 55 | // 直到原图宽高值的一半除以压缩值后都~大于所需宽高值为止 56 | while ((halfHeight / inSampleSize) >= reqHeight 57 | && (halfWidth / inSampleSize) >= reqWidth) { 58 | inSampleSize *= 2; 59 | } 60 | } 61 | 62 | return inSampleSize; 63 | } 64 | 65 | /* 66 | private static String dec2DMS(double paramDouble) 67 | { 68 | if (paramDouble > 0.0D); 69 | while (true) 70 | { 71 | String str1 = Integer.toString((int)paramDouble) + "/1,"; 72 | double d1 = 60.0D * (paramDouble % 1.0D); 73 | String str2 = str1 + Integer.toString((int)d1) + "/1,"; 74 | double d2 = 60000.0D * (d1 % 1.0D); 75 | return str2 + Integer.toString((int)d2) + "/1000"; 76 | paramDouble = -paramDouble; 77 | } 78 | }*/ 79 | 80 | /** 81 | * 获取压缩后的图片 82 | * @param res 83 | * @param resId 84 | * @param reqWidth 所需图片压缩尺寸最小宽度 85 | * @param reqHeight 所需图片压缩尺寸最小高度 86 | * @return 87 | */ 88 | public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, 89 | int reqWidth, int reqHeight) { 90 | 91 | // 首先不加载图片,仅获取图片尺寸 92 | final BitmapFactory.Options options = new BitmapFactory.Options(); 93 | // 当inJustDecodeBounds设为true时,不会加载图片仅获取图片尺寸信息 94 | options.inJustDecodeBounds = true; 95 | // 此时仅会将图片信息会保存至options对象内,decode方法不会返回bitmap对象 96 | BitmapFactory.decodeResource(res, resId, options); 97 | 98 | // 计算压缩比例,如inSampleSize=4时,图片会压缩成原图的1/4 99 | options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); 100 | 101 | // 当inJustDecodeBounds设为false时,BitmapFactory.decode...就会返回图片对象了 102 | options. inJustDecodeBounds = false; 103 | // 利用计算的比例值获取压缩后的图片对象 104 | return BitmapFactory.decodeResource(res, resId, options); 105 | } 106 | 107 | 108 | public static Bitmap decodeSampledBitmapFromUri(ContentResolver paramContentResolver, Uri paramUri, int paramInt1, int paramInt2) 109 | { 110 | BitmapFactory.Options localOptions = getBitmapOptions(paramContentResolver, paramUri); 111 | Bitmap localObject = null; 112 | if (localOptions != null) 113 | { 114 | localOptions.inSampleSize = calculateInSampleSize(localOptions, paramInt1, paramInt2); 115 | localOptions.inJustDecodeBounds = false; 116 | } 117 | try 118 | { 119 | Bitmap localBitmap = BitmapFactory.decodeStream(paramContentResolver.openInputStream(paramUri), null, localOptions); 120 | localObject = localBitmap; 121 | return localObject; 122 | } 123 | catch (FileNotFoundException localFileNotFoundException) 124 | { 125 | localFileNotFoundException.printStackTrace(); 126 | } 127 | return null; 128 | } 129 | 130 | private static double dms2Dbl(String paramString) 131 | { 132 | double d1 = 999.0D; 133 | try 134 | { 135 | String[] arrayOfString1 = paramString.split(",", 3); 136 | String[] arrayOfString2 = arrayOfString1[0].split("/", 2); 137 | d1 = new Double(arrayOfString2[0]).doubleValue() / new Double(arrayOfString2[1]).doubleValue(); 138 | String[] arrayOfString3 = arrayOfString1[1].split("/", 2); 139 | d1 += new Double(arrayOfString3[0]).doubleValue() / new Double(arrayOfString3[1]).doubleValue() / 60.0D; 140 | String[] arrayOfString4 = arrayOfString1[2].split("/", 2); 141 | double d2 = new Double(arrayOfString4[0]).doubleValue(); 142 | double d3 = new Double(arrayOfString4[1]).doubleValue(); 143 | return d1 + d2 / d3 / 3600.0D; 144 | } 145 | catch (Exception localException) 146 | { 147 | } 148 | return d1; 149 | } 150 | 151 | /*public static Location exif2Loc(String paramString) 152 | { 153 | Location localLocation = new Location("exif"); 154 | int i = 1; 155 | String str1 = ""; 156 | String str2 = ""; 157 | double d1 = 0.0D; 158 | double d2 = 0.0D; 159 | try 160 | { 161 | ExifInterface localExifInterface = new ExifInterface(paramString); 162 | String str3 = localExifInterface.getAttribute("GPSLatitude"); 163 | String str4 = localExifInterface.getAttribute("GPSLongitude"); 164 | str1 = localExifInterface.getAttribute("GPSLatitudeRef"); 165 | str2 = localExifInterface.getAttribute("GPSLongitudeRef"); 166 | d1 = dms2Dbl(str3); 167 | if (d1 > 180.0D) 168 | i = 0; 169 | double d3 = dms2Dbl(str4); 170 | d2 = d3; 171 | if (d2 > 180.0D) 172 | i = 0; 173 | label110: if (i == 0) 174 | break label164; 175 | if (str1.contains("S")) 176 | d1 = -d1; 177 | if (str2.contains("W")) 178 | d2 = -d2; 179 | localLocation.setLatitude(d1); 180 | localLocation.setLongitude(d2); 181 | label164: return localLocation; 182 | } 183 | catch (IOException localIOException) 184 | { 185 | i = 0; 186 | break ; 187 | localLocation.setLatitude(Constant.GPS.lat); 188 | localLocation.setLongitude(Constant.GPS.lng); 189 | } 190 | return localLocation; 191 | } 192 | */ 193 | public static BitmapFactory.Options getBitmapOptions(ContentResolver paramContentResolver, Uri paramUri) 194 | { 195 | BitmapFactory.Options localOptions = new BitmapFactory.Options(); 196 | localOptions.inJustDecodeBounds = true; 197 | try 198 | { 199 | BitmapFactory.decodeStream(paramContentResolver.openInputStream(paramUri), null, localOptions); 200 | return localOptions; 201 | } 202 | catch (FileNotFoundException localFileNotFoundException) 203 | { 204 | localFileNotFoundException.printStackTrace(); 205 | } 206 | return null; 207 | } 208 | 209 | private static int getExifOrientation(Uri paramUri) 210 | { 211 | try 212 | { 213 | int i = new ExifInterface(paramUri.getPath()).getAttributeInt("Orientation", 1); 214 | return i; 215 | } 216 | catch (Exception localException) 217 | { 218 | localException.printStackTrace(); 219 | } 220 | return 1; 221 | } 222 | 223 | /* public static void loadFile(Context paramContext, String paramString1, String paramString2, ImageView paramImageView) 224 | { 225 | boolean bool = TextUtils.isEmpty(paramString1); 226 | int i = 0; 227 | if (bool); 228 | while (i != 0) 229 | { 230 | paramImageView.setImageResource(i); 231 | return; 232 | i = paramContext.getResources().getIdentifier(paramString1.substring(0, paramString1.indexOf(".")), "drawable", paramContext.getPackageName()); 233 | } 234 | MatchaLoader.displayImage(paramString2, paramImageView); 235 | }*/ 236 | 237 | /*public static void loc2Exif(Location paramLocation, String paramString) 238 | { 239 | if ((paramLocation != null) && (!TextUtils.isEmpty(paramString))); 240 | try 241 | { 242 | ExifInterface localExifInterface = new ExifInterface(paramString); 243 | localExifInterface.setAttribute("GPSLatitude", dec2DMS(paramLocation.getLatitude())); 244 | localExifInterface.setAttribute("GPSLongitude", dec2DMS(paramLocation.getLongitude())); 245 | if (paramLocation.getLatitude() > 0.0D) 246 | { 247 | localExifInterface.setAttribute("GPSLatitudeRef", "N"); 248 | label63: if (paramLocation.getLongitude() <= 0.0D) 249 | break label96; 250 | localExifInterface.setAttribute("GPSLongitudeRef", "E"); 251 | } 252 | while (true) 253 | { 254 | localExifInterface.saveAttributes(); 255 | return; 256 | localExifInterface.setAttribute("GPSLatitudeRef", "S"); 257 | break ; 258 | label96: localExifInterface.setAttribute("GPSLongitudeRef", "W"); 259 | } 260 | return; 261 | } 262 | catch (IOException localIOException) 263 | { 264 | } 265 | }*/ 266 | /* 267 | public static void loc2Exif(String paramString) 268 | { 269 | Location localLocation = new Location("exif"); 270 | localLocation.setLatitude(Constant.GPS.lat); 271 | localLocation.setLongitude(Constant.GPS.lng); 272 | loc2Exif(localLocation, paramString); 273 | }*/ 274 | } -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.util; 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.graphics.Bitmap.CompressFormat; 10 | import android.graphics.BitmapFactory; 11 | import android.os.Environment; 12 | 13 | public class FileUtils { 14 | /** 15 | * sd卡的根目录 16 | */ 17 | private static String mSdRootPath = Environment.getExternalStorageDirectory().getPath(); 18 | /** 19 | * 手机的缓存根目录 20 | */ 21 | private static String mDataRootPath = null; 22 | /** 23 | * 保存Image的目录名 24 | */ 25 | private final static String FOLDER_NAME = "/LoveCity"; 26 | 27 | private final static String IMAGE_NAME = "/cache"; 28 | 29 | public FileUtils(Context context){ 30 | mDataRootPath = context.getCacheDir().getPath(); 31 | } 32 | 33 | public String makeAppDir(){ 34 | String path = getStorageDirectory(); 35 | File folderFile = new File(path); 36 | if(!folderFile.exists()){ 37 | folderFile.mkdir(); 38 | } 39 | path = path + IMAGE_NAME; 40 | folderFile = new File(path); 41 | if(!folderFile.exists()){ 42 | folderFile.mkdir(); 43 | } 44 | return path; 45 | } 46 | 47 | /** 48 | * 获取储存Image的目录 49 | * @return 50 | */ 51 | private String getStorageDirectory(){ 52 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ? 53 | mSdRootPath + FOLDER_NAME : mDataRootPath + FOLDER_NAME; 54 | } 55 | 56 | /** 57 | * 保存Image的方法,有sd卡存储到sd卡,没有就存储到手机目录 58 | * @param fileName 59 | * @param bitmap 60 | * @throws IOException 61 | */ 62 | public void savaBitmap(String fileName, Bitmap bitmap) throws IOException{ 63 | if(bitmap == null){ 64 | return; 65 | } 66 | String path = getStorageDirectory(); 67 | 68 | 69 | Logger.d("FileUtils", "savaBitmap path = " + path); 70 | Logger.d("FileUtils", "savaBitmap fileName = " + fileName); 71 | Logger.d("FileUtils", "savaBitmap mSdRootPath = " + mSdRootPath); 72 | Logger.d("FileUtils", "savaBitmap mDataRootPath = " + mDataRootPath); 73 | File folderFile = new File(path); 74 | if(!folderFile.exists()){ 75 | folderFile.mkdir(); 76 | } 77 | path = path + IMAGE_NAME; 78 | folderFile = new File(path); 79 | if(!folderFile.exists()){ 80 | folderFile.mkdir(); 81 | } 82 | 83 | File file = new File(path + File.separator + fileName); 84 | file.createNewFile(); 85 | FileOutputStream fos = new FileOutputStream(file); 86 | bitmap.compress(CompressFormat.JPEG, 100, fos); 87 | fos.flush(); 88 | fos.close(); 89 | } 90 | 91 | /** 92 | * 从手机或者sd卡获取Bitmap 93 | * @param fileName 94 | * @return 95 | */ 96 | public Bitmap getBitmap(String fileName){ 97 | return BitmapFactory.decodeFile(getStorageDirectory() + File.separator + fileName); 98 | } 99 | 100 | /** 101 | * 判断文件是否存在 102 | * @param fileName 103 | * @return 104 | */ 105 | public boolean isFileExists(String fileName){ 106 | return new File(getStorageDirectory() + File.separator + fileName).exists(); 107 | } 108 | 109 | /** 110 | * 获取文件的大小 111 | * @param fileName 112 | * @return 113 | */ 114 | public long getFileSize(String fileName) { 115 | return new File(getStorageDirectory() + File.separator + fileName).length(); 116 | } 117 | 118 | 119 | /** 120 | * 删除SD卡或者手机的缓存图片和目录 121 | */ 122 | public void deleteFile() { 123 | File dirFile = new File(getStorageDirectory()); 124 | if(! dirFile.exists()){ 125 | return; 126 | } 127 | if (dirFile.isDirectory()) { 128 | String[] children = dirFile.list(); 129 | for (int i = 0; i < children.length; i++) { 130 | new File(dirFile, children[i]).delete(); 131 | } 132 | } 133 | 134 | dirFile.delete(); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/util/Logger.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.util; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * 7 | * @Description: Log 8 | * @author jun 9 | * @date 2014-7-24 下午5:12:47 10 | * 11 | */ 12 | public final class Logger { 13 | 14 | /** 日志级别 显示级别参考 android.util.Log的级别 配置0全部显示,配置大于7全不显示 */ 15 | public static final int LEVLE = 2; 16 | 17 | public static void v(String tag, String msg) { 18 | if (LEVLE <= Log.VERBOSE) 19 | Log.v(tag, msg); 20 | } 21 | 22 | public static void v(String tag, String msg, Throwable tr) { 23 | if (LEVLE <= Log.VERBOSE) 24 | Log.v(tag, msg, tr); 25 | } 26 | 27 | public static void d(String tag, String msg) { 28 | if (LEVLE <= Log.DEBUG) 29 | Log.d(tag, msg); 30 | } 31 | 32 | public static void d(String tag, String msg, Throwable tr) { 33 | if (LEVLE <= Log.DEBUG) 34 | Log.d(tag, msg, tr); 35 | } 36 | 37 | public static void i(String tag, String msg) { 38 | if (LEVLE <= Log.INFO) 39 | Logger.d(tag, msg); 40 | } 41 | 42 | public static void i(String tag, String msg, Throwable tr) { 43 | if (LEVLE <= Log.INFO) 44 | Logger.d(tag, msg, tr); 45 | } 46 | 47 | public static void w(String tag, String msg) { 48 | if (LEVLE <= Log.WARN) 49 | Log.w(tag, msg); 50 | } 51 | 52 | public static void w(String tag, String msg, Throwable tr) { 53 | if (LEVLE <= Log.WARN) 54 | Log.w(tag, msg, tr); 55 | } 56 | 57 | public static void w(String tag, Throwable tr) { 58 | if (LEVLE <= Log.WARN) 59 | Log.w(tag, tr.getMessage(), tr); 60 | } 61 | 62 | public static void e(String tag, String msg) { 63 | if (LEVLE <= Log.ERROR) 64 | Log.e(tag, msg); 65 | } 66 | 67 | public static void e(String tag, String msg, Throwable tr) { 68 | if (LEVLE <= Log.ERROR) 69 | Log.e(tag, msg, tr); 70 | } 71 | 72 | public static void e(String tag, Throwable tr) { 73 | if (LEVLE <= Log.ERROR) 74 | Log.e(tag, tr.getMessage(), tr); 75 | } 76 | 77 | public static void wtf(String tag, String msg) { 78 | if (LEVLE <= Log.ASSERT) 79 | Log.wtf(tag, msg); 80 | } 81 | 82 | public static void wtf(String tag, Throwable tr) { 83 | if (LEVLE <= Log.ASSERT) 84 | Log.wtf(tag, tr); 85 | } 86 | 87 | public static void wtf(String tag, String msg, Throwable tr) { 88 | if (LEVLE <= Log.ASSERT) 89 | Logger.wtf(tag, msg, tr); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/pmmq/pmmqproject/util/NormalUtils.java: -------------------------------------------------------------------------------- 1 | package com.pmmq.pmmqproject.util; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | 8 | import android.graphics.Bitmap; 9 | import android.text.TextPaint; 10 | 11 | public class NormalUtils { 12 | 13 | /** 14 | * 获取字符串显示宽度,与字体有关 15 | * @param text 16 | * @param Size 17 | * @return 18 | */ 19 | public static float GetTextWidth(String text, float Size) { 20 | //第一个参数是要计算的字符串,第二个参数是字提大小 21 | TextPaint FontPaint = new TextPaint(); 22 | FontPaint.setTextSize(Size); 23 | return FontPaint.measureText(text); 24 | } 25 | 26 | /** 27 | * 将Bitmap放入缓存, 28 | * @Title: saveDrawableToCache 29 | * @param bitmap 30 | * @param filePath 31 | * @return void 32 | * @date 2012-12-14 上午9:27:38 33 | */ 34 | public void saveDrawableToCache(Bitmap bitmap, String filePath){ 35 | 36 | try { 37 | File file = new File(filePath); 38 | 39 | file.createNewFile(); 40 | 41 | OutputStream outStream = new FileOutputStream(file); 42 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream); 43 | outStream.flush(); 44 | outStream.close(); 45 | 46 | } catch (IOException e) { 47 | 48 | e.printStackTrace(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/res/anim/black_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/white_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | 25 | 35 | 45 | 55 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/brand_tag_point_black_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/brand_tag_point_black_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/brand_tag_point_white_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/brand_tag_point_white_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/camera_crop_height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/camera_crop_height.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/camera_crop_width.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/camera_crop_width.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_place.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_place.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_brand_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_brand_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_brand_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_brand_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_geolocation_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_geolocation_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_geolocation_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_geolocation_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_user_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_user_active.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/icon_tag_user_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/icon_tag_user_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/indicator_autocrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/indicator_autocrop.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tag_text_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/tag_text_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tag_text_bg_left.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/tag_text_bg_left.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/tag_text_bg_right.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/tag_text_bg_right.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/wm_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-hdpi/wm_6.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/huishu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-xhdpi/huishu.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qiushi123/AndroidtagView/106c158947167ca173933e9f34a9949c9bc1b440/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_tag.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 17 | 23 | 24 | 33 | 41 | 49 | 56 | 57 | 58 | 59 | 60 | 61 | 70 | 75 | 77 | 78 | 84 | 85 | 86 | 90 | 91 |