HEXO 圖片腳本
2021-09-12 # 腳本應用 # 自製腳本 # Hexo腳本

這個網頁跟一個旅遊網頁都是建基於 HEXO 架構。在前一個版本是使用 Jekyll. Jekyll 版本有專門插入圖片插件,然而HEXO 並沒有健全或相似的插件。於是,一個從零開始的腳本開始開發。近期接近完成開發並發佈在 Github 。這個 post 主要展示效果及使用方法。

前情提要

Github Link: https://github.com/siraisisatoru/hexo-sharp-script

這個 project 是一個修改版基於一個相關的圖片水印 library 。在修改現成 library 時,參照了Jykell picture tag
這個 project 原先是作為這個網頁的建設作用,所以並未發佈至 node 平台及製作成 node 模組。同時,作為一個圖片處理插件,每個人的需求都不同,最終會陷入一個不可能完結的黑洞。所以,我發布我的改編版本,希望可以作為一個起點給任何需要的人,方便繼續改編成自己需要的版本。

這個腳本使用一個功能強大的 node js library Sharp 作為圖片處理工具。理論上,原版圖片水印 library 支持gif. 然而在個人的使用上,暫時不需要。所以並未實現在現版本中。(原版未修改 file 依然保留作為參考。)

簡介

你作為一個初學者或者 HEXO 的老手,你可能需要一個簡單的 HEXO tag 插件或者一個簡單的方法讓你插入圖片。當你嘗試官方提供的方法,你會發現他使用並產生一個原圖的複製品。想像一下,當使用大量圖片時,整個 project 大小將會劇增。這個腳本提供了幾個方法去壓縮,加水印,放大縮小跟裁減圖片。而處理過後的圖片名將加上一段九位基於設置的 MD5 碼,並緩存在一個另外的 image 檔案夾。這個腳本會在處理完圖片後,會產生 WEBP 跟 JPG 檔案。圖片的壓縮率可以在設置文件 config.js 中修改。

使用前

  1. 使用 node js 安裝必須要的模組:
$ npm install fs-extra gifwrap jimp js-md5 sharp svg2png ext-to-svg
  1. 把 github 中的所有檔案拷貝到 /scripts folder
.
├── ...
├── scripts
│   ├── img_lib
│   │   ├── constants
│   │   │   └── cachePath.js
│   │   ├── render
│   │   │   ├── dynamic.js
│   │   │   └── static.js
│   │   ├── utils
│   │   │   ├── cache.js
│   │   │   ├── dynGetWatermarkImageBufferamic.js
│   │   │   ├── index.js
│   │   │   ├── isEqual.js
│   │   │   ├── text2svg.js
│   │   │   └── trueTo256.js
│   │   ├── config.js
│   │   └── index.js
└── ...
  1. 請將你的水印 Watermark.svg file 拷貝到 source/images folder 或者 themes/YOUR_THEME/source/images folder 。要讓這個腳本運行,這個檔案必需存在。這個水印檔案可以是任何圖片,任何檔案名及存在於自定義地址。請修改 config.js file。

在 markdown 中使用

使用範本
[original] [fancybox] [nwatermk] [ncompress] link <--refmaxwidth[co-responding ratio]> <--watermkwidth[co-responding ratio]> <--crop[x]x[y]-[width]x[height]> <--mo[x]x[y]-[width]x[height]> <--ratio[width]:[height]> <--resize[width]x[height]>

  • 前綴 (optional)

    • original
      這個選項會覆蓋所有其他選項。輸出圖片將不進行壓縮處理。

      {% webp original /post_image/abc.JPG %}
    • fancybox
      在一些 HEXO 主題中, fancybox 功能有被使用。這個腳本在一般情況下將返回一段 html 代碼包括一個 nofancybox class。使用這個選項可以排除這個 class 的添加預設。在 #筆記 一欄中將提及如何利用 nofancybox class 剔除 fancybox 功能。

      {% webp fancybox /post_image/abc.JPG %}
    • nwatermk
      當不需要加水印時,可以選擇這個選項。

      {% webp nwatermk /post_image/abc.JPG %}
    • ncompress
      有時候,當圖片縮放時,成果圖可能被像素化,或能見度降低。若再將其二次壓縮,可能導致讀者無法識別,或者造成閱讀困難。選擇此項可以括免最後的二次壓縮。

      {% webp ncompress /post_image/abc.JPG %}
  • link (compulsory)
    這個選項是必須要存在於輸入選項中。這個選項作為主要得分界,將可選型選項與圖片修改選項分開。(由於在腳本設計中,將所有固定形式的前綴(例:–refmaxwidth 等)作為判定,因此所有選項無需要按順序,但以可閱讀性而言,建議跟隨範本。)由於同一個選項壓縮的圖片可能會重用無數次,但來源於同一個圖片源,因此此腳本允許同一張圖片來源重用。同時,也因為輸出檔案時,名稱加上 MD5 碼,可以確保獨立性,同時圖片將只壓縮生產一次。原圖片必須放在 source 檔案夾以內。例如此項可以以 /post_image/abc/def.JPG 來指向圖片 def.JPG

.
├── ...
├── source
│   ├── post_image
│   │   ├── abc
│   │   │   └── def.JPG
│   │   └── ghi.PNG
└── ...
  • 後綴 (optional)
    • --refmaxwidth[co-responding ratio]
      這個設置將輔助加水印的功能。在個人的使用設置中,網頁總寬為 1000px 。因此,水印將自動根據圖片像素比與網頁寬的比例而更改水印比例從而令水印在視覺上一致。該項可以在 config.js 中永久修改。若網頁有部分寬度小於整體網頁寬度,可以添加此項為圖片的水印進行手動縮放。

      {% webp /post_image/abc.JPG --refmaxwidth1000 %}
    • --watermkwidth[co-responding ratio]
      這個設置將輔助加水印的功能。在個人的使用設置中,水印寬 200px。假設想要更改水印與圖片右下邊長距離,可以利用此項。若水印長度非 200px 並想永久更改,可以更改 config.js file。

      {% webp /post_image/abc.JPG --watermkwidth200 %}
    • --crop[x]x[y]-[width]x[height]
      想像一下,你想要裁減圖片中的一部分。

      {% webp /post_image/abc.JPG --crop200x200-50x50 %}

      例子的成果圖片將從原圖的座標 (200,200) 開始裁下長寬各 50px 。

    • --mo[x]x[y]-[width]x[height]
      這個設置可以為圖片的一部分加上模糊方塊。考慮到多次圖片模糊會導致重複模糊部分疊加,不考慮容許多方塊模糊。(他朝一日有更優化的方法會更新。)

      {% webp /post_image/abc.JPG --mo200x200-50x50 %}
    • --ratio[width]:[height]
      使用這個設置可以快速簡單睇將圖片裁剪至特定圖片比例。

      {% webp /post_image/abc.JPG --ratio1:1 %}

      給予特定比例,圖片將被裁剪至特定比例。由於原圖未必已經按比例,圖片將裁剪圖片正中心的最大範圍。

    • --resize[width]x[height]
      使用這個設置可以重新放大縮小到指定長與寬。

      {% webp /post_image/abc.JPG --resize300:200 %}
    • --desc|[text]|
      使用這個設置可以為圖片底端加上圖片說明。

      {% webp /post_image/abc.JPG --desc|This is a long long description for my testing image. However, I think this is not long enough so I extended it a little bit lonnnnnnnnnnnnnnnger.夾雜着繁體中文。日本語もある。she's so damn pretty! he's going to sleep.| %}

      備註:基於 HEXO tag 的機制限制,英語雙引號及引號組會導致不顯示或引發錯誤。舉例:

      {% webp /post_image/abc.JPG --desc|"this is" 'wow'| %}

      請參照 #筆記 一欄如何顯示圖片說明。

選項的優先級

這個腳本有千萬種的使用變化,而當中有一些優先級是基礎設計。

  • original 選項將有最高級的優先權。該項將直接輸出未經處理及壓縮的圖片數據。僅僅會更改輸出圖片格式與加上 MD5 碼的輸出檔案名稱。
  • crop 將覆蓋 ratio 選項。

筆記

  • 圖片將被處理當且僅當有 webp tag 使用在 .md file 或者 webp_helper tag 使用在 .ejs file 。這個設計與其他目前大部分的 HEXO plugin 不同。
  • 經過處理的圖片將儲存在 project 的根資料夾中的 image folder 內。
  • 個人使用的主題是 orange theme。而在這個主題中 fancybox 功能是靠使用 Jquery 添加一個含有 data-fancybox='gallery' 及對應的圖片 href 的上級 a 標籤。當掃描過各個圖片源時,加上一句 if ($(this).hasClass("nofancybox")) {return;} 就可以剔除添加 a 標籤。
  • 在建立 a tag 的時候插入以下代碼:
if ($(this).attr("data-caption")){
    $(element).attr("data-caption", $(this).attr("data-caption"));
    $(this).removeAttr("data-caption")
}

其中 element 是新建立的 a tag 而 this 是當前經過濾的圖片 img tag 有待處理。

在 ejs 範本中使用

這將會與在 markdown 中使用相同。

在 markdown 中:

{% webp /post_image/abc.JPG --resize300:200 %}

在 ejs template 中:

<%- webp_helper /post_image/abc.JPG --resize300:200 %>

額外的方法為圖片加入圖片說明:在個別情況下,你會希望將圖片資訊跟說明放在一個 data 檔案中,方便在範本或 page 中使用。這時,圖片說明與圖片資訊放在同一行便會顯得冗長。可參考下列例子,將圖片資訊與說明分開,並在 template 檔案中將兩者連接:假設你有一個 data 檔案名為 abcData.yml 並放在 source/_data 檔案夾中。而當中 data 檔案有以下資訊:

image:
- fancybox /abc/IMG_0001.JPG
- fancybox /abc/IMG_0002.JPG
caption:
- hello world
- testing caption

在 ejs template 中:

<%- webp_helper `${abcData.image[i]}` , `${abcData.caption[i]}` %>

在這裡假設你有與圖片數量相同的圖片說明。你可以自行添加除錯檢測。

使用權

原水印 library 使用 LGPL-3.0 License。本 project 將使用 MIT licence.

效果演示

ratio= 16:9, resize900x500, resize1000x500, resize1100x500

ratio= 2:1, ratio= 3:1, ratio= 1:3

resize300x200, 0, ratio1:1, ratio16:9

ratio6:9, ratio9:6, ratio1:1, resize400x200

fancybox-ratio9:6, nowatermark-ratio9:6, nowatermark-fancybox-ratio9:6, fancybox-nowatermark-ratio9:6

{% webp original /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 %}

{% webp fancybox original nwatermk /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 %}

{% webp fancybox nwatermk original /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 %}

{% webp /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 --refmaxwidth2000 %}

{% webp /post_image/1-TKO-walk-around/IMG_0643.JPG --refmaxwidth500 --ratio9:6 %}

{% webp /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 --refmaxwidth500 %}

{% webp /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 --crop0x400-60x60 --watermkwidth100 %}

{% webp ncompress /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 %}

{% webp /post_image/1-TKO-walk-around/IMG_0643.JPG --ratio9:6 %}

{% webp ncompress nwatermk /post_image/1-TKO-walk-around/IMG_0643.JPG --mo0x0-300x900 %}