forked from skorokithakis/lektor-thumbnail-generator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lektor_thumbnail_generator.py
124 lines (100 loc) · 4.22 KB
/
lektor_thumbnail_generator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# -*- coding: utf-8 -*-
import shutil
from lektor.build_programs import AttachmentBuildProgram, buildprogram
from lektor.context import get_ctx
from lektor.db import Image
from lektor.imagetools import (compute_dimensions, find_imagemagick,
get_image_info, get_quality)
from lektor.pluginsystem import Plugin
from lektor.reporter import reporter
from lektor.utils import portable_popen
from werkzeug.utils import cached_property
# We override process_image here because Lektor does not support adding extra
# parameters yet, but it will soon, and this can be removed when it does.
def process_image(
ctx,
source_image,
dst_filename,
width=None,
height=None,
mode=None,
quality=None,
extra_params=None,
):
"""Build image from source image, optionally compressing and resizing.
"source_image" is the absolute path of the source in the content directory,
"dst_filename" is the absolute path of the target in the output directory.
"""
if width is None and height is None:
raise ValueError("Must specify at least one of width or height.")
im = find_imagemagick(ctx.build_state.config["IMAGEMAGICK_EXECUTABLE"])
if quality is None:
quality = get_quality(source_image)
resize_key = ""
if width is not None:
resize_key += str(width)
if height is not None:
resize_key += "x" + str(height)
cmdline = [im, source_image, "-auto-orient"]
cmdline += ["-resize", resize_key]
if extra_params:
cmdline.extend(extra_params)
cmdline += ["-quality", str(quality), dst_filename]
reporter.report_debug_info("imagemagick cmd line", cmdline)
portable_popen(cmdline).wait()
@buildprogram(Image)
class ResizedImageBuildProgram(AttachmentBuildProgram):
def build_artifact(self, artifact):
ctx = get_ctx()
plugin = ctx.env.plugins["thumbnail-generator"]
config = plugin.config
artifact.ensure_dir()
AttachmentBuildProgram.build_artifact(self, artifact)
if not config:
return
source_img = artifact.source_obj.attachment_filename
with open(source_img, "rb") as f:
_, w, h = get_image_info(f)
# For every section in the config, we need to generate one image.
for item, conf in config.items():
width = int(conf["max_width"])
height = int(conf.get("max_height", "0"))
if not height:
_, height = compute_dimensions(width, None, w, h)
df = artifact.source_obj.url_path
ext_pos = df.rfind(".")
dst_filename = "%s-%s.%s" % (df[:ext_pos], item, df[ext_pos + 1 :])
def closure(dst_filename, source_img, width, height, resize_image=True):
# We need this closure, otherwise variables get updated and this
# doesn't work at all.
@ctx.sub_artifact(artifact_name=dst_filename, sources=[source_img])
def build_thumbnail_artifact(artifact):
artifact.ensure_dir()
if not resize_image:
shutil.copy2(source_img, artifact.dst_filename)
else:
process_image(
ctx,
source_img,
artifact.dst_filename,
width,
height,
quality=85,
extra_params=[
"-strip",
"-interlace",
"Plane",
],
)
# If the image is larger than the max_width, resize it, otherwise
# just copy it.
resize_image = w > width or h > height
closure(dst_filename, source_img, width, height, resize_image)
class ThumbnailGeneratorPlugin(Plugin):
name = u"thumbnail-generator"
description = u"A configurable way to generate thumbnails."
image_exts = ["png", "jpg", "jpeg", "gif"]
@cached_property
def config(self):
conf = self.get_config()
return {section: conf.section_as_dict(section) for section in conf.sections()}