图片选取、拍摄、裁剪、上传

图片上传

效果图展示

Drawing Drawing

图片上传前的准备

带圆角的方形图片

使用的第三方控件,主要关注如下一些文件

  • RoundedDrawable
  • RoundedImageView
  • RoundedTransformationBuilder
  • res目录下的anim、color以及values下的attrs

布局文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res/com.soulrelay.uploadpic"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="@color/f5f5f5">
<com.soulrelay.uploadpic.view.RoundedImageView
android:id="@+id/imageCover"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginLeft="50dp"
android:layout_centerVertical="true"
android:scaleType="center"
android:src="@drawable/default_cover_img"
app:border_color="@color/border"
app:border_width="1dip"
app:corner_radius="10dp"
app:mutate_background="true"
app:oval="false" />
<TextView
android:id="@+id/add_cover_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/imageCover"
android:text="添加封面"
android:textColor="@color/_3e363d"
android:textSize="15sp" />
</RelativeLayout>

从下而上弹出的PopupWindow

关注如下文件:

  • CoverSelelctPopupWindow
  • cover_select_pop_layout.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class CoverSelelctPopupWindow extends PopupWindow {
private Button albumBtn, photoGraphBtn,cancelBtn;
private View mMenuView;
public CoverSelelctPopupWindow(Activity context, OnClickListener itemsOnClick) {
super(context);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mMenuView = inflater.inflate(R.layout.cover_select_pop_layout, null);
albumBtn = (Button) mMenuView.findViewById(R.id.btn_album);
photoGraphBtn = (Button) mMenuView.findViewById(R.id.btn_photo_graph);
//startRecordBtn = (Button) mMenuView.findViewById(R.id.btn_upload_record);
cancelBtn = (Button) mMenuView.findViewById(R.id.btn_cancel_join);
// 设置按钮监听
albumBtn.setOnClickListener(itemsOnClick);
photoGraphBtn.setOnClickListener(itemsOnClick);
// 设置SelectPicPopupWindow的View
this.setContentView(mMenuView);
// 设置SelectPicPopupWindow弹出窗体的宽
this.setWidth(LayoutParams.FILL_PARENT);
// 设置SelectPicPopupWindow弹出窗体的高
this.setHeight(LayoutParams.WRAP_CONTENT);
// 设置SelectPicPopupWindow弹出窗体可点击
this.setFocusable(true);
// 设置SelectPicPopupWindow弹出窗体动画效果
this.setAnimationStyle(R.style.AnimBottom);
// 实例化一个ColorDrawable颜色为半透明
ColorDrawable dw = new ColorDrawable(0x00FFFFFF);
// 设置SelectPicPopupWindow弹出窗体的背景
this.setBackgroundDrawable(dw);
// mMenuView添加OnTouchListener监听判断获取触屏位置如果在选择框外面则销毁弹出框
mMenuView.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
int height = mMenuView.findViewById(R.id.pop_layout).getTop();
int y = (int) event.getY();
if (event.getAction() == MotionEvent.ACTION_UP) {
if (y < height) {
dismiss();
}
}
return true;
}
});
cancelBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
dismiss();
}
});
}
}

布局文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/pop_layout"
android:layout_width="fill_parent"
android:layout_height="175dp"
android:background="@color/f33e363d"
android:gravity="center_horizontal"
android:orientation="vertical" >
<Button
android:id="@+id/btn_album"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="16dip"
android:textSize="14sp"
android:background="@drawable/btn_report_selector"
android:text="@string/user_info_photo_album"
android:textColor="@color/_3e363d" />
<Button
android:id="@+id/btn_photo_graph"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:layout_marginTop="8dip"
android:textSize="14sp"
android:background="@drawable/btn_report_selector"
android:text="@string/user_info_photo_camera"
android:textColor="@color/_3e363d" />
<Button
android:id="@+id/btn_cancel_join"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dip"
android:layout_marginLeft="20dip"
android:layout_marginRight="20dip"
android:textSize="14sp"
android:background="@drawable/btn_report_selector"
android:text="@string/join_cancel_txt"
android:textColor="@color/_6f6a6f" />
</LinearLayout>
</RelativeLayout>

通过拍照以及相册获取图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
public class MainActivity extends Activity implements android.view.View.OnClickListener {
private RoundedImageView imgCover;
private TextView addCover;
private CoverSelelctPopupWindow coverSelelctPopupWindow;
public static final int ACTIVITY_ALBUM_REQUESTCODE = 2000;
public static final int ACTIVITY_CAMERA_REQUESTCODE = 2001;
public static final int ACTIVITY_MODIFY_PHOTO_REQUESTCODE = 2002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
imgCover = (RoundedImageView) this.findViewById(R.id.imageCover);
addCover = (TextView) this.findViewById(R.id.add_cover_txt);
imgCover.setOnClickListener(this);
addCover.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.imageCover:
case R.id.add_cover_txt:
coverSelelctPopupWindow = new CoverSelelctPopupWindow(this, itemsOnClick);
coverSelelctPopupWindow.showAtLocation(findViewById(R.id.add_cover_txt), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0); //设置layout在PopupWindow中显示的位置
break;
default:
break;
}
}
// 为弹出窗口实现监听类
private OnClickListener itemsOnClick = new OnClickListener() {
public void onClick(View v) {
coverSelelctPopupWindow.dismiss();
if (CommonUtils.isFastDoubleClick()) {
return;
}
switch (v.getId()) {
case R.id.btn_album:
Intent i = new Intent(Intent.ACTION_PICK, null);// 调用android的图库
i.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(i, ACTIVITY_ALBUM_REQUESTCODE);
break;
case R.id.btn_photo_graph:
if (CommonUtils.isExistCamera(MainActivity.this)) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 调用android自带的照相机
Uri imageUri = Uri.fromFile(FileUtil.getHeadPhotoFileRaw());
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
intent.putExtra(MediaStore.Images.Media.ORIENTATION, 0);
startActivityForResult(intent, ACTIVITY_CAMERA_REQUESTCODE);
} else {
Toast.makeText(MainActivity.this,
getResources().getString(R.string.user_no_camera),
Toast.LENGTH_SHORT).show();
}
break;
}
}
};
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case ACTIVITY_ALBUM_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
if(data.getData() == null){
ToastUtils.toast(this, getString(R.string.pic_not_valid));
return;
}
CommonUtils.cutPhoto(this, data.getData(), true);
}
break;
case ACTIVITY_CAMERA_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = 2;
int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
FileUtil.saveCutBitmapForCache(this,cameraBitmap);
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
}
break;
case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
// Bundle bundle = data.getExtras();
// if (bundle != null) {
// Bitmap bitmap = bundle.getParcelable("data");
// if (bitmap == null) {
// return;
// }
// headImg.setImageBitmap(bitmap);
// }
String coverPath = FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP;
Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
imgCover.setImageBitmap(bitmap);
//接下来是完成上传功能
/* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid="
+ LoginUtils.getInstance(this), coverPath, this);*/
//成功之后删除临时图片
FileUtil.deleteTempAndRaw();
break;
}
}
}

拍照获取图片失败的问题

过程中发现,如果拍照获取图片的存储路径与裁切后存储的路径一致的话会出现问题,所以分别设置了两个路径,请参考

  • FileUtil
    相关代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    public class FileUtil {
    private static final String TAG = "FileUtil";
    // 用户头像保存位置
    private final static String HEADPHOTO_PATH = "/Android/data/com.soulrelay.uploadpic/";
    // 剪切头像时临时保存头像名字,完成或取消时删除
    public final static String HEADPHOTO_NAME_TEMP = "user_photo_temp.jpg";
    //拍照临时存取图片
    public final static String HEADPHOTO_NAME_RAW = "user_photo_raw.jpg";
    // 剪切壁纸图片
    private final static String WALLPAPER = "wallpaper.jpg";
    public static String getCropPath(String path) {
    String storageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_REMOVED.equals(storageState)) {
    return null;
    }
    String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH + "cache" + File.separator;
    String s = MD5.Md5Encode(path)+".jpg";
    return dirPath + s;
    }
    /**
    * 用户头像保存路径
    */
    public static String getHeadPhotoDir() {
    String storageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_REMOVED.equals(storageState)) {
    return null;
    }
    String path = Environment.getExternalStorageDirectory().getAbsolutePath() + HEADPHOTO_PATH;
    SDCardUtil.mkdirs(path);
    return path;
    }
    /**
    * 剪切头像时临时保存头像名字,完成或取消时删除
    */
    public static File getHeadPhotoFileTemp() {
    File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_TEMP);
    return file;
    }
    /**
    * 剪切头像时临时保存头像名字,完成或取消时删除(用于拍照时存储原始图片)
    */
    public static File getHeadPhotoFileRaw() {
    File file = new File(getHeadPhotoDir() + HEADPHOTO_NAME_RAW);
    return file;
    }
    /**
    * 获取剪切壁纸图片
    */
    public static File getWallPaperFile() {
    File file = new File(getHeadPhotoDir() + WALLPAPER);
    return file;
    }
    public static void saveCutBitmapForCache(Context context, Bitmap bitmap) {
    File file = new File(getHeadPhotoDir() + /*File.separator +*/ HEADPHOTO_NAME_RAW);
    try {
    FileOutputStream out = new FileOutputStream(file);
    bitmap.compress(Bitmap.CompressFormat.JPEG, 85, out);
    out.flush();
    out.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    /**
    * 读取图片属性:旋转的角度
    * @param path 图片绝对路径
    * @return degree旋转的角度
    */
    public static int readPictureDegree(String path) {
    int degree = 0;
    try {
    ExifInterface exifInterface = new ExifInterface(path);
    int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
    switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
    degree = 90;
    break;
    case ExifInterface.ORIENTATION_ROTATE_180:
    degree = 180;
    break;
    case ExifInterface.ORIENTATION_ROTATE_270:
    degree = 270;
    break;
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    return degree;
    }
    /**
    * 旋转图片
    * @param angle
    * @param bitmap
    * @return Bitmap
    */
    public static Bitmap rotaingImageView(int angle , Bitmap bitmap) {
    //旋转图片 动作
    Matrix matrix = new Matrix();;
    matrix.postRotate(angle);
    System.out.println("angle2=" + angle);
    // 创建新的图片
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
    bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    return resizedBitmap;
    }
    /**
    * Delete the file/dir from the local disk
    *
    */
    public static boolean deleteFile(String filePath) {
    if (TextUtils.isEmpty(filePath)) {
    return false;
    }
    File file = new File(filePath);
    if (!file.exists()) {
    Log.w(TAG, "the file is not exist while delete the file");
    return false;
    }
    return deleteDir(file);
    }
    /**
    * Delete the file from the local disk
    *
    * @param dir
    */
    private static boolean deleteDir(File dir) {
    if (dir.isDirectory()) {
    String[] children = dir.list();
    if (children != null) {
    // 递归删除目录中的子目录下
    for (int i = 0; i < children.length; i++) {
    boolean success = deleteDir(new File(dir, children[i]));
    if (!success) {
    return false;
    }
    }
    }
    }
    if (!dir.canRead() || !dir.canWrite()) {
    Log.w(TAG, "has no permission to can or write while delete the file");
    return false;
    }
    // 目录此时为空,可以删除
    return dir.delete();
    }
    /**
    * 删除临时文件(拍照的原始图片以及临时文件)
    * @param path
    */
    public static void deleteTempAndRaw() {
    deleteFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP);
    deleteFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
    }
    }

拍照获取图片角度不正确的问题

1
2
3
4
5
6
7
8
9
10
11
case ACTIVITY_CAMERA_REQUESTCODE:
if (resultCode == Activity.RESULT_OK) {
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = 2;
int degree = FileUtil.readPictureDegree(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW);
Bitmap cameraBitmap = BitmapFactory.decodeFile(FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_RAW, bitmapOptions);
cameraBitmap = FileUtil.rotaingImageView(degree, cameraBitmap);
FileUtil.saveCutBitmapForCache(this,cameraBitmap);
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);
}
break;

如果不存在图片角度的问题可以直接调用(我测试的时候发现:型号相同,系统版本相同的手机上也有可能存在角度不统一的问题,如果有更好的处理方法,欢迎指教!)

1
CommonUtils.cutPhoto(this, Uri.fromFile(FileUtil.getHeadPhotoFileRaw()), true);

上传成功之后删除临时文件

可以根据服务器接口形式,来进行图片上传,我这边上传的格式是
传入两个参数

  • uid 用户id
  • image 图片二进制数据
    1
    2
    3
    4
    5
    6
    7
    8
    9
    case ACTIVITY_MODIFY_PHOTO_REQUESTCODE:
    String coverPath = FileUtil.getHeadPhotoDir() + FileUtil.HEADPHOTO_NAME_TEMP;
    Bitmap bitmap = BitmapFactory.decodeFile(coverPath);
    imgCover.setImageBitmap(bitmap);
    //接下来是完成上传功能
    /* HttpUtil.uploadCover(this, UrlContainer.UP_LIVE_COVER + "?uid="
    + LoginUtils.getInstance(this), coverPath, this);*/
    //成功之后删除临时图片
    FileUtil.deleteTempAndRaw();

图片上传以及上传之后的处理

大家可以在自己的网络请求中按照如下方式处理,然后根据上传成功和失败的回调做相应的事情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
ublic static void uploadCover(final Context context, final String url, final String path,
final UploadLiveCoverListener listener) {
ThreadPoolUtils.execute(new Runnable() {
@Override
public void run() {
// 添加密钥
try {
HttpClient client = new DefaultHttpClient();
MultipartEntity multipartContent = getEntity(context,
new HashMap<String, String>());
FileBody fileBody = new FileBody(new File(path), "image/jpeg", "UTF-8");
multipartContent.addPart("image", fileBody);
String ret = doPost(context, url, multipartContent, client);
JSONObject json = new JSONObject(ret);
int status = json.getInt("status");
if (status == 0) {
JSONObject resultO = json.getJSONObject("result");
String imgUrl = resultO.getString("img_url");
listener.onUploadSuccess(imgUrl);
}else {
listener.onUploadFail(status);
}
deleteTempAndRaw(path);
} catch (Exception e) {
listener.onUploadFail(-1);
}
}
});
}

代码下载

源代码地址:选我选我选我

SuS wechat
欢迎您扫一扫上面的微信公众号,订阅我的最新信息!
坚持原创技术分享,您的支持将鼓励我继续创作!