一直觉得 mac
的截图效果非常好看,之前在 ArchLinux
上用 imagemagick
撸了一个类似的,最近在体验 windows 11
,顺便也移植了一份。
1 实现效果
- 添加阴影
- 添加圆角
- 添加水印
- 添加边框
2 实现流程
2.1 剪切板操作
想要对剪切板图片进行修改首先就要能获取剪切板的图片和向剪切板发送图片,在运行 Xorg
的 Linux
上可以很方便地使用 xclip
来操作
# get image from clipboard
xclip -selection clipboard -t image/png -o > /tmp/src.png
# send image to clipboard
xclip -selection clipboard -t image/png -i /tmp/des.png
但在 windows 11
上该如何获取呢?我先是查询了 powershell
的相关 API
,然后我发现有现成的 Get-Clipboard
和 Set-Clipboard
两个模块函数可用
# get image from clipboard
$img = Get-Clipboard -Format Image
但很可惜我发现 Get-Content path/to/file | Set-Clipboard
对文本是可以的,但是对图片却会乱码,在网上查询也没找到相关解释,于是我换了一种设置剪切板的方法
# send result to clipboard
Add-Type -Assembly System.Windows.Forms
Add-Type -Assembly System.Drawing
$img = [Drawing.Image]::FromFile($result_image)
[Windows.Forms.Clipboard]::SetImage($img)
我也查询了一下 python
基于 PIL
和 win32clipboard
的操作方法
from PIL import ImageGrab
from io import BytesIO
import win32clipboard
# get image from clipboard
image = ImageGrab.grabclipboard()
# send image to clipboard
output = BytesIO()
border_image.convert('RGB').save(output, 'BMP')
data = output.getvalue()[14:]
output.close()
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
win32clipboard.CloseClipboard()
2.2 图片处理
2.2.1 imagemagick
对于图片的处理首先想到的就是 imagemagick
这个工具了,在 Linux
使用非常简单
先加圆角,我这里使用的圆角弧度为 8
convert /tmp/src.png \
\( +clone -alpha extract \
-draw 'fill black polygon 0,0 0,8 8,0 fill white circle 8,8 8,0' \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite /tmp/output.png
再加阴影和边框,我设置的边框为 20px,这是为了配合我的水印图片
convert /tmp/output.png -bordercolor none -border 20 \( +clone -background black -shadow 100x15+0+0 \) \
+swap -background transparent -layers merge +repage /tmp/des.png
再加上自己的水印
composite -gravity SouthEast ~/.local/bin/watermark.png /tmp/des.png /tmp/des.png
但我在 powershell
上尝试使用 imagemagick
的时候发现参数识别出现了问题,+clone
没认出来,还好 win 11
窗口自带阴影和圆角,那我只要打一下水印就好了
$cmd = "composite -gravity SouthEast $watermark $source_image $result_image"
Invoke-Expression $cmd
在 scoop
安装 imagemagick
的时候我发现还引入了 ffmpeg
这个依赖包,我虽然也经常用它,但毕竟还是有点大,于是我尝试用 PIL
来处理图片。
先加一下边框,我是 nord
配色的忠实用户,所以选用了 “#2E3440” 同时也是我桌面壁纸的主要颜色,这是我用 k-means
算法写的一个提取图片主要颜色的脚本。
# add border
border = 20 # border size
border_color = "#2E3440" # border color
border_image = Image.new("RGBA", (image.width + border, image.height + border), border_color)
align = int(border / 2)
border_image.paste(image, (align, align))
然后添加水印
# add watermark
watermark = Image.open(r"C:\Users\zjuyk\Desktop\watermark.png")
watermark = watermark.convert("RGBA")
border_image.paste(watermark, (border_image.width - watermark.width, border_image.height - watermark.height), watermark)
在尝试添加圆角的时候我发现,锯齿非常严重,严重影响美观度,所以没有放进脚本里,阴影也是一样,我打算全用 windows 11
自带的窗口阴影和圆角。如果非要自己实现的话,我建议准备几张 mask image
来做图片遮罩。
3 实现效果
- imagemagick - Linux
#!/bin/bash -e
# Get the picture from flameshot
flameshot gui -r > /tmp/src.png
wait $!
# Get the picture from scrot
# scrot --select "/tmp/src.png"
# wait $!
# xclip -selection clipboard -t image/png -o > /tmp/src.png
# add shadow, round corner, border and watermark
convert /tmp/src.png \
\( +clone -alpha extract \
-draw 'fill black polygon 0,0 0,8 8,0 fill white circle 8,8 8,0' \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite /tmp/output.png
convert /tmp/output.png -bordercolor none -border 20 \( +clone -background black -shadow 100x15+0+0 \) \
+swap -background transparent -layers merge +repage /tmp/des.png
composite -gravity SouthEast ~/.local/bin/watermark.png /tmp/des.png /tmp/des.png
# Send the picture to clipboard
xclip -selection clipboard -t image/png -i /tmp/des.png
# remove the left pictures
rm /tmp/src.png /tmp/des.png /tmp/output.png
- imagemagick - PowerShell
# Please add execution policy
# Set-ExecutionPolicy Unrestricted
# get image from clipboard
$img = Get-Clipboard -Format Image
if ($img -eq $null) {
Write-Host "Clipboard contains no image."
Exit
}
# save it to desktop
$img.Save("C:\Users\zjuyk\Desktop\src.png")
# add watermark
$watermark = "C:\Users\zjuyk\Desktop\watermark.png"
$source_image = "C:\Users\zjuyk\Desktop\src.png"
$result_image = "C:\Users\zjuyk\Desktop\res.png"
$cmd = "composite -gravity SouthEast $watermark $source_image $result_image"
Invoke-Expression $cmd
# send result to clipboard
Add-Type -Assembly System.Windows.Forms
Add-Type -Assembly System.Drawing
$img = [Drawing.Image]::FromFile($result_image)
[Windows.Forms.Clipboard]::SetImage($img)
# remove temp files (do it manually)
Remove-Item "C:\Users\zjuyk\Desktop\src.png" -Force
# Remove-Item "C:\Users\zjuyk\Desktop\res.png" -Force
- PIL - Python
from PIL import ImageGrab, Image
from io import BytesIO
import win32clipboard
if __name__ == "__main__":
# get image from clipboard
image = ImageGrab.grabclipboard()
# add border
border = 20 # border size
border_color = "#2E3440" # border color
border_image = Image.new("RGBA", (image.width + border, image.height + border), border_color)
align = int(border / 2)
border_image.paste(image, (align, align))
# add watermark
watermark = Image.open(r"C:\Users\zjuyk\Desktop\watermark.png")
watermark = watermark.convert("RGBA")
border_image.paste(watermark, (border_image.width - watermark.width, border_image.height - watermark.height), watermark)
# send image to clipboard
output = BytesIO()
border_image.convert('RGB').save(output, 'BMP')
data = output.getvalue()[14:]
output.close()
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_DIB, data)
win32clipboard.CloseClipboard()