相册服务器位置,带你实现拍照||从相册选择->裁剪->上传服务器

涉及到的知识点:

1,调用系统拍照功能,拿到图片进行裁剪,上传服务器

2,调用手机相册,拿到图片进行裁剪,上传服务器

3,拍照权限,读取写入存储卡权限的请求和处理。

4,上传服务器使用的我以前封装的retrofit2和rxjava的类

1,实现拍照功能

首先我在主界面放了俩个按钮一个点击拍照,一个点击从相册获取,底部放置一个ImageView用来显示截取后的图片,至于为什么一定要截取,后面我会讲到

xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/activity_main"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:paddingBottom="@dimen/activity_vertical_margin"

android:paddingLeft="@dimen/activity_horizontal_margin"

android:paddingRight="@dimen/activity_horizontal_margin"

android:paddingTop="@dimen/activity_vertical_margin"

tools:context="cn.swt.m.photodemo.MainActivity">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="takePhoto"

android:text="拍照"/>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:onClick="getPhotoFromPhone"

android:text="从相册获取"/>

android:id="@+id/photo_img"

android:layout_width="200dp"

android:layout_height="200dp"/>

当拍照按钮被点击的时候,请求拍照权限

public void takePhoto(View view) {

MPermissions.requestPermissions(MainActivity.this, 4, android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE);

}

权限申请我用的弘洋大神的库具体可以看

Android 6.0 运行时权限处理完全解析

请求权限成功后,打开照相机

@PermissionGrant(4)

public void requestCameraSuccess() {

String sdStatus = Environment.getExternalStorageState();

if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用

Toast.makeText(this, "sd卡不可用", Toast.LENGTH_SHORT).show();

return;

}

if (targetUri == null) {

File dirfile = new File(photopath);

if (!dirfile.exists()) {

dirfile.mkdirs();

}

tempFile = new File(photopath, getPhotoFileName());

targetUri = Uri.fromFile(tempFile);

}

Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

intent2.putExtra(MediaStore.EXTRA_OUTPUT, targetUri);

startActivityForResult(intent2, PHOTO_REQUEST_TAKEPHOTO);// 采用ForResult打开

}

解释一下上面的代码

因为需要把拍照得到的照片保存到sd卡中,所以先判断sd卡是不是可用

接下来指定一个路径,根据路径判断文件夹是否存在,如果不存在就创建一个

代码中定义了一些常量

private static final int PHOTO_REQUEST_TAKEPHOTO = 1;//拍照

private static final int PHOTO_REQUEST_GALLERY = 2;//相册

private static final int PHOTO_REQUEST_CUT = 3;// 结果

private Uri targetUri;//拍照时 指定的存储路径

File tempFile; //拍照存储的文件

File cropFilePath;//裁剪后的文件

接下来指定拍照之后文件的路径和文字

tempFile = new File(photopath, getPhotoFileName());

public static final String photopath = Environment.getExternalStorageDirectory() + "/photodemo";

private String getPhotoFileName() {

Date date = new Date(System.currentTimeMillis());

SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");

return dateFormat.format(date) + ".jpg";

}

当拍照结束后,会在外部的根目录生成一个photodemo的文件夹里面会有一张名字为IMG_加上当前时间.jpg的一张图片,这张图片是拍照后得到的 没有经过裁剪的

最后调用系统的拍照功能,同时指定照片生成的路径

Intent intent2 = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

intent2.putExtra(MediaStore.EXTRA_OUTPUT, targetUri);

startActivityForResult(intent2, PHOTO_REQUEST_TAKEPHOTO);// 采用ForResult打开

可以看到startActivityForResult调用的拍照功能,同时requestcode==PHOTO_REQUEST_TAKEPHOTO

所以重写onActivityResult在onActivityResult中拿到拍摄的照片

@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

switch (requestCode) {

case PHOTO_REQUEST_TAKEPHOTO:

if (resultCode == RESULT_OK) {

startPhotoZoom(targetUri, 200);// 裁剪图片

}

break;

case PHOTO_REQUEST_GALLERY:

if (resultCode == RESULT_OK) {

startPhotoZoom(data.getData(), 200);// 裁剪图片

}

break;

case PHOTO_REQUEST_CUT:

if (data != null && !"".equals(data)) {

Bundle extras = data.getExtras();

head = extras.getParcelable("data");

if (head != null) {

mImageView.setImageBitmap(head);

/**

* 上传服务器代码

*/

RequestBody requestFile =

RequestBody.create(MediaType.parse("image/png"), cropFilePath);

// MultipartBody.Part is used to send also the actual file name

MultipartBody.Part Part =

MultipartBody.Part.createFormData("avatar", cropFilePath.getName(), requestFile);

Upload(Part);

}

}

break;

default:

break;

}

}

首先只看下面这个,其他的case后面会讲到

case PHOTO_REQUEST_TAKEPHOTO:

if (resultCode == RESULT_OK) {

startPhotoZoom(targetUri, 200);// 裁剪图片

}

break;

private void startPhotoZoom(Uri uri, int size) {

Intent intent = new Intent("com.android.camera.action.CROP");

intent.setDataAndType(uri, "image/*");

// crop为true是设置在开启的intent中设置显示的view可以剪裁

intent.putExtra("crop", "true");

// aspectX aspectY 是宽高的比例

intent.putExtra("aspectX", 1);

intent.putExtra("aspectY", 1);

// outputX,outputY 是剪裁图片的宽高

intent.putExtra("outputX", size);

intent.putExtra("outputY", size);

intent.putExtra("return-data", true);

cropFilePath = new File(photopath, getCroPhotoFileName());

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFilePath));

startActivityForResult(intent, PHOTO_REQUEST_CUT);

}

前面说了 当拍照完后,再调用系统的裁剪

简单的代码上面我都标了注释,我设置裁剪图片的宽度是200,200,可以自行改变

通过 intent.setDataAndType(uri, "image/*");根据拍照后设置的图片路径拿到照片

最后设置裁剪后的图片存放的位置,因为上传服务器是上传裁剪后的图片

cropFilePath = new File(photopath, getCroPhotoFileName());

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cropFilePath));

--------------------------------

private String getCroPhotoFileName() {

Date date = new Date(System.currentTimeMillis());

SimpleDateFormat dateFormat = new SimpleDateFormat("'CROIMG'_yyyyMMdd_HHmmss");

return dateFormat.format(date) + ".jpg";

}

这里说一下为什么要裁剪图片,

f2ca7f973aeb

这里写图片描述

前缀为croimg的是裁剪后的图片

对比一下大小,差别很大,同时在手机上,控件加载并不需要这么大的图片,所以裁剪看来是很必要的

最后拿到裁剪后的图片后

case PHOTO_REQUEST_CUT:

if (data != null && !"".equals(data)) {

Bundle extras = data.getExtras();

head = extras.getParcelable("data");

if (head != null) {

mImageView.setImageBitmap(head);

/**

* 上传服务器代码

*/

RequestBody requestFile =

RequestBody.create(MediaType.parse("image/png"), cropFilePath);

// MultipartBody.Part is used to send also the actual file name

MultipartBody.Part Part =

MultipartBody.Part.createFormData("avatar", cropFilePath.getName(), requestFile);

Upload(Part);

}

}

break;

首先head是我定义的一个bitmap

Bitmap head;

可以直接通过

Bundle extras = data.getExtras();

head = extras.getParcelable("data");

拿到一张bitmap,同时这张bitmap也是裁剪过后的

然后根据裁剪后的图片的路径找到文件,并上传到服务器

2,从相册选择照片

前面在第二个button定义了一个点击事件

public void getPhotoFromPhone(View view) {

MPermissions.requestPermissions(MainActivity.this, 3, Manifest.permission.READ_EXTERNAL_STORAGE);

}

请求读取外部存储卡的权限,请求成功后

@PermissionGrant(3)

public void requestContactSuccess() {

String sdStatus = Environment.getExternalStorageState();

if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用

Toast.makeText(this, "sd卡不可用", Toast.LENGTH_SHORT).show();

return;

}

// 设置文件类型

Intent intent = new Intent(Intent.ACTION_PICK, null);

intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");

startActivityForResult(intent, PHOTO_REQUEST_GALLERY);

}

@PermissionDenied(3)

public void requestContactFailed() {

Toast.makeText(this, "没有权限", Toast.LENGTH_SHORT).show();

}

代码很简单,也是调用手机系统的选择照片功能

拿到照片后,继续裁剪

case PHOTO_REQUEST_GALLERY:

if (resultCode == RESULT_OK) {

startPhotoZoom(data.getData(), 200);// 裁剪图片

}

break;

然后和上面开始走一样的逻辑

最后简单的说明retrofit2单文件上传的参数说明

requestbody放置参数,比如我的接口需要一个token的参数

RequestBody tokenString =

RequestBody.create(

MediaType.parse("multipart/form-data"), token);

requestpart 放置文件,比如上面裁剪后得到的图片,根据文件路径拿到图片位置

RequestBody requestFile =

RequestBody.create(MediaType.parse("image/png"), cropFilePath);

// MultipartBody.Part is used to send also the actual file name

MultipartBody.Part Part =

MultipartBody.Part.createFormData("avatar", cropFilePath.getName(), requestFile);

上传到服务器

最后看下效果图,因为是模拟器跑的 所以没有真实的镜头

f2ca7f973aeb

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用vant-uploader和vue-cropper来实现裁剪图片并上,你可以按照以下步骤进行操作: 1. 首先,安装vant和vue-cropper插件。你可以使用npm或yarn来安装它们。 2. 在你的Vue组件中,引入vant-uploader和vue-cropper组件。 3. 在模板中,使用vant-uploader组件来实现图片上功能。设置上的action属性为你的上接口地址,并设置on-success事件来处理上成功后的逻辑。 4. 在on-success事件中,获取到上成功后的图片地址,并将其递给vue-cropper组件。 5. 在vue-cropper组件中,设置裁剪框的样式和裁剪比例等属性。使用v-model指令来绑定裁剪后的图片数据。 6. 在提交按钮的点击事件中,将裁剪后的图片数据上服务器。 下面是一个简单的示例代码: ```vue <template> <div> <van-uploader action="/upload" :on-success="handleUploadSuccess" ></van-uploader> <vue-cropper v-if="showCropper" :src="cropperSrc" :output-size="{ width: 200, height: 200 }" :output-type="'jpeg'" :fixed-box="true" :fixed-number="\[1, 1\]" v-model="croppedImage" ></vue-cropper> <button @click="handleSubmit">提交</button> </div> </template> <script> import { VanUploader } from 'vant'; import VueCropper from 'vue-cropper'; export default { components: { VanUploader, VueCropper, }, data() { return { showCropper: false, cropperSrc: '', croppedImage: '', }; }, methods: { handleUploadSuccess(response) { // 获取上成功后的图片地址 const imageUrl = response.data.imageUrl; // 显示裁剪组件 this.showCropper = true; // 设置裁剪组件的图片地址 this.cropperSrc = imageUrl; }, handleSubmit() { // 提交裁剪后的图片数据到服务器 // this.croppedImage 包含裁剪后的图片数据 }, }, }; </script> ``` 请注意,以上代码只是一个简单的示例,你需要根据你的实际需求进行适当的修改和调整。同时,你还需要在后端实现相应的上裁剪功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值