給上傳的圖片添加水印

本文首發(fā)于公眾號(hào):水很大
做這個(gè)小Demo是因?yàn)榻?jīng)城缮В看見(jiàn)社交平臺(tái)的用戶上傳的圖片是自動(dòng)添加了水印的。我對(duì)這個(gè)自動(dòng)添加水印的功能比較好奇格二,想探究一下究竟是怎么實(shí)現(xiàn)這個(gè)功能的劈彪。
閱讀本文前您需要對(duì)canvas有一定的了解。

01 HTML結(jié)構(gòu)

因?yàn)槭且粋€(gè)簡(jiǎn)單的Demo,所以HTML只保留最核心的部分顶猜,未添加CSS沧奴。

  <main>
    <div>
      <form id="upload-img">
        <input type="file" value="上傳" id="select-img" name="select-img"  style="display: none" >
        <label for="select-img" class="select-label-img">選擇圖片</label>
       </form>
    <canvas id="imageCanvas" ></canvas>
    </div>
  </main>
</body>

canvas標(biāo)簽是用來(lái)展示添加了文字以后的照片。這里也可以將canvas標(biāo)簽轉(zhuǎn)換成img標(biāo)簽长窄。

02 分析

(1)input標(biāo)簽選擇文件后怎樣才能知道選擇已經(jīng)結(jié)束?
選擇文件的過(guò)程是:點(diǎn)擊按鈕滔吠,通過(guò)彈出的文件選擇器選擇文件,再點(diǎn)擊文件選擇器的確認(rèn)或者取消按鈕挠日。當(dāng)點(diǎn)擊確認(rèn)按鈕已經(jīng)代表文件選擇完畢疮绷,需要進(jìn)行下一步的操作。但是問(wèn)題來(lái)了:怎樣才能知道用戶點(diǎn)擊了確認(rèn)按鈕肆资?目前我做不到對(duì)這個(gè)按鈕的監(jiān)聽(tīng),所以考慮其他的方法矗愧。只能從input標(biāo)簽著手考慮:通過(guò)查閱資料得知input標(biāo)簽有一個(gè)change事件,只要通過(guò)input標(biāo)簽得到的數(shù)據(jù)發(fā)生變化就會(huì)觸發(fā)change事件,所以現(xiàn)在就從change事件入手:

document.getElementById('upload-img').querySelector('input').addEventListener('change',(e)=>{
});

到這里就做到了對(duì)用戶進(jìn)行的操作進(jìn)行監(jiān)聽(tīng)灶芝。
(2)怎樣獲取上傳的文件郑原?
input標(biāo)簽有一個(gè)files屬性,通過(guò)這個(gè)屬性可以得到上傳文件的數(shù)據(jù)唉韭。

this.imgFrom = document.getElementById("select-img");
this.files = this.imgFrom.files[0];

為什么是files[0]?
這是因?yàn)橹贿x擇了一個(gè)文件。this.imgFrom.files是一個(gè)FileList對(duì)象犯犁,因?yàn)樽鲞@個(gè)Demo的時(shí)候只上傳了一個(gè)文件,所以是files[0]属愤。
(3)驗(yàn)證文件類型
因?yàn)樾枰幚淼氖菆D片格式的文件,所以像pdf、mp3等格式的文件是不能被上傳的酸役,怎么辦住诸?
this.imgFrom.files[0]可以得到文件的type屬性,通過(guò)這個(gè)type屬性即可判斷。

let typeReg = new RegExp('png|jpg|jpeg')
if(typeReg.test(type) == false) {
   //if成立則不是圖片
}

(4)怎樣讀取文件?
到目前為止只是通過(guò)input標(biāo)簽得到了文件,但是并沒(méi)有拿到文件的數(shù)據(jù)涣澡。所以現(xiàn)在要做的就是怎樣拿到上傳文件的數(shù)據(jù)贱呐。

let reader = new FileReader();
reader.readAsDataURL(this.files);

簡(jiǎn)單來(lái)講FileReader對(duì)象用于將文件轉(zhuǎn)換為二進(jìn)制字符串,而readAsDataURL則會(huì)讀取指定的Blob或者File對(duì)象(解釋來(lái)源于MDN)。當(dāng)讀取完成以后會(huì)有一個(gè)onload事件被觸發(fā):

reader.onload = function(e){
}

函數(shù)表達(dá)式里面的e是一個(gè)ProgressEvent入桂。對(duì)ProgressEvent只需知道里面存放著上傳圖片的地址奄薇。
(5)圖片地址有了,怎樣將上傳的圖片構(gòu)造出來(lái)?

let img = new Image();
reader.onload = function(e){
  img.src = e.target.result;
}

new Image()相當(dāng)于

document.createElement('img')

(6)給圖片添加水印
通常將圖片放在canvas上面可能是這樣操作的:

let ctx=canvasId.getContext("2d");
ctx.drawImage(img,0,0)

但是現(xiàn)在需要將文字放到圖片上面。所以應(yīng)該先按照上面的方法在畫布上繪制圖片然后再繪制文字(這個(gè)順序是不能顛倒的)抗愁。
怎樣繪制文字?

ctx.font = "40px xxx";//xxx為字體,若不設(shè)置像素大小可能無(wú)效
ctx.fillText("Hello world", 0, 0);

執(zhí)行上面代碼可能在畫布中看不見(jiàn)文字,之所以這樣是因?yàn)樵诶L制文本時(shí)canvas有一個(gè)繪制當(dāng)前文本的基線屬性textBaseline馁蒂。textBaseline默認(rèn)值為alphabetic。繪制的水印圖片如:

Hello world
圖片

這就導(dǎo)致在圖片上顯示不了文字蜘腌。
為了解決這個(gè)問(wèn)題就要顯示的設(shè)置textBaseline的值沫屡。當(dāng)文字處于左上、右上時(shí)需將textBaseline設(shè)置為top撮珠。當(dāng)文字處于左下沮脖、右下時(shí)需將textBaseline設(shè)置為bottom。textBaseline總共可以有六個(gè)值可以選擇芯急,按照項(xiàng)目的需要選擇即可倘潜。
(7)水印圖片地址獲取

canvasId.toDataURL("image/jpeg", 1.0);

03 代碼

完整代碼請(qǐng)?jiān)L問(wèn)公眾號(hào):水很大

本文的主要目的是為了記錄水印功能的實(shí)現(xiàn),故有些細(xì)節(jié)問(wèn)題就沒(méi)有再記錄。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載志于,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者涮因。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市伺绽,隨后出現(xiàn)的幾起案子养泡,更是在濱河造成了極大的恐慌,老刑警劉巖奈应,帶你破解...
    沈念sama閱讀 223,207評(píng)論 6 521
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澜掩,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡杖挣,警方通過(guò)查閱死者的電腦和手機(jī)肩榕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,455評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惩妇,“玉大人株汉,你說(shuō)我怎么就攤上這事筐乳。” “怎么了乔妈?”我有些...
    開(kāi)封第一講書人閱讀 170,031評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵蝙云,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我路召,道長(zhǎng)勃刨,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 60,334評(píng)論 1 300
  • 正文 為了忘掉前任股淡,我火速辦了婚禮身隐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘唯灵。我一直安慰自己抡医,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,322評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布早敬。 她就那樣靜靜地躺著忌傻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪搞监。 梳的紋絲不亂的頭發(fā)上水孩,一...
    開(kāi)封第一講書人閱讀 52,895評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音琐驴,去河邊找鬼俘种。 笑死,一個(gè)胖子當(dāng)著我的面吹牛绝淡,可吹牛的內(nèi)容都是我干的宙刘。 我是一名探鬼主播,決...
    沈念sama閱讀 41,300評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼牢酵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼悬包!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起馍乙,我...
    開(kāi)封第一講書人閱讀 40,264評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤布近,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后丝格,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體撑瞧,經(jīng)...
    沈念sama閱讀 46,784評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,870評(píng)論 3 343
  • 正文 我和宋清朗相戀三年显蝌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了预伺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,989評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酬诀,靈堂內(nèi)的尸體忽然破棺而出脏嚷,到底是詐尸還是另有隱情,我是刑警寧澤料滥,帶...
    沈念sama閱讀 36,649評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站艾船,受9級(jí)特大地震影響葵腹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屿岂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,331評(píng)論 3 336
  • 文/蒙蒙 一践宴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧爷怀,春花似錦阻肩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,814評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至吁朦,卻和暖如春柒室,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逗宜。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,940評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工雄右, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纺讲。 一個(gè)月前我還...
    沈念sama閱讀 49,452評(píng)論 3 379
  • 正文 我出身青樓擂仍,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親熬甚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逢渔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,995評(píng)論 2 361