ionic上传图片总共分3个步骤:
(1)通过插件选取图片,或者调用手机相机拍摄然后获取图片
(2)将获取到的图片进行编辑,裁剪
(3)将裁剪后的图片利用ajax上传至服务器
ionic cordova plugin add cordova-plugin-camera
npm install @ionic-native/camera
import { Camera, CameraOptions } from '@ionic-native/camera/ngx';
constructor(private camera: Camera) { }
...
const options: CameraOptions = {
quality: 100, // 这里图片质量最好不要100 , 会导致有些图片上传不成功
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
this.camera.getPicture(options).then((imageData) => {
// 为了保证在低内存手机使用正常,获取路径类型建议不要选择Base64,否则会导致手机闪退崩溃
// 这里获取出来的路径,是带“file://”协议的,
}, (err) => {
// Handle error
});
ionic cordova plugin add cordova-plugin-file
npm install @ionic-native/file
import {File} from '@ionic-native/file/ngx';
constructor(private file: File) { }
...
async translateFilePath(file) {
file = await this.file.resolveLocalFilesystemUrl(file);
file = file.toInternalURL(); // 转化成cdvfile://地址
return file;
}
// 这里的文件,是已经通过file插件,转换成了cdvfile:// 协议的
const fileTransfer: FileTransferObject = this.transfer.create();
const options: FileUploadOptions = {
fileKey: 'upload', // 后端接口接收文件的键名
chunkedMode: false, // 这里一定要设置false, 否则安卓上是上传不成功的,
fileName: file.substr(file.lastIndexOf('/') + 1),
params: { // 接口额外的参数,视接口而定 }
};
try {
const {response} = await fileTransfer.upload(file, encodeURI('http://demo.api/uploadFile'), options);
const ret = JSON.parse(response);
console.log(ret);
} catch (e) {
console.log(e);
}
let cameraOption: any = {
quality: 65,
allowEdit: true, // IOS上,若是使用Crop插件裁剪图片,那么这个参数必须设置为true
correctOrientation: true, // 旋转图像以在捕获过程中校正设备的方向
destinationType: this.camera.DestinationType.FILE_URI, // 返回的数据类型,默认DATA_URL
sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM, // 来源类型,默认CAMERA
};
抛弃了Crop插件后,目光锁在了H5裁剪上,于是百度一番,找到了cropperjs 这个纯javascript插件,功能比较强大,原理使用Canvas进行图片编辑,对于浏览器兼容性较好。GitHub地址:https://github.com/fengyuanchen/cropperjs
在确认使用cropperjs插件后,图片上传,也是弃用了FileTransfer插件,官方也是不太建议使用FileTransfer上传的,并且也已经不再维护此插件,上传还是改用了ajax。
使用这种方式裁剪图片,需要解决一个问题,通过Camera插件获取的图片文件路径是file协议,把此路径直接放入img 的src 是不会显示图片的,那么就无法使用cropperjs进行裁剪,之前在cordova-plugin-file GitHub 上看到一段文字:
To use cdvfile as a tag' src you can convert it to native path via toURL() method of the resolved fileEntry, which you can get via resolveLocalFileSystemURL - see examples below.
You can also use cdvfile:// paths directly in the DOM, for example:
Note: This method requires following Content Security rules updates:
1. Add cdvfile: scheme to Content-Security-Policy meta tag of the index page, e.g.:
' data: gap: cdvfile: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
2. Add > to config.xml.
但是这个方法展示HTML图片,我也放弃了,因为第一个条件,就很麻烦,下面附上另一个解决方法:
// 借助ionic-webview提供的convertFileSrc方法转换file:// 协议的文件路径
import { WebView } from '@ionic-native/ionic-webview/ngx'; // 使用Cordova
import { DomSanitizer } from '@angular/platform-browser';
import { Capacitor } from '@capacitor/core'; // 若是使用Capacitor,则需要导入此
constructor(private webview: WebView, private domSanitizer: DomSanitizer) { }
...
let imgSrc = this.webview.convertFileSrc('file:///Users/dan/camera-image-12345.png'); // Cordova对应的
// let imgSrc = Capacitor.convertFileSrc(filePath); // 使用Capacitor
imgSrc = this.domSanitizer.bypassSecurityTrustUrl(imgSrc); // 这样Dom中就可以正常显示file:// 协议的图片了
具体使用可以参照官方文档:https://github.com/fengyuanchen/cropperjs
当然也有大神对于Angular使用封装了一个插件:https://github.com/matheusdavidson/angular-cropperjs 其配置参数和官方文档无异
npm i angular-cropperjs --save
<angular-cropper [cropperOptions]="config" [imageUrl]="imageUrl" #angularCropper>angular-cropper>
import {NavController} from "@ionic/angular";
import {ActivatedRoute} from "@angular/router";
import { HttpClient} from "@angular/common/http";
import { DomSanitizer } from '@angular/platform-browser';
import {Component, OnInit, ViewChild} from '@angular/core';
import {ToolsService} from "../../services/tools/tools.service";
import {apilist} from "../../services/request/api/apiListConfig";
import {ComponentsService} from "../../services/component/component.service";
@Component({
selector: 'app-crop',
templateUrl: './crop.page.html',
styleUrls: ['./crop.page.scss'],
})
export class CropPage implements OnInit {
@ViewChild('angularCropper', { static: true}) angularCropper: any;
cropper: any;
imageData: any;
config: any = {
viewMode: 1,
autoCropArea: 1,
dragMode :'move',
aspectRatio: this.activedRoute.snapshot.queryParamMap.get('imageAspectRatio'), //裁剪框的宽高比
autoCrop:true, //初始化时,自动生成裁剪框 当初始化时,可以自动生成图像。(就是自动显示裁剪框,改成false裁剪框自动消失
cropend: function () { // 每次裁剪完毕,获取裁剪后的图片
this.getCropperImage();
}.bind(this),
ready: function () {
this.getCropperImage(); // 初始化后,自动获取默认裁剪区域的图片
}.bind(this)
};
imageUrl: any = "../../../assets/icon/[email protected]";
constructor(
private http: HttpClient,
private dom: DomSanitizer,
private toolsService: ToolsService,
private navController: NavController,
private activedRoute: ActivatedRoute,
private componentsService: ComponentsService,
) { }
async ngOnInit() {
const localImage = this.activedRoute.snapshot.queryParamMap.get('imageSrc');
if(localImage) this.imageUrl = this.dom.bypassSecurityTrustUrl(localImage) ;
}
getCropperImage() {
this.imageData = this.angularCropper.cropper.getCroppedCanvas({
width: 750, // 这里配置的是裁剪后,生成后的图片的大小,width和height至少需要设置一个,否则IOS可能无法生成裁剪图片导致上传文件是失败的,
imageSmoothingEnabled: true,
imageSmoothingQuality: 'high'
});
}
async uploadCropImage() {
await this.toolsService.showLoading();
this.imageData.toBlob(blob => { // this.imageData.toDataURL('image/jpeg') 可以生成base64, 这里是使用Blob来上传图片,推荐使用
const formData = new FormData();
formData.append('upload', blob, new Date().valueOf()+'.png');
this.http.post(apilist().uploadFile, formData).toPromise().then((res: any) => {
if(res.status) {
this.toolsService.toast('上传成功');
const events = this.activedRoute.snapshot.queryParamMap.get('events');
this.componentsService.sendEvents({ type: events, data: res.data.url});
this.navController.back();
} else {
this.toolsService.toast(res.msg);
}
}).catch(err => console.log(err)).finally(() => this.toolsService.hideLoading())
})
}
}
集成之后,Android和IOS都运行试过了,基本没有太大问题,尤其注意一点,如果IOS上出现裁剪框无法拖动,请试着将cropperjs安装至最新版本:
npm i cropperjs --save
过程中有问题请留言。