Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

本地图片自动上传浏览器扩展开发工作笔记-Chrome版(一) #16

Open
abeet opened this issue Jun 7, 2016 · 0 comments

Comments

@abeet
Copy link
Owner

abeet commented Jun 7, 2016

●先要确认两个前提
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();
});

●读取本地文件
window.webkitRequestFileSystem(window.TEMPORARY, 1024 * 1024 * 2 /* ~2MB */ , function(fs) {
console.log(fs.root.getFile)//可以跑到这儿
fs.root.getFile('F:\Temp\image002.gif',{},function(fileEntry){
console.log('F:\Temp\image002.gif',fileEntry);//总是读取不到这个文件
})
})


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:\Temp\msohtml1\01\clip_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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant