近来需要完成一个在文本编辑框中直接粘贴截图的功能。但是发现现有的CKEditor并不能做到。但是发现知乎,还有CSDN本身,都能直接在编辑框中直接Ctrl+V将图片粘贴上。所以,有实现的地方,就有相应的技术。后面再回去看新浪微博,支持得刚好,Ctrl+V还会弹个框出来。这次结合了好多网友的回答和文章,结合之后完成了自己想要的功能。
首先是在知乎上受到Clipboard的启发。知乎回答问题编辑框用 Ctrl+V 粘贴图片是如何实现的?
发现了大体的思路。参照其中的一个回答,修改之后再写一个demo。是简单的textarea实现粘贴截图还有html的功能。
test chrome paste image
test image paste in browser
copy the following img, then paste it into the area below
这边的原理好多东西自己查找大量资料,发现主要是webapi这块很薄弱。
这里通过ajax请求。不过首先,我们要先了解一下。FormData是什么?
现在blog为getAsFile方法返回,为File对象。
FormData介绍:
https://developer.mozilla.org/zh-CN/docs/Web/API/FormData
普通的Ajax请求代码,这是一篇博客里面写的,具体出处忘了开了太多东西了:
var createStandardXHR = function () {
try {
return new window.XMLHttpRequest();
} catch (e) {
return false;
}
};
var createActiveXHR = function () {
try {
return new window.ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
return false;
}
};
var xhr;
function createXHR() {
var temp = createStandardXHR() || createActiveXHR();
if (window.XDomainRequest === undefined) {
return temp;
} else {
return new XDomainRequest();
}
}
function uploadImg(obj) {
xhr = createXHR();
var fd = new FormData();
fd.append("image", obj, "test.png");
xhr.open('POST', 'xx.action', true);
xhr.send(fd);
}
再来看看FormData的方法介绍:
append() 给当前FormData对象添加一个键/值对.
void append(DOMString name, Blob value, optional DOMString filename);
void append(DOMString name, DOMString value);
参数值
name 字段名称.
value 字段值.可以是,或者一个字符串,如果全都不是,则该值会被自动转换成字符串.
filename
(可选) 指定文件的文件名,当value参数被指定为一个Blob对象或者一个File对象时,该文件名会被发送到服务器上,对于Blob对象来说,这个值默认为"blob"。
上述普通的ajax方法比较复杂,引入jQuery的js文件,使用封装方法就简单很多了。
var fd = new FormData();
fd.append("image", blob,"a.png");
$.ajax({
type: 'POST',
url: 'xx.action',
data: fd,
processData: false,
contentType: false
})
public String upload() throws Exception {
ActionContext context=ActionContext.getContext();
Map parameterMap=context.getParameters();
Set s = parameterMap.keySet();
for (Object object : s) {
System.out.println(object);
System.out.println(parameterMap.get(object));
}
String filename =((String[])parameterMap.get("imageFileName"))[0] ;
System.out.println(((String[]) parameterMap.get("imageContentType"))[0]);
System.out.println(filename);
File f = ((File[]) parameterMap.get("image"))[0];
BufferedImage image = ImageIO.read(f);
ImageIO.write(image, "png", new File("e:\\test.png"));
return "ok";
}
输出
image
[Ljava.io.File;@3b382278
imageContentType
[Ljava.lang.String;@625f12a7
imageFileName
[Ljava.lang.String;@4fc1c465
image/png
a.png
这里有东西是需要注意的,如果File f = ((File) parameterMap.get("image")); 这样的强制转换是异常的。
原因是类型为Ljava.io.File,而不是java.io.File。
区别是什么呢?
[Ljava.io.File;是 File[].class的名字,java.io.File表示的File.class。所以需要类型转换是将其转换File数组对象。
到CKEditor添加该功能的时候,我就被卡死了一次。
CKEditor相当于一个内嵌iframe,然后上面的document.getElementById('editable').innerHTML这种方式获取修改内容就做不到了。
多亏看了这位仁兄的做法:Ckeditor and ckfinder 配置实现截图上传图片到远程服务器
然后成功地让CKEditor能够顺利的粘贴到截图,后续发现同事用的CKEditor,只要配置一下东西就有这个功能了。囧。
不过刚开始整个原理没有弄清楚。现在终于把这些FileReader等对象的方法给理顺了。
//instances是保存editor实例的引用
var editor = CKEDITOR.instances["Editor"];
//如果存在,则销毁。
if (editor2) {editor2.destroy(true)};
//用 CKEditor实例替换