Skip to content

Commit 8482e4d

Browse files
authored
v2.5.22: 新增long_img插件,将本子合并为长图 (#299)
1 parent b0cd904 commit 8482e4d

File tree

4 files changed

+105
-2
lines changed

4 files changed

+105
-2
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,11 @@ jmcomic.download_album(422866, option)
121121
- `压缩文件插件`
122122
- `下载特定后缀图片插件`
123123
- `发送QQ邮件插件`
124-
- `日志主题过滤插件`
125124
- `自动使用浏览器cookies插件`
126125
- `jpg图片合成为一个pdf插件`
127126
- `导出收藏夹为csv文件插件`
127+
- `合并所有图片为pdf文件插件`
128+
- `合并所有图片为长图插件`
128129

129130
## 使用小说明
130131

assets/docs/sources/option_file_syntax.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,13 @@ plugins:
244244
pdf_dir: D:/pdf/ # pdf存放文件夹
245245
filename_rule: Aname # pdf命名规则,A代表album, name代表使用album.name也就是本子名称
246246

247+
# 插件来源:https://github.com/hect0x7/JMComic-Crawler-Python/pull/294
248+
# long_img插件是把所有图片合并为一个png长图,效果和img2pdf类似
249+
- plugin: long_img
250+
kwargs:
251+
img_dir: D:/pdf/ # 长图存放文件夹
252+
filename_rule: Aname # 长图命名规则,同上
253+
247254
# 请注意⚠
248255
# 下方的j2p插件的功能不如img2pdf插件,不建议使用。
249256
# 如有图片转pdf的需求,直接使用img2pdf即可,下面的内容请忽略。

src/jmcomic/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# 被依赖方 <--- 使用方
33
# config <--- entity <--- toolkit <--- client <--- option <--- downloader
44

5-
__version__ = '2.5.21'
5+
__version__ = '2.5.22'
66

77
from .api import *
88
from .jm_plugin import *

src/jmcomic/jm_plugin.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,101 @@ def ensure_make_pdf_dir(pdf_dir: str):
799799
return pdf_dir
800800

801801

802+
class LongImgPlugin(JmOptionPlugin):
803+
plugin_key = 'long_img'
804+
805+
def invoke(self,
806+
photo: JmPhotoDetail = None,
807+
album: JmAlbumDetail = None,
808+
downloader=None,
809+
img_dir=None,
810+
filename_rule='Pid',
811+
delete_original_file=False,
812+
**kwargs,
813+
):
814+
if photo is None and album is None:
815+
jm_log('wrong_usage', 'long_img必须运行在after_photo或after_album时')
816+
817+
try:
818+
from PIL import Image
819+
except ImportError:
820+
self.warning_lib_not_install('PIL')
821+
return
822+
823+
self.delete_original_file = delete_original_file
824+
825+
# 处理文件夹配置
826+
img_dir = self.get_img_dir(img_dir)
827+
828+
# 处理生成的长图文件的路径
829+
filename = DirRule.apply_rule_directly(album, photo, filename_rule)
830+
831+
# 长图路径
832+
long_img_path = os.path.join(img_dir, f'{filename}.png')
833+
834+
# 调用 PIL 把 photo_dir 下的所有图片合并为长图
835+
img_path_ls = self.write_img_2_long_img(long_img_path, album, photo)
836+
self.log(f'Convert Successfully: JM{album or photo}{long_img_path}')
837+
838+
# 执行删除
839+
self.execute_deletion(img_path_ls)
840+
841+
def write_img_2_long_img(self, long_img_path, album: JmAlbumDetail, photo: JmPhotoDetail) -> List[str]:
842+
import itertools
843+
from PIL import Image
844+
845+
if album is None:
846+
img_dir_items = [self.option.decide_image_save_dir(photo)]
847+
else:
848+
img_dir_items = [self.option.decide_image_save_dir(photo) for photo in album]
849+
850+
img_paths = itertools.chain(*map(files_of_dir, img_dir_items))
851+
img_paths = filter(lambda x: not x.startswith('.'), img_paths) # 过滤系统文件
852+
853+
images = self.open_images(img_paths)
854+
855+
try:
856+
resample_method = Image.Resampling.LANCZOS
857+
except AttributeError:
858+
resample_method = Image.LANCZOS
859+
860+
min_img_width = min(img.width for img in images)
861+
total_height = 0
862+
for i, img in enumerate(images):
863+
if img.width > min_img_width:
864+
images[i] = img.resize((min_img_width, int(img.height * min_img_width / img.width)),
865+
resample=resample_method)
866+
total_height += images[i].height
867+
868+
long_img = Image.new('RGB', (min_img_width, total_height))
869+
y_offset = 0
870+
for img in images:
871+
long_img.paste(img, (0, y_offset))
872+
y_offset += img.height
873+
874+
long_img.save(long_img_path)
875+
for img in images:
876+
img.close()
877+
878+
return img_paths
879+
880+
def open_images(self, img_paths: List[str]):
881+
images = []
882+
for img_path in img_paths:
883+
try:
884+
img = Image.open(img_path)
885+
images.append(img)
886+
except IOError as e:
887+
self.log(f"Failed to open image {img_path}: {e}", 'error')
888+
return images
889+
890+
@staticmethod
891+
def get_img_dir(img_dir: Optional[str]) -> str:
892+
img_dir = fix_filepath(img_dir or os.getcwd())
893+
mkdir_if_not_exists(img_dir)
894+
return img_dir
895+
896+
802897
class JmServerPlugin(JmOptionPlugin):
803898
plugin_key = 'jm_server'
804899

0 commit comments

Comments
 (0)