├── .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 │ │ └── maodq │ │ └── imguploaddemo │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── maodq │ │ │ └── imguploaddemo │ │ │ ├── MainActivity.java │ │ │ ├── QuickOptionDialog.java │ │ │ ├── UploadImgAdapter.java │ │ │ └── utils │ │ │ ├── BitmapHelper.java │ │ │ └── IOUtil.java │ └── res │ │ ├── anim │ │ ├── dialog_enter.xml │ │ └── dialog_exit.xml │ │ ├── drawable │ │ ├── dialog_background.9.png │ │ └── selector_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── dialog_quick_option.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── maodq │ └── imguploaddemo │ └── ExampleUnitTest.java ├── build.gradle ├── demo.gif ├── 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 | ImgUploadDemo -------------------------------------------------------------------------------- /.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 | 22 | 23 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | # 头像上传功能封装 2 | 3 | ![image](https://github.com/noiary/upload-image/blob/master/demo.gif) 4 | ## 两种模式: 5 | 1. 选取头像,默认剪切尺寸为260px,可以选取剪切区域 6 | 2. 上传图片,不需要剪切,原图比例直接上传,上传之前会进行bitmap压缩,大概会控制在200KB左右 7 | 8 | ## 注意事项 9 | 1. 权限问题,如果是6.0以上系统,可能需要手动授权存储空间 10 | 2. 在调取uploadAdapter的页面,监听onActivityResult方法,并执行uploadAdapter.onResult(resultCode,resultCode,intent) 11 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.maodq.imguploaddemo" 9 | minSdkVersion 23 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.4.0' 26 | } 27 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/maodq/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/maodq/imguploaddemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo; 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 | 4 | 5 | 6 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/maodq/imguploaddemo/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo; 2 | 3 | import android.content.Intent; 4 | import android.graphics.BitmapFactory; 5 | import android.os.Bundle; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.View; 8 | import android.widget.Button; 9 | import android.widget.ImageView; 10 | 11 | import java.io.File; 12 | 13 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 14 | 15 | private Button btnUploadHead, btnUploadImg; 16 | private ImageView ivHead, ivImg; 17 | private UploadImgAdapter uploadImgAdapter; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | btnUploadHead = (Button) findViewById(R.id.btn_upload_head); 25 | btnUploadImg = (Button) findViewById(R.id.btn_upload_img); 26 | ivHead = (ImageView) findViewById(R.id.iv_head); 27 | ivImg = (ImageView) findViewById(R.id.iv_img); 28 | btnUploadHead.setOnClickListener(this); 29 | btnUploadImg.setOnClickListener(this); 30 | 31 | } 32 | 33 | @Override 34 | public void onClick(View v) { 35 | if (uploadImgAdapter == null) 36 | initUploadImgAdapter(); 37 | switch (v.getId()) { 38 | case R.id.btn_upload_head: 39 | uploadImgAdapter.withMode(UploadImgAdapter.MODE_HEAD).showDialog(); 40 | break; 41 | case R.id.btn_upload_img: 42 | uploadImgAdapter.withMode(UploadImgAdapter.MODE_IMG).showDialog(); 43 | break; 44 | } 45 | } 46 | 47 | private void initUploadImgAdapter() { 48 | uploadImgAdapter = new UploadImgAdapter(MainActivity.this, new UploadImgAdapter.Action2() { 49 | @Override 50 | public void call(File file, int mode) { 51 | if (mode == UploadImgAdapter.MODE_HEAD) 52 | ivHead.setImageBitmap(BitmapFactory.decodeFile(file.getAbsolutePath())); 53 | else if (mode == UploadImgAdapter.MODE_IMG) 54 | ivImg.setImageBitmap(BitmapFactory.decodeFile(file.getAbsolutePath())); 55 | } 56 | }); 57 | } 58 | 59 | @Override 60 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 61 | super.onActivityResult(requestCode, resultCode, data); 62 | if (uploadImgAdapter != null) 63 | uploadImgAdapter.onActivityResult(requestCode, resultCode, data); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/maodq/imguploaddemo/QuickOptionDialog.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Dialog; 5 | import android.content.Context; 6 | import android.os.Bundle; 7 | import android.view.Display; 8 | import android.view.Gravity; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.widget.ImageView; 14 | 15 | 16 | /** 17 | * 拍照或选择本机相册选项弹窗dialog 18 | * Created by maodeqiang on 2015/9/29. 19 | */ 20 | public class QuickOptionDialog extends Dialog implements View.OnClickListener { 21 | 22 | private ImageView mClose; 23 | private OnQuickOptionFormClick mListener; 24 | 25 | 26 | public QuickOptionDialog(Context context) { 27 | this(context, R.style.quick_option_dialog); 28 | } 29 | 30 | public QuickOptionDialog(Context context, boolean flag, OnCancelListener listener) { 31 | super(context, flag, listener); 32 | } 33 | 34 | @SuppressLint("InflateParams") 35 | private QuickOptionDialog(Context context, int defStyle) { 36 | super(context, defStyle); 37 | View dialog_quick_option = getLayoutInflater().inflate(R.layout.dialog_quick_option, null); 38 | 39 | dialog_quick_option.findViewById(R.id.tv_photograph).setOnClickListener(this); 40 | dialog_quick_option.findViewById(R.id.tv_select).setOnClickListener(this); 41 | dialog_quick_option.findViewById(R.id.tv_cancel).setOnClickListener(this); 42 | 43 | requestWindowFeature(Window.FEATURE_NO_TITLE); 44 | dialog_quick_option.setOnTouchListener(new View.OnTouchListener() { 45 | @Override 46 | public boolean onTouch(View v, MotionEvent event) { 47 | QuickOptionDialog.this.dismiss(); 48 | return true; 49 | } 50 | }); 51 | super.setContentView(dialog_quick_option); 52 | } 53 | 54 | 55 | @Override 56 | protected void onCreate(Bundle savedInstanceState) { 57 | super.onCreate(savedInstanceState); 58 | getWindow().setGravity(Gravity.BOTTOM); 59 | 60 | WindowManager wm = getWindow().getWindowManager(); 61 | Display defaultDisplay = wm.getDefaultDisplay(); 62 | WindowManager.LayoutParams attributes = getWindow().getAttributes(); 63 | attributes.width = defaultDisplay.getWidth(); 64 | attributes.alpha = 0.95f; 65 | getWindow().setAttributes(attributes); 66 | } 67 | 68 | public void setOnQuickOptionformClickListener(OnQuickOptionFormClick lis) { 69 | mListener = lis; 70 | } 71 | 72 | @Override 73 | public void onClick(View v) { 74 | if (mListener != null) { 75 | mListener.onQuickOptionClick(v); 76 | } 77 | dismiss(); 78 | } 79 | 80 | public interface OnQuickOptionFormClick { 81 | void onQuickOptionClick(View v); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/maodq/imguploaddemo/UploadImgAdapter.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | import android.content.ContentResolver; 6 | import android.content.Intent; 7 | import android.graphics.Bitmap; 8 | import android.net.Uri; 9 | import android.os.Environment; 10 | import android.provider.MediaStore; 11 | import android.text.TextUtils; 12 | import android.view.View; 13 | import android.widget.Toast; 14 | 15 | import com.maodq.imguploaddemo.utils.BitmapHelper; 16 | 17 | import java.io.File; 18 | import java.io.IOException; 19 | 20 | 21 | /** 22 | * 上传头像功能封装 23 | * 必须在使用此adapter页面监听欧尼ActivityResult方法,执行adapter.onActivityResult(requestCode, resultCode, data) 24 | * Created by maodq on 16/4/29. 25 | */ 26 | public class UploadImgAdapter { 27 | // 可自定义文件目录名 28 | private static final String ROOT_NAME = "UPLOAD_CACHE"; 29 | private final String TAG = "UploadImgAdapter"; 30 | 31 | private Activity mActivity; 32 | private File mTempCameraFile; 33 | private File mTempCropFile; 34 | public static final int MODE_HEAD = 0; 35 | public static final int MODE_IMG = 1; 36 | 37 | 38 | private static final int ALBUM_REQUEST_CODE = 1; 39 | private static final int CAMERA_REQUEST_CODE = 2; 40 | private static final int CROP_REQUEST_CODE = 4; 41 | Action2 mOnImageUpdateListener; 42 | private ProgressDialog mProgressDialog; 43 | private int mMode = -1; 44 | private QuickOptionDialog mDialog; 45 | 46 | public UploadImgAdapter(Activity activity, Action2 l) { 47 | mActivity = activity; 48 | mOnImageUpdateListener = l; 49 | mDialog = new QuickOptionDialog(mActivity); 50 | mDialog.setCancelable(true); 51 | mDialog.setCanceledOnTouchOutside(true); 52 | mDialog.setOnQuickOptionformClickListener(new QuickOptionDialog.OnQuickOptionFormClick() { 53 | @Override 54 | public void onQuickOptionClick(View v) { 55 | clickQuickOption(v); 56 | } 57 | }); 58 | } 59 | 60 | public UploadImgAdapter showDialog() { 61 | if (mMode == -1) 62 | throw new IllegalStateException("请通过withMode(mode)方法设置执行图片模式"); 63 | mDialog.show(); 64 | return this; 65 | } 66 | 67 | public UploadImgAdapter withMode(int mode) { 68 | mMode = mode; 69 | return this; 70 | } 71 | 72 | // 头像dialog点击监听器 73 | private void clickQuickOption(View v) { 74 | switch (v.getId()) { 75 | case R.id.tv_photograph: 76 | Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 77 | cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempCameraFile())); 78 | mActivity.startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE); 79 | break; 80 | case R.id.tv_select: 81 | // Intent albumIntent = new Intent(Intent.ACTION_PICK); // 老版本的相册 82 | // albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED); 83 | Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT).setType("image/*"); 84 | mActivity.startActivityForResult(albumIntent, ALBUM_REQUEST_CODE); 85 | break; 86 | case R.id.tv_cancel: 87 | // 默认不做处理也会自动关闭dialog 88 | default: 89 | break; 90 | } 91 | } 92 | 93 | 94 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 95 | if (resultCode == Activity.RESULT_OK) { 96 | switch (requestCode) { 97 | case CAMERA_REQUEST_CODE: // 照相机返回结果 98 | if (mMode == MODE_IMG) { 99 | File file = composBitmap(mTempCameraFile); 100 | sendImage(file); 101 | } else if (mMode == MODE_HEAD) { 102 | // 头像宽高为65dp,对应xxxhdpi为260px 103 | startCrop(Uri.fromFile(mTempCameraFile), 260, 260); 104 | } 105 | break; 106 | case ALBUM_REQUEST_CODE: // 相册返回结果 107 | Uri uri = data.getData(); 108 | if (mMode == MODE_IMG) { 109 | File file = BitmapHelper.decodeUriAsFile(mActivity, uri); 110 | file = composBitmap(file); 111 | sendImage(file); 112 | } else if (mMode == MODE_HEAD) { 113 | startCrop(uri, 260, 260); 114 | } 115 | break; 116 | case CROP_REQUEST_CODE: // 裁剪返回结果 117 | sendImage(getTempCropFile()); 118 | break; 119 | } 120 | } 121 | } 122 | 123 | /** 124 | * 开始裁剪 125 | * 附加选项 数据类型 描述 126 | * crop String 发送裁剪信号 127 | * aspectX int X方向上的比例 128 | * aspectY int Y方向上的比例 129 | * outputX int 裁剪区的宽 130 | * outputY int 裁剪区的高 131 | * scale boolean 是否保留比例 132 | * return-data boolean 是否将数据保留在Bitmap中返回 133 | * data Parcelable 相应的Bitmap数据 134 | * circleCrop String 圆形裁剪区域? 135 | * MediaStore.EXTRA_OUTPUT ("output") URI 将URI指向相应的file:///... 136 | * 137 | * @param uri uri 138 | */ 139 | private void startCrop(Uri uri, int outputX, int outputY) { 140 | Bitmap bitmap = null; 141 | String str = ""; 142 | 143 | try { 144 | bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri); 145 | str = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "", ""); 146 | } catch (IOException e) { 147 | e.printStackTrace(); 148 | } 149 | if (bitmap == null || TextUtils.isEmpty(str)) { 150 | Toast.makeText(mActivity, "找不到此图片", Toast.LENGTH_SHORT).show(); 151 | return; 152 | } 153 | uri = Uri.parse(str); 154 | 155 | Intent intent = new Intent("com.android.camera.action.CROP"); //调用Android系统自带的一个图片剪裁页面 156 | intent.setDataAndType(uri, "image/*"); 157 | intent.putExtra("crop", "true");//进行修剪 158 | // aspectX aspectY 是宽高的比例 159 | if (outputX == outputY) { 160 | intent.putExtra("aspectX", 1); 161 | intent.putExtra("aspectY", 1); 162 | } else { 163 | intent.putExtra("scale", true); 164 | } 165 | // outputX outputY 是裁剪图片宽高 166 | intent.putExtra("outputX", outputX); 167 | intent.putExtra("outputY", outputY); 168 | intent.putExtra("return-data", false); 169 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(getTempCropFile())); 170 | mActivity.startActivityForResult(intent, CROP_REQUEST_CODE); 171 | } 172 | 173 | private ContentResolver getContentResolver() { 174 | return mActivity.getContentResolver(); 175 | } 176 | 177 | private File getTempCropFile() { 178 | if (mTempCropFile == null) { 179 | mTempCropFile = getTempMediaFile(); 180 | } 181 | return mTempCropFile; 182 | } 183 | 184 | private File getTempCameraFile() { 185 | if (mTempCameraFile == null) 186 | mTempCameraFile = getTempMediaFile(); 187 | return mTempCameraFile; 188 | } 189 | 190 | private File composBitmap(File file) { 191 | Bitmap bitmap = BitmapHelper.revisionImageSize(file); 192 | return BitmapHelper.saveBitmap2file(mActivity, bitmap); 193 | } 194 | 195 | private void sendImage(final File file) { 196 | if (file == null) { 197 | Toast.makeText(mActivity, "找不到此图片", Toast.LENGTH_SHORT).show(); 198 | return; 199 | } 200 | // 可以在这里统一进行联网上传操作,把上传结果传回,也可以直接传file交给原页面处理 201 | mOnImageUpdateListener.call(file, mMode); 202 | } 203 | 204 | /** 205 | * 原项目用的RxJava的Action2 206 | */ 207 | public interface Action2 { 208 | void call(File file, int mode); 209 | } 210 | 211 | /** 212 | * 获取相机的file 213 | */ 214 | public File getTempMediaFile() { 215 | File file = null; 216 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 217 | String fileName = getTempMediaFileName(); 218 | file = new File(fileName); 219 | } 220 | return file; 221 | } 222 | 223 | public String getTempMediaFileName() { 224 | return getParentPath() + "image" + System.currentTimeMillis() + ".jpg"; 225 | } 226 | 227 | private String getParentPath() { 228 | String parent = Environment.getExternalStorageDirectory() 229 | + File.separator + ROOT_NAME + File.separator; 230 | mkdirs(parent); 231 | return parent; 232 | } 233 | 234 | public boolean mkdirs(String path) { 235 | File file = new File(path); 236 | return !file.exists() && file.mkdirs(); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /app/src/main/java/com/maodq/imguploaddemo/utils/BitmapHelper.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo.utils; 2 | 3 | import android.app.Activity; 4 | import android.graphics.Bitmap; 5 | import android.graphics.BitmapFactory; 6 | import android.net.Uri; 7 | import android.util.Log; 8 | 9 | import java.io.BufferedInputStream; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.FileInputStream; 13 | import java.io.FileNotFoundException; 14 | import java.io.FileOutputStream; 15 | import java.io.IOException; 16 | import java.io.OutputStream; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | 21 | /** 22 | * BitmapHelper 23 | * Created by maodeqiang on 2015/11/4. 24 | */ 25 | public class BitmapHelper { 26 | private static final String TAG = "BitmapHelper"; 27 | public static int max = 0; 28 | public static boolean act_bool = true; 29 | public static List bmp = new ArrayList<>(); 30 | 31 | 32 | public static List images = new ArrayList<>(); 33 | 34 | // public static Bitmap revisionImageSize(File file) { 35 | // BufferedInputStream in = null; 36 | // try { 37 | // in = new BufferedInputStream(new FileInputStream(file)); 38 | // } catch (FileNotFoundException e) { 39 | // e.printStackTrace(); 40 | // } 41 | // return revisionImageSize(in); 42 | // } 43 | 44 | 45 | //图片sd地址 上传服务器时把图片调用下面方法压缩后 保存到临时文件夹 图片压缩后小于100KB,失真度不明显 46 | public static Bitmap revisionImageSize(File file) { 47 | if (file == null) 48 | return null; 49 | long start = System.currentTimeMillis(); 50 | BufferedInputStream in = null; 51 | Bitmap bitmap = null; 52 | try { 53 | in = new BufferedInputStream(new FileInputStream(file)); 54 | BitmapFactory.Options options = new BitmapFactory.Options(); 55 | options.inJustDecodeBounds = true; 56 | BitmapFactory.decodeStream(in, null, options); 57 | IOUtil.close(in); 58 | int i = 0; 59 | while (true) { 60 | if ((options.outWidth >> i <= 2000) && (options.outHeight >> i <= 2000)) { 61 | in = new BufferedInputStream(new FileInputStream(file)); 62 | options.inSampleSize = (int) Math.pow(2.0D, i); 63 | options.inJustDecodeBounds = false; 64 | bitmap = BitmapFactory.decodeStream(in, null, options); 65 | break; 66 | } 67 | i += 1; 68 | } 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | } finally { 72 | IOUtil.close(in); 73 | } 74 | long time = System.currentTimeMillis() - start; 75 | Log.d(TAG, "revisionImageSize: 耗时" + time + "毫秒"); 76 | return bitmap; 77 | } 78 | 79 | // 图片转为文件 80 | public static boolean saveBitmap2file(Bitmap bmp, String filename) { 81 | Bitmap.CompressFormat format = Bitmap.CompressFormat.JPEG; 82 | int quality = 100; 83 | OutputStream stream = null; 84 | try { 85 | stream = new FileOutputStream(filename); 86 | } catch (FileNotFoundException e) { 87 | e.printStackTrace(); 88 | } 89 | 90 | return bmp.compress(format, quality, stream); 91 | } 92 | 93 | // bitmap转换file 94 | public static File saveBitmap2file(Activity activity, Bitmap bmp) { 95 | if (bmp == null) 96 | return null; 97 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); 98 | bmp.compress(Bitmap.CompressFormat.JPEG, 75, stream);// (0-100)压缩文件 99 | File file = new File(activity.getCacheDir(), "uploadFile"); 100 | IOUtil.writeTo(stream, file); 101 | IOUtil.close(stream); 102 | return file; 103 | } 104 | 105 | // uri转换bitmap 106 | public static Bitmap decodeUriAsBitmap(Activity activity, Uri uri) { 107 | Bitmap bitmap = null; 108 | try { 109 | bitmap = BitmapFactory.decodeStream(activity. 110 | getContentResolver().openInputStream(uri)); 111 | } catch (FileNotFoundException e) { 112 | e.printStackTrace(); 113 | return null; 114 | } 115 | return bitmap; 116 | } 117 | 118 | public static int getImageSize() { 119 | return images.size(); 120 | } 121 | 122 | // uri转换file 123 | public static File decodeUriAsFile(Activity activity, Uri uri) { 124 | Bitmap bitmap = decodeUriAsBitmap(activity, uri); 125 | return saveBitmap2file(activity, bitmap); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/maodq/imguploaddemo/utils/IOUtil.java: -------------------------------------------------------------------------------- 1 | package com.maodq.imguploaddemo.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.Closeable; 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | 10 | /** 11 | * IOUtil 12 | * Created by maodeqiang on 2015/7/13. 13 | */ 14 | public class IOUtil { 15 | static final String TAG = "IOUtil"; 16 | 17 | /** 18 | * InputStream to byte[] 19 | */ 20 | public static byte[] readStream(InputStream inStream) { 21 | byte[] returnByte = null; 22 | byte[] buffer = new byte[1024]; 23 | ByteArrayOutputStream outSteam = null; 24 | try { 25 | outSteam = new ByteArrayOutputStream(); 26 | int len = -1; 27 | while ((len = inStream.read(buffer)) != -1) { 28 | outSteam.write(buffer, 0, len); 29 | } 30 | returnByte = outSteam.toByteArray(); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } finally { 34 | close(outSteam); 35 | close(inStream); 36 | } 37 | return returnByte; 38 | } 39 | 40 | public static void close(Closeable... ios) { 41 | for (Closeable io : ios) { 42 | try { 43 | if (io != null) 44 | io.close(); 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | } 50 | 51 | 52 | public static void writeTo(ByteArrayOutputStream baos, File file) { 53 | try { 54 | baos.writeTo(new FileOutputStream(file, false)); 55 | } catch (IOException e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | 60 | public static void createNewFile(File file) { 61 | try { 62 | boolean newFile = file.createNewFile(); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_enter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/anim/dialog_exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dialog_background.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noiary/upload-image/3f458a6e7c725c65447f0082c715796d8356fc9c/app/src/main/res/drawable/dialog_background.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/selector_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 20 | 21 |