搗鼓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. 我的性子是不求甚解,能拼湊就拼湊,能猜就猜。。。。反正搗鼓出來就行了,什么代碼優化之類的與我無緣。 只是我用了好多關鍵字搜索,但是搜出來的解決方案都有問題,所以我才寫了這篇文章,希望也能幫助看文章的你節省寶貴的時間。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM