再見了,搬運黨們

1. 天下苦搬運黨久矣

對於我這樣經常需要寫點文章的技術自媒體來說,很經常早上我纔在公衆號首發了原創文章,中午就有人同步到了知乎、今日頭條等外部平臺,並且拿到了該篇文章在這些平臺的首發。

平臺的首發很重要,以微信的公衆號平臺來說,一篇文章能否在公衆號標原創,就是通過檢測是否在公衆號平臺上首發,如果公衆號的文章庫裏沒有搜索到與你文章相似度較高的文章,那麼你就可以標原創了。

爲了解決了首發的問題,我付費使用了 OpenWrite 這個平臺,每個月 20 塊錢的費用,一鍵就可以分發各大平臺,非常的省心~

首發固然重要,但有時候也沒那麼重要。

因爲有專門的培訓機構(這裏就不點名,避免給他們反向營銷)就是拿你的文章去給自己的帳號堆乾貨,吸引關注,他們纔不在乎原創不原創,只要文章能發佈就行了。

這種人在知乎這種沒有原創檢測機制的平臺,可以活得很好。

之前有一無良培訓機構在知乎上生產了10幾個號,批量搬運我以及一些朋友的原創文章。那時候,我每天都可以舉報好多。

漸漸地,我累了,自己寫了幾百篇的文章,如果一篇一篇去檢查,那我這一天基本啥事都做不了,違權成本實在太高了。

考慮到我的文章都有非常多的圖片,爲了讓這些人在白嫖我文章的同時,也能給我帶來點收益(當然人家是不可能付費的,但至少能給我的公衆號打打廣告也是非常奈斯的)。

於是我就想啊,是不是可以自己寫個工具,給自己的每張配圖上都加上自己的水印,看他們還盜不盜。。

2. 目前的圖牀管理工具

在開始講如何利用 Python 來實現我的需求之前 ,我有必要介紹下我的圖牀管理工具。

我在寫文章的時候,主要用到三款工具:

  • Typora :Markdown 文案的編輯
  • Snipaste:非常好用的截圖工具
  • PicGo:非常人性的圖牀管理工具

其中今天的要參與的主角是 PicGo

它對當下主流的圖牀平臺都提供了很好的支持

當我使用了 Snipaste 截圖後,再按住快捷鍵(⌘ ⇧ P),就可以立即將你的圖牀上傳至指定圖牀,並且將上傳後的鏈接以 markdown 的圖片格式複製到剪切板中,你可以直接粘貼使用。

3. 方案的設想

由於這一整工具,我已經使用了三年,各種操作都非常的熟悉,對他們我已經產生了極度的依賴,因此現在我想要實現自動加水印的功能,也一定是建立在這套工具的基礎上完成的。

Snipaste 和 PicGo 本身都不支持自定義水印,也不提供第三方插件的開發入口。

Snipaste 和 PicGo 之所以能夠在一起工作,是因爲有了剪切板這個橋樑,因此想要實現自己的需求,只能從剪切板上尋找突破口。

多餘的廢話就不多說了,我直接說下我的方案:

  1. 在 Snipaste 將圖像放入剪切板後
  2. 由我敲入自定義的熱鍵去觸發 Python 腳本去從剪切板中讀取圖像
  3. 然後使用 PIL 去給該圖像加水印,重新放入剪切板中
  4. 接着利用 Python 腳本去自動化觸發 PicGo 的快捷鍵
  5. PicGo 被激活後,就能將帶有水印的圖片上傳到圖牀

爲了讓你對這個方案,有一個直觀的理解,我特地畫了一張流程圖,其中虛線就是我得自己實現的功能。

4. 代碼完整解析

4.1 定義熱鍵並監聽鍵盤

在 Python 中有一個 pynput 庫,利用它可以來監聽系統的鍵盤。

在它的官方文檔中,很快找到了一個可以自定義熱鍵組合的方案。

from pynput import keyboard

def on_activate():
    print('Global hotkey activated!')

def for_canonical(f):
    return lambda k: f(l.canonical(k))

hotkey = keyboard.HotKey(
    keyboard.HotKey.parse('<ctrl>+<alt>+h'),
    on_activate)
with keyboard.Listener(
        on_press=for_canonical(hotkey.press),
        on_release=for_canonical(hotkey.release)) as l:
    l.join()

但是很遺憾的是,這個功能目前來看是有 BUG 的,我在 Mac 上親測是沒有效的,而在 github 的 issue 中也有人在 2020 年8月反應過問題, 沒想到到現在還沒有解決

雖然它本身提供的組合鍵監聽模式無法使用,但普通的監聽模式還是可以使用的,只要有這個做爲基礎,那我自己造輪子也不難實現組合熱鍵的功能。

第一步:先定義好你的熱鍵:⌘ ⌃ ⌥ P

upload_pic_set = {
    keyboard.Key.ctrl.value.vk,
    keyboard.Key.cmd.value.vk,
    keyboard.Key.alt.value.vk,
    keyboard.KeyCode(35).vk
}

第二步:監聽所有的鍵盤動作

with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

只要有一個鍵處於 press 的狀態,就往列表中存放這個鍵

key_list = []

def on_press(key):
    if isinstance(key, keyboard.KeyCode):
        key_list.append(key.vk)
    elif isinstance(key, keyboard.Key):
        key_list.append(key.value.vk)

    if set(key_list) == upload_pic_set:
        image = get_image_from_clipboard()
        new_image = make_watermark(image)
        put_image_to_clip(new_image)
        upload_image_via_picgo()
        notify_to_mac("成功添加水印並上傳到圖牀")

但是一旦有鍵釋放了,就要清空這個列表

def on_release(key):
    key_list.clear()

每一次按下鍵都會檢查,key_list 是否等於 定義好的快捷鍵,如果剛好是相等,就可以開始圖片的處理邏輯了。

if set(key_list) == upload_pic_set:
  pass

4.2 從內存中讀取圖像

PIL 有一個 ImageGrab 模塊,在這個模塊中有一個 grabclipboard 函數,它實現了從剪切板中讀取圖像的功能,不過讀取的 rgb 格式,由於我們後面加水印時,必須使用 rgba 格式纔可以,因此再用 convert 轉一下。

  from PIL import  ImageGrab
  
  img_rgb = ImageGrab.grabclipboard()
  image = img_rgb.convert("RGBA")

###4.3 添加水印生成新圖像

以下是添加水印的代碼,其實可能要注意的一點就是如果你的文字裏包含中文,那麼選擇字體時一定要是中文字體,否則會出現方塊字

def make_watermark(image):
    txt = Image.new('RGBA', image.size, (0, 0, 0, 0))
    fnt = ImageFont.truetype("/System/Library/Fonts/STHeiti Medium.ttc", 20)
    draw = ImageDraw.Draw(txt)
    draw.text(((txt.size[0]-300)//2, txt.size[1]-40), "微信公衆號: Python編程時光", font=fnt, fill=(240, 49, 48, 255))
    draw.text(((txt.size[0]-300)//2, txt.size[1]-70), "未經授權請勿轉載", font=fnt, fill=(240, 49, 48,  255))
    out = Image.alpha_composite(image, txt)
    return out

4.4 將新圖像重新放入剪切板

內置的 io 模塊支持在內存中讀寫 bytes,只要PIL 的 image 對象在 save 的時候保存保存在 BytesIO 對象中,然後通過 pasteboard 模塊從 BytesIO 對象中載入數據,就可以實現往剪切板中放入圖像的功能。

def put_image_to_clip(image):
    img_byte_arr = io.BytesIO() 
    pb = pasteboard.Pasteboard()

    image.save(img_byte_arr, format='PNG')
    img_byte_arr = img_byte_arr.getvalue()
    pb.set_contents(img_byte_arr, pasteboard.PNG)

pasteboard 載入的圖像只支持 PNG 格式,因此在保存時,一定要指定 PNG。

此外 pasteboard 還支持更多格式的數據,比如 PDF,音頻數據,HTML、顏色數據等等

更多格式可查看:https://developer.apple.com/documentation/appkit/nspasteboardtypestring

4.5 模擬觸發 PicGo

正常情況下,我們是通過快捷鍵來觸發 PicGo 去從剪切板中上傳圖像的,因此想要在程序中激活 PicGo,也只需要在 Python 腳本中模擬鍵盤動作即可。

具體的代碼如下:

from pykeyboard import PyKeyboard

def upload_image_via_picgo():
    k = PyKeyboard()
    k.press_keys(['Command', 'shift', 'p'])

4.6 通知 Mac 通知臺

上面整個過程都是腳本在後臺默默運行的,如果沒有任何通知,作爲用戶,很難知道我們的圖片是否處理好,是否上傳成功,因此建議加一個通知的函數。

import os

def notify_to_mac(message):
    os.system("osascript -e 'display notification \"{}\"\'".format(message))

不過其實 PicGo 上傳完圖片後,本身就會通知,所以這個通知並不是必要的,看個人需求啦~

5. 其他設置工作

5.1 設置程序權限

如果你在使用如上腳本時,發現有的鍵無法捕捉,那一定是系統沒有給予權限,需要你手動開啓。

5.2 設置開機自啓

在這裏添加一個開機啓動項,而這個 init.sh 是一個 Shell 腳本。

這個腳本的內容如下,注意最後那個 & 一定不能省略。

6. 運行效果

代碼全部解析完了,是不是很想看這個程序運行後,可以實現怎樣的效果呢?

我錄製了個 GIF 動態圖,你可以瞧一瞧,真的太方便了。

7. 寫在最後

對於有和我一樣寫博客習慣的朋友來說,我相信這篇文章的思路一定會有幫助,腳本我已經腳本上傳好了(鏈接: https://wws.lanzous.com/iIDt1ml8mpi),直接下載即可。

另外,即使你沒有防搬運的需求,代碼的實現依然值得學習,比如

  • 如何監聽鍵盤並定義程序的熱鍵?
  • 如何從剪切板中讀取圖像?
  • 如何給圖像添加水印?
  • 如何將圖像再放入到剪切板?
  • 如何模擬鍵盤來激活程序?

在編碼的時候,也遇到了不少的坑,有的第三方庫並不適用於 Mac,有的有 BUG 至今也還沒修復,有的甚至要閱讀源碼才能知道如何使用,經過多輪的調試和搜索,最終才完成這個腳本。


文章最後給大家介紹三個我自己寫的在線文檔:

第一個文檔PyCharm 中文指南 1.0 文檔

花了兩個多月的時間,整理了 100 個 PyCharm 的使用技巧,爲了讓新手能夠直接上手,我花了很多的時間錄製了上百張 GIF 動圖,有興趣的前往在線文檔閱讀。

第二個文檔PyCharm 黑魔法指南 1.0 文檔

系統收錄各種 Python 冷門知識,Python Shell 的多樣玩法,令人瘋狂的 Python 炫技操作,Python 的超詳細進階知識解讀,非常實用的 Python 開發技巧等。

第三個文檔Python 中文指南 1.0 文檔

花了三個月時間寫的一本 適合零基礎入門 Python 的全中文教程,搭配大量的代碼案例,讓初學者對 代碼的運作效果有一個直觀感受,教程既有深度又有廣度,每篇文章都會標內容的難度,是基礎還是進階的,可供讀者進行選擇,是一本難得的 Python 中文電子教程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章