在博客園里給圖片加水印(canvas + drag)


前言

想給自己的一些圖片加上水印,於是就搗騰了這么個東西。
此功能沒有考慮兼容性(太懶了),只在Chrome下測試通過,如果您在什么IE火狐下測試不通過就不要吐槽了。
因為應用了download屬性,所以IE什么的就不用指望了,如果您是火狐瀏覽器的話,自己改一下兼容性應該是沒問題的。
代碼什么的開了F12自己拿吧,沒有壓縮哦。(最后吐槽一下,本來代碼是貼進博客里面的,保存為草稿預覽的時候也可以,結果在發布后js代碼全被屏蔽了,最后只能寫到頁腳里了。所以獲取js代碼到頁腳那里獲取就好了)
當然你也可以訪問下面這個github地址獲取代碼: 代碼地址
另外為了弄進博客園,特意把代碼從ES2015改成了ES5,所以多多少少有點亂,不過必要的注釋都加上去了,這么辛苦,點個贊啊。
至於要改水印樣式什么的,控制台里更改這個變量的屬性即可。
var watermarkInfo = {
  fontSize: 18, // 像素值
  fontFamily: 'cursive',
  content: '',
  color: '#fffbf0'
};
 廢話就不多說了,直接上作品。
選擇背景圖后,設置水印文字,然后拖動水印文字到任意位置,最后點擊下載文件按鈕即可。

實現過程中的問題與解決方案

代碼什么的就不全部貼上來了,只是講一下其中遇到的一些問題與實現思路。

這些問題您可能已經大多了解了,不過為了兼顧所有人,所以還是會將一些比較簡單的技術點也講一下。

整個實現過程中遇到的問題如下

  • 獲取圖片
  • 將上傳文件轉換為圖片
  • 在圖片上加水印
  • 拖動文字加水印
  • 將最后修改的圖片下載下來

獲取圖片

獲取圖片實際上就是用到文件上傳控件,也就是

<input id="target_file" type="file"/>

然而原始的文件上傳控件比較丑,所以隱藏此控件,並加了一個新的按鈕在它前面

<a class="btn" id="btn_select_file" href="jacascript:void(0)">選擇背景圖</a>
<input id="target_file" type="file" style="display:none" />

而想實現點擊選擇背景圖按鈕去選擇文件,用以下代碼即可

// 按下選擇的背景圖
$('#btn_select_file').click(function () {
  $('#target_file').click();
});

選擇文件后,文件上傳控件會觸發change事件,此時可以拿到文件。

$('#target_file').change(function (event) {
    var imgFile = event.target.files[0];
    ......
});

將文件轉換為圖片

文件轉換為圖片實際上首先需要讀取文件,這里需要用到FileReader。

function setImgIntoCanvas(imgFile) {
  var reader = new FileReader();

  reader.onloadend = function (e) {
    var dataURL = e.target.result;
    img.onload = function (event) {
      var ctx = document.getElementById('target_canvas').getContext('2d');
      //將canvas大小設置為和圖片一樣大
      setCanvasSize(event.target.naturalWidth, event.target.naturalHeight);
      ctx.drawImage(img, 0, 0);
      setCanvasImgToDownloadLink();
    };
    img.src = dataURL;
  };
   reader.readAsDataURL(imgFile);
   resetWatermark();
};

 

以上為核心代碼,通過 FileReaderreadAsDataURL函數讀取文件可以獲得Base64格式的圖片數據,將圖片數據賦值給一個Image對象。

在圖片上加水印

看了上面的代碼,里面就有一個步驟是將圖片渲染進canvas,實際上核心功能就是用canvas來給圖片加水印。
操作思路就是先將圖片用 drawImage渲染進canvas,再在指定的位置用 fillText渲染文字即可,並將最后的canvas用
toDataURL
轉化為圖片數據即可。
具體的用法可以參考我的代碼,然后查一下canvas的API即可。
這種在新手看來很難的東西說穿了其實很簡單,這里就不講了。
 
但是接下來就麻煩了,如果是白色水印,圖片上加水印的地方肯定不能和圖片色差太小,要不然很難發現。
所以針對不同的圖片,水印的位置肯定需要可調整。
最開始的方案是給定兩個輸入框,然后輸入位置,接着渲染水印到文本上。
但是這個方案首先就面臨一個易用性的問題,我怎么獲得具體的位置呢,只能一個一個去試,並不是每個用戶都會用截圖軟件去找位置。
所以這里采用拖動文字的方案。

拖動文字加水印

canvas雖然也能捕獲事件,獲取鼠標位置,並實現拖動文字效果,但是實現起來太麻煩。

所以這里采用更簡單的方案。

當我們設置水印時,直接將文字渲染到canvas上,然后在文字上方安放一個顏色透明的內容為水印文字的span元素。

然后我們在這個span元素上加drag事件。

HTML5拖動功能網上一大堆,這里就不講了。

主要講一下實現思路:

在開始拖動時,重新用圖片渲染canvas,使得之前渲染的文字消失。

在結束拖動時,獲取到具體的位置,再重新將文字渲染進canvas。

這里說起來簡單,其實還是有一些細節,包括css和js的配合,比如文字拖動到邊界時的處理方式,又比如文字拖動到邊界出現換行的情況。

還有一些其他的小坑點,需要你自己看代碼去體會了。

這里貼出部分代碼:

     // 綁定移動水印相關事件
     var bindEvent4DragWatermark = function () {
          $('#watermark').on('dragstart', function (e) {
            var ctx = document.getElementById('target_canvas').getContext('2d');
            ctx.clearRect(0, 0, $('#target_canvas').width(), $('#target_canvas').height());
            ctx.drawImage(img, 0, 0);
            // 顯示可拖拽水印
            $(this).addClass('selected');
            watermarkInfo.offsetX = e.originalEvent.offsetX + canvasInfo.left;
            watermarkInfo.offsetY = e.originalEvent.offsetY + canvasInfo.top;
          });
          // 讓水印跟着鼠標移動
          $('#watermark').on('drag', function (e) {
            var x = e.originalEvent.pageX;
            var y = e.originalEvent.pageY;
            if (x === 0 && y === 0) {
              return;
            }
            x -= watermarkInfo.offsetX;
            y -= watermarkInfo.offsetY;

            $('#watermark').css('left', x).css('top', y);
          });
          $('#watermark').on('dragend', function (e) {
            // 調整位置,使水印無法超出canvas邊界
            var x = e.originalEvent.pageX - watermarkInfo.offsetX;
            var y = e.originalEvent.pageY - watermarkInfo.offsetY;
            if (x < 0) {
              x = 0;
            }
            if (y < 0) {
              y = 0;
            }

            var maxX = canvasInfo.width - watermarkInfo.width;
            var maxY = canvasInfo.height - watermarkInfo.height;
            if (x > maxX) {
              x = maxX;
            }
            if (y > maxY) {
              y = maxY;
            }
            $('#watermark').css('left', x).css('top', y);
            // 拖拽完水印,文本隱藏
            $('#watermark').removeClass('selected');
            setTextIntoCanvas();
          });
          // 讓鼠標不顯示禁用樣式
          $('#canvas-container').on('dragover', function (e) {
            e.preventDefault();
          });
        }

將最后修改的圖片下載下來

之前我們已經講到了用canvas的toDataURL函數獲取最后的圖片數據,然后關於下載就需要用到一個HTML5的download屬性。

<a class="btn" id="download_file" href="#" download="水印圖片">下載合成圖片</a>

接下來是設置圖片數據的代碼

/**
 * 設置canvas圖像到下載鏈接上
 */
function setCanvasImgToDownloadLink() {
  var imgData = document.getElementById('target_canvas').toDataURL();
  $('#download_file').attr('href', imgData);
};

將功能寫進博客里

至於這部分首先要申請JS權限。

其次如果觀察仔細,還可以在我的代碼中看到下列代碼

// 此處通過這種方式將html插入,是因為博客園自動屏蔽了canvas標簽和download屬性
var initHtmlConstruct = function () {
  $('#canvas-container').text('').append('<canvas id="target_canvas" width="100" height="100">瀏覽器不支持此功能,請升級</canvas><span draggable="true" id="watermark"></span>')
  $('#toolbar').append('<a class="btn" id="download_file" href="#" download="水印圖片">下載合成圖片</a>');
}

至於原因注釋里也寫了,是因為博客園的編輯器屏蔽了canvas標簽和download屬性。

總結

總的來說,這其實是一個很小的功能,但是要把它做得好用一點,涉及到的知識點並不少,也不並不僅僅我提到的這一點(比如canvas的透明度樣式並不是用圖片哦,而是用css樣式,還是從《css揭秘》那本書上學到的)。

當然這個東西或多或少還是有那么一些瑕疵,也存在一些兼容性上的問題,不過對我而言夠用就好。

也希望上面介紹的一些東西對您也有收獲。


免責聲明!

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



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