• 捣鼓TinyMCE粘贴图片并上传+Flask后台


    好久没有编程了,最近需要完成一个小功能,为了方便,需要粘贴图片后上传到后台。前台编辑器用tinymce(N年前用过,我也就知道这个编辑器而已。这次使用下来感觉文档更丰富了),后台我用的Flask。昨天从下午4点开始一直捣鼓到半夜2点,终于完成了,这里大致记录一下遇到的问题和解决的办法。

    1.  使用的tinymce版本是4.7.4,稍微熟悉了一下,advlist 插件不能用。 粘贴图片主要用的是自带的paste插件。

     tinymce.init({
            selector:'#mycontent',
            menubar:false,
            plugins: [
                'code paste',
    		],
            toolbar:'code',
            height:400,
            paste_data_images: true
    });
    

    2. 上面的代码已经能成功粘贴图片,并且显示在编辑框里面了。我查看了源代码,图片的src是这样的

    <img src="blob:http://127.0.0.1:5000/e8b7743b-6637-45f5-8473-9cf5271cc841">
    

    3. 我懵逼了,这是什么玩意儿,但是似乎听说过Blob这个东西。我又想了下我的思路,我是要把这个图像上传到后台,然后把后台的地址返回给客户端,然后把这个src给替换掉。 因此我的问题就是把这个图片读出来,然后上传。一开始我网上找到不少解决方法,可以把blob读出来,主要是用了HTML5的canvas 对象。用context 画图,然后输出DataURL,转化为Base64。 这一段耗费了我大量的时间。 下面的代码是有问题的,贴出来仅仅是为了表达完整的过程。

    var Img = new Image();
    Img.src=url;  
    width = Img.width; // 实际上是拿不到长宽的。
    height = Img.height; var canvas = document.createElement("canvas"); canvas.getContext("2d").drawImage(Img,0,0, width, height); dataURL=canvas.toDataURL('image/jpeg');

     大致的核心代码如上。rul: 就是上面 blob:http://.... 这一段。关键在于drawImage这个函数上,我为了看看这个画布上画出来的图像是否跟我粘贴的图像是一样的,因此在页面下部让这个画布显示出来,我遇到了几个问题

       1. 第一次粘贴,画布无法显示图像,第二次粘贴后,画布会一次显示2个图像,而且错误 -__-!

       2. 画布大小和图像大小不匹配。 打印了width和height 之后发现都是0。原来blob图像无法获得长宽。

       3. 我粘贴的图像比较大,1800×3600以上,Base64太长了,传到后台,保存成图像之后,数据丢失,出来的是一片白色。

      因此这条路基本上是走不通了。

    4. 解决方法:换成纯二进制数据进行操作,不再转换。

    直接看下面的代码吧,写的很粗,因为我不是很懂javascript。基本上全是复制粘贴过来的。

    <script>
        
        globalcounter = 1;
       
        tinymce.init({
            selector:'#mycontent',
            menubar:false,
            plugins: [
                'code paste',
    			],
            toolbar:'code',
            height:400,
            paste_data_images: true,
            paste_preprocess: function(plugin, args) {                  
                args.content = args.content.replace("<img", "<img id="pasted_image_" + parseInt(globalcounter) + """);
                console.log(args.content)
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = function(){
                    if (this.readyState == 4 && this.status == 200){
                  
                        upload(this.response);
                    }
                };
    
                xhr.open('GET', args.content.split('"')[3]);
                xhr.responseType = 'blob';
                xhr.send(); 
    
                function upload(BlobFile){
                    var x = new XMLHttpRequest();
                    x.onreadystatechange = function(){
                        if( this.readyState == 4 && this.status == 200 ){
                            data = this.responseText;
                            console.log('response data: ' + data);
                            id = parseInt(globalcounter++);
    
                            // function setimg(id, data){
                            //     if( document.getElementById("pasted_image_" + id)  == null){
                            //         setTimeout( setimg , 5000);                                
                            //     }else{
                            //         document.getElementById("pasted_image_" + id).setAttribute("src", data);      
                            //     }
                            // }
                            document.getElementById("mycontent_ifr").contentWindow.document.getElementById("pasted_image_" + id).setAttribute("src", data);
                        }
                    };
                    x.open('POST', '/pasteimg/');   
                    x.send(BlobFile);
                }
    
            }
            
        });
    </script>  

    这里是后台的python代码,框架用的是Flask

    @app.route('/pasteimg/', methods=['GET','POST'])
    def paste_upload():
        if request.method == 'POST':
            imgdata = request.get_data()
            file = open('test.png', 'wb')
            file.write(imgdata)
            file.close()
    
        imgsrc = "/static/img/60_1.png"
        return Response( imgsrc,  mimetype='application/text')
    

      

    上面的代码有几个我遇到的问题,解决了。也有一些问题,我只是绕过了,但是没有真正解决;:

    1. 用XMLHttpRequest 可以直接把img 读出来成为一段二进制数据 -- blob。而且没有大小限制,我贴的图片有时候size超过7位数。。也能够顺利上传到后台,相比之下,我觉得比Base64一串常常的字符串好多了。

    2. tinymce 的paste_postprocess 中无法给插入对象设置id,这样我之后就没有办法获取图片了,因此,我只能在preprocess中设置了id,由于要插入多张图片,因此我用一个全局的计数器来递增id号。以后如果有多个textarea,那么还要再想办法。

    3. jquery 的ajax方法不能传二进制,因此用XMLHttpRequest.

    4. XMLHttpRequest 不能设置同步操作,设置了之后contenttype就不能设置blob,否则出错。我没时间去处理了,就用异步了。

    5. 由于服务器端我命名规则还没有订好,因此我只是返回固定的一个图片,这样只要在前端能够顺利显示,说明整个路子都走通了。

    6. 获取图片对象费了老大劲,原来tinymce自己是一个iframe,因此要先找到iframe,然后再找到里面的图片。 在chrome里面我直接用getElementById(”图片的id“)却始终找不到,奇怪。 后来我到Firefox中就能找到了。

    7. 当服务器端把图像返回回来时,如果paste事件还没有完成,那么DOM对象还没有生成的话,图片对象是找不到的。虽然这种可能性很小,所以我设置了timeout,找不到就一直给我找,直到找到位置。当然也可以用一个wait 的gif,类似 博客园这么干。

    8. 我的性子是不求甚解,能拼凑就拼凑,能猜就猜。。。。反正捣鼓出来就行了,什么代码优化之类的与我无缘。 只是我用了好多关键字搜索,但是搜出来的解决方案都有问题,所以我才写了这篇文章,希望也能帮助看文章的你节省宝贵的时间。

  • 相关阅读:
    基础之前ORM的一个框架(在OA系统上已经应用)
    自己创建的一个ORM框架
    spring cloud+docker 简单说一说
    有价值的数据
    Axis2Service客户端访问通用类集合List自定义类型
    java.io.IOException: Cleartext HTTP traffic to e.hiphotos.baidu.com not permitted
    Android Studio 3.x 自动生成多渠道包
    单例模式
    Linux(ubuntu 18.0.4) Java环境安装,环境变量配置
    ImageLoader常用方法注释
  • 原文地址:https://www.cnblogs.com/moogle/p/8079610.html
Copyright © 2020-2023  润新知