因公司项目需要,要修改一个手机端上传图片的一个功能,原本的项目用的是input 的file控件上传的,虽然标注了可以多选,但是在实际运用当中只有iOS手机可以实现多选,Android手机并不支持多选,甚至部分Android手机因为input file 上multiple="multiple"属性连图片选择框都打开不了。而这次的需求需要用户上传多张图片,显然让用户一张图片一张图片上传满足不了需求,我们需要多选上传。

  因为我们的项目是挂在微信企业号里面的,所以我想到用微信企业号的JS-SDK的方法来选择图片,可以直接绕开file控件的缺陷。直接上代码:  

  

wx.chooseImage({
count: , // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
$(".previewimg").html("");//每次选择图片完成后都清空之前已经添加的html节点
var images = {
localId: [],//微信返回的本地id列表
serverId: [],//微信返回的服务器id列表
};
ioslocId = [];//用于兼容ios的本地id列表 图片是base64格式的
rows = "";//声明一个空字符串用于保存循环出来的html
images.localId = images.localId.concat(res.localIds); // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
localId = images.localId;
try { for (var i = ; i < images.localId.length; i++) {
//alert(res.localIds[i]);
wx.getLocalImgData({ //循环调用 getLocalImgData
localId: res.localIds[i], // 图片的localID
success: function (res) {
var localData = res.localData; // localData是图片的base64数据,可以用img标签显示
//alert(localData);
if (window.__wxjs_is_wkwebview) { //ios
localData = localData.replace('jgp', 'jpeg');//iOS 系统里面得到的数据,类型为 image/jgp,因此需要替换一下
}
else {
localData = "data:image/jpeg;base64," + localData; //android
}
ioslocId.push(localData) //把base64格式的图片添加到ioslocId数组里 这样该数组里的元素都是base64格式的
rows = "";
for (var j = ; j < ioslocId.length; j++) {
rows += '<img style="margin: 5px;" class="up_p" src="' + ioslocId[j] + '"> <input type="hidden" name="upimg' + j + '" value="' + ioslocId[j] + '" />';
}
$(".previewimg").html(rows);
}, fail: function (e) {
alert(e);
}
});
} }
catch (err) {
alert(err) // 可执行
} }
});

这里注意到:微信企业号api官网上:https://work.weixin.qq.com/api/doc#10029/获取本地图片接口

说:wx.getLocalImgData,此接口仅在企业微信iOS支持,要求版本为2.4.6及以上,但是我们很显然的发现,Android也可以用只是返回的res.localData做处理的不同而已。

一开始我也不知道安卓手机获取的图片可以直接用getLocalImgData的返回值转base64,所以我想了很多其他办法,也走了不少冤枉路,比如我想用前端显示的图片转base64,用canvas ,如下:

function getBase64Image(img) {
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, , , img.width, img.height);
var dataURL = canvas.toDataURL("image/png");
return dataURL
// return dataURL.replace("data:image/png;base64,", "");
}

但是很遗憾,这里的img必须是同一域里的图片或者是允许跨域访问的图片地址,而微信返回的是本地ID,即使安卓手机上这个id可以直接放在img 的src上显示图片,但不知是因为id问题还是因为这个“地址”不允许跨域访问导致用canvas转的base64是错的,传到服务器端后不能保存成我们选择的图片。所以这个方法肯定不行。

于是经过他人的指点我想到用wx.uploadImage接口先上传到微信服务器,然后再用微信提供的接口在服务器端将微信服务器的图片下载到我们自己的服务器。

wx.uploadImage({
localId: '', // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: , // 默认为1,显示进度提示
success: function (res) {
var serverId = res.serverId; // 返回图片的服务器端ID
}
});

服务器端请求地址:https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID

此处获得的 media_id即serverId  。

这里上传到微信服务器必须一提的是:上传图片只能一张一张图片上传,上传下一张图片必须等上一张图片上传完成,再进行下一张图片,所以我立即想到写个递归上传即可,如下:

//递归上传到微信服务器 add by torres  cooooooooooooooool
localId: [];
function uploadImg(index) {
if (index < ) {
return;
}
wx.uploadImage({
localId: localId[index], // 需要上传的图片的本地ID,由chooseImage接口获得
isShowProgressTips: , // 默认为1,显示进度提示
success: function (res) {
//res.serverId 返回图片的服务器端ID
try {
var rows = '<input type="hidden" name="serverIdArr' + index + '" value="' + res.serverId + '" />';
$(".previewimg").append(rows);
} catch (e) {
alert(e)
}
uploadImg(index - );
}, fail: function (res) {
alert("上传失败,msg:" + JSON.stringify(res));
}
});
}

这样的写法可能有点low,我在网上看到另一种

 var syncUpload = function (localIds, index) {
var localId = localIds.pop();
wx.uploadImage({
localId: localId,
isShowProgressTips: ,
success: function (res) {
//其他对serverId做处理的代码
try {
//alert("上传下一张");
var serverId = res.serverId; // 返回图片的服务器端ID
var rows = '<input type="hidden" name="serverIdArr' + index + '" value="' + res.serverId + '" />';
$(".previewimg").append(rows);
if (localIds.length > ) {
syncUpload(localIds, index - );
}
} catch (e) {
alert(e)
}
}, fail: function (res) {
alert("上传失败,msg:" + JSON.stringify(res));
}
});
};

两种方法差不多,都能实现我想要的,但是仅仅是在iOS。很奇怪,在Android机器上,上传多张图片时并不能上传全部图片并返回sercerId并打印出input隐藏域在页面上(或者说并不是所有图片上传都走了success方法,但也没有走fail方法),单张图片上传完全OJBK。这就很让人郁闷了,选择了三张图片上传微信服务器,但是只返回了一个或两个serverId,十分不稳定,有时候能全部上传,有时候只能上传部分图片。

这里也顺便贴出C#语言后台下载微信服务器端图片代码:

 string stUrl = string.Format("https://qyapi.weixin.qq.com/cgi-bin/media/get?access_token={0}&media_id={1}", access_token, serverIdArr[i]);
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(stUrl);
HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();
string contentType = myResponse.ContentType;
if (myResponse.ContentLength == || (contentType != "image/jpeg" && contentType != "image/pjpeg" && contentType != "image/bmp" && contentType != "image/gif" && contentType != "image/png" && contentType != "image/x-png"))
{
htInfo["error"] += "第" + (i + ) + "个文件上传的附件格式不对,请重新上传!<br/>";
continue;
}
int picUploadSize = Convert.ToInt32(ConfigurationManager.AppSettings["picUploadSize"]);
if (myResponse.ContentLength > picUploadSize * )
{
htInfo["error"] += string.Format("第" + (i + ) + "个图片不能超过{0}KB!<br/>", picUploadSize);
continue;
}
req.Method = "GET";
//req.ProtocolVersion = HttpVersion.Version10;
string strpath = myResponse.ResponseUri.ToString();
WebClient mywebclient = new WebClient();
string extension = GetExtensionName(contentType); //获取扩展名
string imgName = DateTime.Now.ToString("yyyyMMddHHmmssffff") + extension;
//下载原图
mywebclient.DownloadFile(strpath, savepath);

最终因为Android上传图片的问题这个方法还是行不通。没有办法之下我只能在 wx.chooseImage的success方法里显示选择图片的下面再加一个上传按钮,让用户手动一个一个点击上传到微信服务器,这样保证了每张都可以返回serverId,这么low的方法只能先用着了,正当我要放弃继续探索其他方法的时候,我在微信开发群里面问了一下我这个问题,然后有好心的群友给了我建议说直接转base64,不用上传微信服务器时我就告诉了他我的疑问,他给了我他的代码,最终有了

localData = "data:image/jpeg;base64," + localData;   //android
上面这行代码 ,苦苦追寻,在埋头研究两天后终于实现了手机端选择多图上传的功能,在用户操作上也不用区分iOS和Android。
以上的故事告诉我们:不要轻言放弃,这种方法不行就换一种再试试,你会发现,哪一种方式都TM不行啊!!!我屮艸芔茻。略略略略略 ,才不是呢!你会发现总有一种适合你。
有什么建议或意见可以请大家多多指点,谢谢!

微信企业号JS-SDK选择图片、上传图片的更多相关文章

  1. 微信企业号JS SDK

    微信企业号JS SDK <?php define('CorpID', "wx82e2c31215d9a5a7"); define('CorpSecret', "&q ...

  2. 微信前端js sdk以外的开发

    此时页面中就会出现刚才我画红圈部分的工具条. 这个工具条再加上上面的标题栏工具条. 极大的降低了可视区域的面积. 是否能将它去掉呢?答案是能够的.增加以下代码就能够去掉微信中以下的工具条: docum ...

  3. python开发微信公众号SDK选择

    1.wechat-sdk sudo pip install wechat-sdk 文档地址:  http://ww2.wechat-python-sdk.com/ 2.wechat sudo pip ...

  4. 调用微信js sdk

    场景:需要调用微信获取当前位置的借口. 途径:查看微信 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 .后 ...

  5. 微信JS-SDK选择图片遇到的坑

    微信JS-SDK选择图片遇到的坑 有个需求要在微信企业号里面做开发,有个功能是选择图片,使用input标签肯定是不管用了,Android手机上不能多选,所以使用了微信的JS-SDK提供的相关API,这 ...

  6. 微信JS SDK Demo 官方案例[转]

    摘要: 微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包. 通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照.选图.语音.位置等手机系统的能力,同时可以直接使用 ...

  7. 微信js SDK接口

    微信JS-SDK说明文档 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 一.微信登录功能 在进行微信OAut ...

  8. 微信企业号办公系统-JSSDK上传图片(多图上传)

    在开发微信企业号办公系统中,涉及到了图片上传功能,一开始使用的flash插件上传方法,在苹果手机上可以调用相机直接拍摄照片,但在安卓手机上只能选择照片. 微信jssdk-api带有一套完整的调用选择本 ...

  9. 微信JS SDK Demo

    微信JS-SDK 分享到朋友圈 分享给朋友 分享到QQ 拍照或从手机相册中选图 识别音频并返回识别结果 使用微信内置地图查看位置原文:http://www.cnblogs.com/txw1958/p/ ...

随机推荐

  1. maven项目添加findbugs,checkstyle,jacoco,assembly,maven-jar-plugin插件的配置

    (1)名称解释(插件的作用) findbugs:检测代码的不明显的语法错误.例如:用了==去比较字符串,定义了没有用的变量-- checkstyle:检测代码的格式规范.例如:方法没有写注释,类的命名 ...

  2. 【原创】相对完整的一套以Jmeter作为工具的性能测试教程(接口性能测试,数据库性能测试以及服务器端性能监测)

    准备工作 jmeter3.1,为什么是3.1,因为它是要配合使用的serveragent所支持的最高版本,下载链接 https://pan.baidu.com/s/1dWu5Ym JMeterPlug ...

  3. android EditText与TextView几个常用的属性

    android:maxLength="100"输入框最多输入的字数. android:maxEms="10"每行最多输入字符个数 android:textcol ...

  4. JavaScript之正则表达式(1)

    一,在线工具: regexper.com 二 ,正则示例: (1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)(1)( ...

  5. zabbix图形乱码

    毕竟是中文为主,特别是有些香项目最好以中文命名,容易区分,也方便识别 环境: centos7.3安装zabbix3.2 问题: 图文乱码问题 原理上只要找到对应的字符集,在修改配置文件 windows ...

  6. 【转】shell学习笔记(一)——学习目的性、特殊字符、运算符等

    1 学习shell的目的性 写之前我们先来搞清楚为什么要学shell,学习要有目的性 shell简单.灵活.高效,特别适合处理一些系统管理方面的小问题 shell可以实现自动化管理,让系统管理员的工作 ...

  7. 【转】wget(二)

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  8. mysql 我们眼中的int(10)

    自我总结,欢迎拍砖! 目的:定义int(3)和int(10)真的有区别吗? 论证: 1.创建student,student2表 分别定义一个student,student2表 create table ...

  9. 模块dll和lib

    一.dll动态链接库 1.dll 没有 main 函数 2.不能直接执行,可以注入exe中让它间接执行.只有把它编译到应用程序中才可以. 3.编写dll 函数前加上 _declspec(dllexpo ...

  10. Azure Functions + Azure Batch实现MP3音频转码方案

    客户需求 客户的环境是一个网络音乐播放系统,根据网络情况提供给手机用户收听各种码率的MP3歌曲,在客户没购买歌曲的情况下提供一个三十秒内的试听版本.这样一个系统非常明确地一个需求就是会定期需要将一批从 ...