Sincerely Thanks @wzhqwq
从不规则四边形到规则矩形,一开始我想通过拉伸+仿射变换实现,不过即使是最简单的梯形,得到的效果也不是很理想。
后来在网上发现可以通过四点透视变化解决。
透视变换原理图
OpenCV: Geometric Transformations of Images
官网上的例子,是从规则四边形到不规则,其实是一样的,我们需要的只是传8个点。
let src = cv.imread('canvasInput');
let dst = new cv.Mat();
let dsize = new cv.Size(src.rows, src.cols);
// (data32F[0], data32F[1]) is the first point
// (data32F[2], data32F[3]) is the sescond point
// (data32F[4], data32F[5]) is the third point
// (data32F[6], data32F[7]) is the fourth point
// 实际测试,只要源和目的的点次序保证是相对的,顺序是无所谓的
let srcTri = cv.matFromArray(4, 1, cv.CV_32FC2, [56, 65, 368, 52, 28, 387, 389, 390]);
let dstTri = cv.matFromArray(4, 1, cv.CV_32FC2, [0, 0, 300, 0, 0, 300, 300, 300]);
let M = cv.getPerspectiveTransform(srcTri, dstTri);
cv.warpPerspective(src, dst, M, dsize, cv.INTER_LINEAR, cv.BORDER_CONSTANT, new cv.Scalar());
cv.imshow('canvasOutput', dst); // 这个方法会改变我们Canvas的大小,用定义的dsize
src.delete(); dst.delete(); M.delete(); srcTri.delete(); dstTri.delete();
我们可以直接用用FileSaver库,支持从很多组件中下载,会触发浏览器的下载效果
<script src="https://cdn.bootcss.com/FileSaver.js/1.3.8/FileSaver.min.js"></script>
xxx.toBlob(function(blob) {
saveAs(blob, "name.png");
})
但是WebView不支持,我的想法是通过WebView调用JS函数,将图片转化成base64编码,然后返回到Android形成输出流,输出到相册。
实现的时候遇到的问题的返回值一直为null,没找到合适的方法。
String jsMethodName = "getBase64()"; //不需要参数的JS函数名
webView.evaluateJavascript("javascript:" + jsMethodName, new ValueCallback<String>() {
@Override
public void onReceiveValue(String response) { // 这里传入的参数就是JS函数的返回值
// System.out.println(response);
}
});
微信的做法,则是直接提示可以跳转到浏览器打开。
我发现即使按照网上的一些方法设置很多的WebView属性,也不能解决html文件在移动端布局混乱的问题,不过浏览器可以通过缩放解决,但是WebView却没有这个效果。后来在同学的帮助下,重新针对移动端做了布局,解决了显示的问题。
获取客户端允许Canvas的宽度和高度,图片的实际尺寸做比较,求出合适的伸缩比例。然后在绘制Canvas显示原图的时候,按比例绘制,不过这样有一个坏处是 显示在Canvas上的图片会变得的模糊。同学说通过Canvas的zoom属性来设置缩放,替代绘制Canvas时设置的width。
-
鼠标比我们的手触摸精确很多,所以我们不能完全按照触摸来算,而是判定为到四个点距离最近的一个点为我们的要拖动的点。值得注意的触摸事件还有多指。
-
mouseMove --> touchmove
-
拖动事件,有时候浏览器会有默认的响应,比如放回,下拉刷新之类的,所以我们需要禁止掉默认事件
e.preventDefault()
类似的在网上发现在做微信小程序的html5开发时,也会有这个问题,WebView不支持了,但是找到了可以通过重写一下WebClient的onShowFileChooser方法,并且在onActivityResult方法中获取到文件的Uri。
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) {
if (uploadMessage != null) {
uploadMessage.onReceiveValue(null);
uploadMessage = null;
}
uploadMessage = filePathCallback;
Intent intent = fileChooserParams.createIntent();
try {
startActivityForResult(intent, REQUEST_SELECT_FILE);
} catch (ActivityNotFoundException e) {
uploadMessage = null;
Toast.makeText(MainActivity.this.getApplicationContext(), "Cannot Open File Chooser", Toast.LENGTH_LONG).show();
return false;
}
return true;
}
}
从本地加载图片到html文件上,往往会造成跨域的问题,使用这个组件来输入还可以解决跨域的问题。或者另外一种的解决方案是通过WebView向JS通过base64传入图片参数,不过长度大小有限制,可以分段传入。
可以看OpenCV.js-demos 和 OpenCV.py-demos这两个项目中的readme.md文件