由于产品需要讲word中的图片自动上传到服务端,现阶段不少浏览器对本地文件的访问存在不少限制,基于这个出发点调研可行性
● 先要确认两个前提
1、Chrome扩展可以获取到粘贴到编辑器里的文档
2、扩展可以上传文件到远程服务器
这两个问题应该都是可行的,
对于第2个问题,要知道的是可以用纯js上传文件,还是需要写dll扩展。
● 百度搜索"Chrome扩展 Hello World"
http://blog.csdn.net/ciml/article/details/5638112
找到一个示例,仿写并运行之。
关测试
"matches": [ "http:///article", "https:///article" ],
果然能匹配路径中有article字样的
manifest.json中的content_scripts中的run_at:该字段指明对应内容脚本执行的时机。可以取三个值:
document_start:文档开始,相当于document对象刚刚创建,此时DOM树还没有构建完成。这个值是内容脚本挂接文档级事件的好时机。
document_end:文档结束,此时DOM树已经构建,主文档加载完毕,但图片等子资源数据可能未加载完成。
document_idle:空闲,可理解为在window.onload事件之后执行。
● Chrome插件教程,在 Nutz ② 群 里 大鲨鱼(11624317) 的教程
http://www.wizzer.cn/?p=2378
经验分享:Chrome插件开发源码说明
● 在chrome下上传文件
google搜索"develop Upload Extension For Chrome -Dashboard"
http://stackoverflow.com/questions/4093722/upload-a-file-in-a-google-chrome-extension
XMLHttpRequest2 新技巧
http://www.html5rocks.com/zh/tutorials/file/xhr2/
在上一篇文章中有FileSystem API链接
FileSystem API
http://www.html5rocks.com/zh/tutorials/file/filesystem/
File API
http://www.html5rocks.com/zh/tutorials/file/dndfiles/
● 查找扩展与页面通讯的方法
百度搜索“chrome 插件 不能访问web页面 的变量和函数”
http://open.chrome.360.cn/html/dev_content_scripts.html
http://open.chrome.360.cn/html/dev_messaging.html
参考上面的代码对同一个页面上的表单元素监听事件,来传递数据
在页面的js里
var customEvent = document.createEvent('Event');
customEvent.initEvent('valuechange', true, true);
dataBridgeElem4plugin.value=JSON.stringify(getLocalImagesInEditor());
dataBridgeElem4plugin.setAttribute('uploadActionUrl',uploadActionUrl);
dataBridgeElem4plugin.dispatchEvent(customEvent);
dataBridge.addEventListener('valuechange',function(){
var replaceList=JSON.parse(dataBridge.value);
replaceImgTags(replaceList);
})
在插件的js里
dataBridgeElem4plugin.addEventListener('valuechange', function() {
ZvingTools.replaceImagesList = JSON.parse(dataBridgeElem4plugin.value);
ZvingTools.uploadActionUrl = dataBridgeElem4plugin.getAttribute('uploadActionUrl');
ZvingTools.uploadAllImages();
});
● 读取本地文件
dataBridgeElem4plugin.addEventListener('valuechange', function() {
ZvingTools.replaceImagesList = JSON.parse(dataBridgeElem4plugin.value);
ZvingTools.uploadActionUrl = dataBridgeElem4plugin.getAttribute('uploadActionUrl');
ZvingTools.uploadAllImages();
});
在
http://www.html5rocks.com/zh/tutorials/file/filesystem/
发现相关说明:
如果您是首次调用 requestFileSystem(),系统会为您的应用创建新的存储。请注意,这是沙箱文件系统,也就是说,一个网络应用无法访问另一个应用的文件。这也意味着您无法在用户硬盘上的任意文件夹(例如“我的图片”、“我的文档”等)中读/写文件。
● Chrome插件开发中的消息传递
http://blog.csdn.net/xiaioji/article/details/7996871
特别应该注意的是:扩展程序向内容脚本发送请求数据时用的是chrome.tabs.sendMessage,反过来,用的是chrome.extension.sendMessage。
接收都用
chrome.extension.onMessage
◎chrome.tabs.sendMessage第一个参数为tab.id,需要异步获取
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendMessage(tab.id, {
message: msg
});
});
● 推测:对文件的读写需求肯定其他人也需要,是不是有现成的NPAPI呢?
搜索"NPAPI Filesystem access for Chrome extensions"
找到npapi-file-io
http://code.google.com/p/npapi-file-io/
使用npapi-file-io的示例见
https://github.com/captn3m0/sympathy
https://github.com/nirgeier/HTML5Files_NPAPI
var fileIO = document.getElementById('plugin0');
fileIO.getBinaryFile('F:Tempmsohtml101clip_image002.gif')
发现得到的内容为一个Array对象,怎么转为文件对象?
在之前阅读的文章里见到过 FileReader Blob 等关键词,了解一下先
●搜索"文件上传 FileReader BlobBuilder Blob"
找到相关的文章
http://www.cfanz.cn/?c=article&a=read&id=35
var reader = new FileReader();
reader.onload = function(event) {
var filecontent = event.target.result;
var builder = new WebKitBlobBuilder();
builder.append(filecontent);
var blobURL = webkitURL.createObjectURL(builder.getBlob("image/gif"));
console.log(blobURL);
};
var control = document.getElementById("file1");
var file = control.files[0];
console.log(webkitURL.createObjectURL(file))
reader.readAsArrayBuffer(file);
通过阅读文章,及上面的测试,
对Blob有一些了解,
◎Blob里可以放 字符串 或者 ArrayBuffer 或者 Blob,
http://yimity.com/2012/06/06/working-with-files-in-javascript-part-5-blobs.html
var blob=new Blob([arrayBuffer], { type: "image/gif" });
◎操作文件需要用到 File 对象,实际上 File 对象只是 Blob 对象的一个更具体的版本,blob 存储着大量的二进制数据,并且 blob 的 size 和 type 属性,都会被 file 对象所继承。
所以,可以说,在大多数情况下,blob 对象和 file 对象可以用在同一个地方,例如,可以使用 FileReader 借口从 blob 读取数据,也可以使用 URL.createObjectURL() 从 blob 创建一个新的 URL 对象。
http://yimity.com/2012/06/06/working-with-files-in-javascript-part-5-blobs.html
◎ 可以用一个Blob创建一个网络线程(new Worker())而不需要为这个线程代码写一份单独的文件。
◎ FileReader 只有一个功能,那就是读取文件数据并且将其存储在 javascript 变量中,此 API 专门被设计成模拟(类似) XMLHttpRequest 操作,因为它们两个都是从外部资源加载数据(不包括浏览器)。
readAsText() – 返回文本数据(text/plain)。
readAsBinaryString() – 返回此文件被编码的二进制数据 (已弃用– 使用 readAsArrayBuffer() 代替)。
readAsArrayBuffer() – 返回此文件的一个ArrayBuffer(二进制数据缓冲)(适合二进制数据,例如图像文件)数据。
readAsDataURL() – 返回此文件的 data URL
◎ ArrayBuffer 最初是作为 WebGL 的一部分的,ArrayBuffer 代表一个可以存储任意任意大小的数字的一个有限的区域,此种方式读取的数据,必须使用特殊的方式访问,例如 Int8Array ,将此底层的数据视为 8 位的符号整数。或者 Float32Array 将其视为 32 位的浮点数,这些都被叫做类型化数组/格式化数组,都被强制的使用某种数据格式来使用,而不像普通格式的数据那样。
ArrayBuffer 主要用来处理二进制数据文件,已能够对数据具有更细粒度的控制,并且远远超出此篇文章解释的范围。反正在使用的时候,只要记住,你可以很简单的将一个文件读取为二进制缓冲,并且可以简单地将此数据通过 XHR 的 send() 方法发送给后端服务器(当然了,你必须从服务器上接受此二进制缓冲,并且重建此文件),但是浏览器还必须完整的支持 XMLHttpRequest Level 2,不过可惜的是,只有 IE10 以上的现代浏览器才支持。
● 现在要解决的问题就是 普通数组与 ArrayBuffer 数组之间的转换问题了
首先,发现fileContent=fileIO.getBinaryFile(filePath)返回的数组内有负数,
以2进制打开图片文件,发现fileContent内为-92 在图片文件二进制对应数字为 164 (十六进制为A4)
使用附件科学计算器 把十进制 -92 转为十六进制(或2进制)时,发现后两位(8位字节),值为A4
可知数组内存的数据原来,Uint8,转为了int后出现了负数,所以需要变回为Uint8
搜索"ArrayBuffer DataView Uint8Array 数组"
http://msdn.microsoft.com/zh-cn/library/br212477
发现了转换方法
arr=[71, 73, 70, 56, 57, 97, -92, 0, 76, 0, 119, 0, 49, 33, -2];
uInt8Array = new Uint8Array(arr);
结果为
[71, 73, 70, 56, 57, 97, 164, 0, 76, 0, 119, 0, 49, 33, 254]
并且uInt8Array.buffer直接指向一个ArrayBuffer对象,可以用于构建Blob对象。
这时候再去查看之前找到过的文章
Upload a File in a Google Chrome Extension
http://stackoverflow.com/questions/4093722/upload-a-file-in-a-google-chrome-extension
阅读xhr2-FormData.js源码,可知道
原生FormData.append方法只接受Blobs, Files or strings
但Uint8Array值或ArrayBuffer值(还有DataView)可转为Blobs
var blob=new Blob([arrayBuffer], { type: "application/octet-stream" });
● 特别注意通过构建blob对象上传到服务器时,上传数据里对文件名命名为blob(无后缀)
需要后台作考虑这种情况作兼容处理,如接受另一个表单元素值为上传的文件名。
或者像firefox里那样,手动构建requestBody
http://blog.cloudspokes.com/2013/01/guest-blog-constantly-learning-with.html
评论 (0)