sublime中为Markdown文档插入剪切板中的图片
sublime中为Markdown文档插入剪切板中的图片
sublime中为Markdown文档插入剪切板中的图片的插件没有合适的,找到一个不是很好用,几年前开发的,以及不维护了。于是,自己写一个吧。
自己写的好处就是,各种问题都可以自己去进行修复,进行定制化的配置。这个也是的,在Macos系统下面是Retina屏,截屏保存的图片的像素是普通屏幕的大概4倍,就是长度和宽度都变成了2倍。
所以,我在粘贴图片的时候就会在普通的![]()
后面再加上原始截屏时的长度和宽度![](){width="10" height="10"}
。这样,即使在Retina屏下截取的图片也不影响,最终呈现的大小和原始的Retina一样,而不是4倍。
目前直接使用全路径,将所有的图片放在一个单独的文件夹,而不是一般的,放在.md文件的当前目录下面,这样,.md文档的目录看起来更干净一些。
TODO:
后面,可以再完善一个清理图片的功能,因为在粘贴的过程中,有可能会截图多次,或者文章中把图片删除了,但实际上的图片并没有删除。可以把图片对应的文章中的引用扫描一下,如果没有引用了,则可以删除掉。这样,可以把不需要的图片及时清理掉。
由于sublime的默认包里面没有PIL包,所以,使用了外置的python来执行,需要在环境变量中加入python的路径。并且安装PIL包。
pip3 install pillow
import sublime
import sublime_plugin
import os
import sys
import subprocess
class MarkdownImagePasteObject(object):
settings_file = 'MarkdownImagePaste.sublime-settings'
def __init__(self, *args, **kwgs):
super(MarkdownImagePasteObject, self).__init__(*args, **kwgs)
self.settings = sublime.load_settings(self.settings_file)
self.image_dir = self.settings.get("image_dir", ".images")
self.project_dir = self.settings.get("project_dir")
# TODO:
if len(self.project_dir) == 0:
self.project_dir = "~/md"
self.project_dir = os.path.normpath(os.path.expanduser(self.project_dir))
print(self.project_dir)
class MarkdownImagePasteCommand(MarkdownImagePasteObject, sublime_plugin.TextCommand):
def run(self, edit):
filename = self.get_filename()
if filename is None:
sublime.error_message('Please save the file first!')
return
size = self.paste_image(filename)
# print("size:", size)
if size:
for pos in self.view.sel():
if 'text.html.markdown' in self.view.scope_name(pos.begin()):
if sys.platform == 'darwin':
width = int(size[0]) // 2
hight = int(size[1]) // 2
if width > 900:
ratio = 900.0 / width
width = 900
hight = int(hight * ratio)
self.view.insert(edit, pos.begin(), '{width="%d" height="%d"}' % (filename, width, hight))
# self.view.insert(edit, pos.begin(), '
' % (filename, size[0], size[1]))
else:
self.view.insert(edit, pos.begin(), "" % filename)
else:
self.view.insert(edit, pos.begin(), "%s" % filename)
break
else:
self.view.run_command("paste")
def get_filename(self):
view = self.view
filename = view.file_name()
if filename is None:
# raise RuntimeError("Please save the file first!")
return None
else:
filename = os.path.normpath(os.path.expanduser(filename))
# create dir in current path with the name of current filename
dirname, _ = os.path.splitext(filename)
sub_dir = dirname[len(self.project_dir) + 1:]
# print("sub_dir", sub_dir)
# create new image file under currentdir/filename_without_ext/filename_without_ext%d.png
fn_without_ext = os.path.basename(dirname)
full_image_dir = os.path.join(self.project_dir, self.image_dir, sub_dir)
# print("full_image_dir", full_image_dir)
if not os.path.lexists(full_image_dir):
os.makedirs(full_image_dir)
i = 0
while True:
# absolute file path
abs_filename = os.path.join(full_image_dir, "%s%d.png" % (fn_without_ext, i))
if not os.path.exists(abs_filename):
break
i += 1
# print("save file: " + abs_filename)
return abs_filename
def paste_image(self, filename):
'''
成功:返回格式为 (width, height),失败:返回 None
'''
# 内部没有pillow的lib,用外包python执行
command = 'python3 "%s" save "%s"' % (os.path.join(os.path.dirname(__file__), 'bin/imageutils.py'), filename)
# print(command)
out = self.run_command(command)
# print("out:" + out + ":end")
if out and out[-2:-1] == "0":
return out.split("\n")[0].split(",")
else:
return None
def run_command(self, cmd):
filename = self.view.file_name()
if filename is None:
cwd = "~"
else:
cwd = os.path.dirname(filename)
# print("cmd %r" % cmd)
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd, env=os.environ)
try:
outs, errs = proc.communicate(timeout=15)
# print("outs %r %r" % (outs, proc))
except Exception:
proc.kill()
outs, errs = proc.communicate()
print("outs %r, errs %r" % (b'\n'.join(outs.split(b'\r\n')), errs))
if errs is None or len(errs) == 0:
return outs.decode()
bin/imageutils.py
"""
pip install pillow
"""
import sys
import os
from PIL import Image, ImageGrab
def getSize(filename):
with Image.open(filename) as im:
# print("file: %s with size: %d %d" % (file1, im.width, im.height))
return (im.width, im.height)
def saveImagefile(filename):
im = ImageGrab.grabclipboard()
if isinstance(im, Image.Image):
# retina screen should scale 0.5
# if sys.platform == 'darwin':
# im = im.resize((im.size[0] // 2, im.size[1] // 2), Image.ANTIALIAS)
print("%d,%d" % (im.size[0], im.size[1]))
im.save(filename)
return 0
else:
return 1
if __name__ == '__main__':
if len(sys.argv) == 3:
# python imageutil.py size filename
# print("begin %r" % sys.stdin.encoding)
if sys.argv[1] == 'size':
print("%d,%d" % getSize(sys.argv[2]))
elif sys.argv[1] == 'save':
print(saveImagefile(sys.argv[2]))