因公司项目需要,要修改一个手机端上传图片的一个功能,原本的项目用的是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. 【转】CentOS 6.3(x86_32)下安装Oracle 10g R2

    一.硬件要求 1.内存 & swap Minimum: 1 GB of RAMRecommended: 2 GB of RAM or more 检查内存情况 # grep MemTotal / ...

  2. [HTTP] PHP 实现 HTTP Server 原理

    单进程服务器简陋版: <?php /** * Single http server. * * Access http://127.0.0.1:8081 * * @license Apache-2 ...

  3. poj2479 最大子段和

    题意:给定一个数列.求出数列中不相交的两个子段和,要求和最大 解题思路:对每一个i来说,求出[0-i-1]的最大子段和以及[i-n-1]的最大子段和,再加起来,求出最大的一个.[0-i-1]的最大子段 ...

  4. CSS选择器的组合选择器之后代选择器和子元素选择器

    实例代码: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF ...

  5. iOS-MD5加密、SHA1加密

    1.MD5加密 ///MD5加密************************************** + (NSString *)md5:(NSString *)inputString{ co ...

  6. GitHub入门之路(1)

    介绍 从本篇文章开始,是一系列介绍GitHub相关内容以及Git的一些基本操作的文章,记录了自己的学习过程. 概要 简单介绍GitHub是什么,Git又是什么. 1.Git是什么 Git是一款分散型的 ...

  7. bzoj 4835: 遗忘之树 [树形DP]

    4835: 遗忘之树 题意:点分治,选标号最小的重心,上一次重心向下一次重心连有向边,求原树方案数. md我真不知道当初比赛时干什么去了...现在一眼秒啊... \(size[v]=\frac{siz ...

  8. POJ 2404 Jogging Trails [DP 状压 一般图最小权完美匹配]

    传送门 题意:找一个经过所有边权值最小的回路,$n \le 15$ 所有点度数为偶则存在欧拉回路,直接输出权值和 否则考虑度数为奇的点,连着奇数条边,奇点之间走已经走过的路移动再走没走过的路 然后大体 ...

  9. Getting the pixel coordinates of text or ticks in matplotlib

    The exact pixel coordinates of title, labels, legends or ticks are important information for the tra ...

  10. Jenkins持续集成-自动化部署脚本的实现

    要实现Jenkins端的持续集成,其实在CI服务配置端很容易,难点呢?就是如何实现自动化的部署.我的脚本设计就是为了解决以下难题: 难点一.如何使得自动化部署脚本更通用 我用的脚本,依赖依赖一个配置文 ...