jekyll-images 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/lib/jekyll/filters/height.rb +25 -0
- data/lib/jekyll/filters/thumbnail.rb +15 -24
- data/lib/jekyll/filters/width.rb +25 -0
- data/lib/jekyll/images/cache.rb +24 -0
- data/lib/jekyll/images/image.rb +31 -0
- data/lib/jekyll/images/thumbnail.rb +36 -29
- data/lib/jekyll-images.rb +7 -0
- metadata +7 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 940d7564e5f46ba24c22eec51f474252fc5f23445f37f2589a05788c2b107e55
|
4
|
+
data.tar.gz: 3fdb9012e009324edac12a65d2550dedb93cb4bf899d50ce011a0849c23fc44a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1b872ea8903b49b10efe560c0d568debcdfb937a8efbdb6059f238251ab71279d78056479d756cbc7c6bef34577e23c09e22c0ce97ff73d1e2ec0e853b31a49
|
7
|
+
data.tar.gz: 59136867e0841097770b5ae7f3a774f8a4d6934445dcc0bf8e47ab6df4104bd70d34061eb88ac0bcf0c7ef6c53a4b30c970f959164700a41cb4a501008593772
|
data/README.md
CHANGED
@@ -53,10 +53,12 @@ In your templates, you can use the `thumbnail` filter:
|
|
53
53
|
|
54
54
|
Options for this filter are in the following order:
|
55
55
|
|
56
|
-
* `width
|
56
|
+
* `width`, the desired width for the image, if `nil`, `height` is
|
57
|
+
required.
|
57
58
|
|
58
59
|
* `height`, if provided, the thumbnail will crop to this size. If not,
|
59
|
-
the image is scaled down proportionally to the width.
|
60
|
+
the image is scaled down proportionally to the width. It becomes
|
61
|
+
required if the width is `nil`.
|
60
62
|
|
61
63
|
* `crop` the smart cropping algorithm. One of `none`, `centre`,
|
62
64
|
`entropy` or `attention` (default). See
|
@@ -67,7 +69,7 @@ Options for this filter are in the following order:
|
|
67
69
|
orientation metadata, this controls if it's automatically rotated.
|
68
70
|
|
69
71
|
If you want to pass `crop` and `auto_rotate` but not `height`, just set
|
70
|
-
`height` to `
|
72
|
+
`height` to `nil`.
|
71
73
|
|
72
74
|
## TODO
|
73
75
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
# Obtain image height
|
6
|
+
module Height
|
7
|
+
def height(input)
|
8
|
+
return unless input
|
9
|
+
input = @context.registers[:site].in_source_dir input
|
10
|
+
|
11
|
+
unless ::File.exist? input
|
12
|
+
Jekyll.logger.warn "File doesn't exist #{input}"
|
13
|
+
return input
|
14
|
+
end
|
15
|
+
|
16
|
+
Jekyll::Images::Cache.cached_image(input).height
|
17
|
+
rescue Vips::Error => e
|
18
|
+
Jekyll.logger.warn "Failed to process #{input}: #{e.message}"
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Liquid::Template.register_filter(Jekyll::Filters::Height)
|
@@ -1,41 +1,32 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'pry'
|
4
3
|
module Jekyll
|
5
4
|
module Filters
|
6
5
|
# Liquid filter for use in templates
|
7
6
|
module Thumbnail
|
8
|
-
@@cached_images = {}
|
9
|
-
|
10
7
|
# Generates a thumbnail and returns its alternate destination
|
11
|
-
def thumbnail(input, width, height = nil, crop =
|
8
|
+
def thumbnail(input, width = nil, height = nil, crop = nil, auto_rotate = nil)
|
12
9
|
return unless input
|
13
|
-
|
10
|
+
input = @context.registers[:site].in_source_dir input
|
11
|
+
|
12
|
+
unless ::File.exist? input
|
13
|
+
Jekyll.logger.warn "File doesn't exist #{input}"
|
14
|
+
return input
|
15
|
+
end
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
+
image = Jekyll::Images::Cache.cached_image input
|
18
|
+
thumb = image.thumbnail(width: width,
|
19
|
+
height: height,
|
20
|
+
crop: crop,
|
21
|
+
auto_rotate: auto_rotate)
|
17
22
|
|
18
|
-
|
19
|
-
|
23
|
+
thumb.write && thumb.optimize
|
24
|
+
|
25
|
+
thumb.url
|
20
26
|
rescue Vips::Error => e
|
21
27
|
Jekyll.logger.warn "Failed to process #{input}: #{e.message}"
|
22
28
|
input
|
23
29
|
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def cached_image?(input)
|
28
|
-
@@cached_images.key? input
|
29
|
-
end
|
30
|
-
|
31
|
-
def cached_image(input, width = nil, height = nil, crop = nil, auto_rotate = nil)
|
32
|
-
@@cached_images[input] ||= Jekyll::Images::Thumbnail.new(@context.registers[:site],
|
33
|
-
input,
|
34
|
-
width: width,
|
35
|
-
height: height,
|
36
|
-
crop: crop,
|
37
|
-
auto_rotate: auto_rotate)
|
38
|
-
end
|
39
30
|
end
|
40
31
|
end
|
41
32
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Filters
|
5
|
+
# Obtain image width
|
6
|
+
module Width
|
7
|
+
def width(input)
|
8
|
+
return unless input
|
9
|
+
input = @context.registers[:site].in_source_dir input
|
10
|
+
|
11
|
+
unless ::File.exist? input
|
12
|
+
Jekyll.logger.warn "File doesn't exist #{input}"
|
13
|
+
return input
|
14
|
+
end
|
15
|
+
|
16
|
+
Jekyll::Images::Cache.cached_image(input).width
|
17
|
+
rescue Vips::Error => e
|
18
|
+
Jekyll.logger.warn "Failed to process #{input}: #{e.message}"
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Liquid::Template.register_filter(Jekyll::Filters::Width)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module Images
|
5
|
+
# Cache
|
6
|
+
class Cache
|
7
|
+
class << self
|
8
|
+
attr_accessor :site
|
9
|
+
|
10
|
+
def cached_images
|
11
|
+
@cached_images ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def cached_image?(input)
|
15
|
+
cached_images.key? input
|
16
|
+
end
|
17
|
+
|
18
|
+
def cached_image(input)
|
19
|
+
cached_images[input] ||= Jekyll::Images::Image.new(site, input)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module Images
|
7
|
+
class Image
|
8
|
+
attr_reader :site, :filename, :height, :width
|
9
|
+
|
10
|
+
def initialize(site, filename)
|
11
|
+
unless File.exist? filename
|
12
|
+
raise ArgumentError, "File not found: #{filename}"
|
13
|
+
end
|
14
|
+
|
15
|
+
@cached_thumbnails = {}
|
16
|
+
@site = site
|
17
|
+
@filename = filename
|
18
|
+
|
19
|
+
# We only need the image to get height and width
|
20
|
+
image = Vips::Image.new_from_file filename, access: :sequential
|
21
|
+
|
22
|
+
@height = image.height
|
23
|
+
@width = image.width
|
24
|
+
end
|
25
|
+
|
26
|
+
def thumbnail(**args)
|
27
|
+
@cached_thumbnails[args.hash.to_s] ||= Thumbnail.new site: site, filename: filename, image: self, **args
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -4,45 +4,41 @@ require 'vips'
|
|
4
4
|
|
5
5
|
module Jekyll
|
6
6
|
module Images
|
7
|
-
# Use LibVIPS to generate images in different sizes
|
8
|
-
#
|
9
|
-
# We're assuming every image is going to be thumbnailed
|
10
7
|
class Thumbnail
|
11
|
-
attr_reader :site, :filename, :width, :height, :crop, :auto_rotate
|
8
|
+
attr_reader :site, :filename, :image, :width, :height, :crop, :auto_rotate
|
12
9
|
|
13
|
-
def initialize(site
|
14
|
-
|
15
|
-
raise ArgumentError, "
|
10
|
+
def initialize(site:, filename:, image:, **args)
|
11
|
+
if args.slice(:width, :height).values.none?
|
12
|
+
raise ArgumentError, "#{filename} thumbnail needs width or height"
|
16
13
|
end
|
17
|
-
raise ArgumentError, 'Missing width' unless args[:width]
|
18
14
|
|
19
15
|
@site = site
|
20
16
|
@filename = filename
|
21
|
-
@
|
22
|
-
@
|
23
|
-
@
|
24
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
def image
|
28
|
-
@image ||= Vips::Image.new_from_file filename,
|
29
|
-
access: :sequential
|
17
|
+
@image = image
|
18
|
+
@width = args[:width] || proportional_width(args[:height])
|
19
|
+
@height = args[:height] || proportional_height(args[:width])
|
20
|
+
@crop = args[:crop]&.to_sym || :attention
|
21
|
+
@auto_rotate = args[:auto_rotate].nil? ? true : args[:auto_rotate]
|
30
22
|
end
|
31
23
|
|
24
|
+
# XXX: We don't memoize because we don't need the thumbnail in
|
25
|
+
# memory after it has been written.
|
32
26
|
def thumbnail
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
Vips::Image.thumbnail filename,
|
28
|
+
width,
|
29
|
+
height: height,
|
30
|
+
auto_rotate: auto_rotate,
|
31
|
+
crop: crop
|
37
32
|
end
|
38
33
|
|
39
|
-
|
40
|
-
|
34
|
+
# Finds a height that's proportional to the width
|
35
|
+
def proportional_height(width)
|
36
|
+
@proportional_height ||= (image.height * (width / image.width.to_f)).round
|
41
37
|
end
|
42
38
|
|
43
|
-
#
|
44
|
-
def
|
45
|
-
@
|
39
|
+
# Find a width that's proportional to height
|
40
|
+
def proportional_width(height)
|
41
|
+
@proportional_width ||= (image.width * (height / image.height.to_f)).round
|
46
42
|
end
|
47
43
|
|
48
44
|
# Generates a destination from filename only if we're downsizing
|
@@ -54,6 +50,10 @@ module Jekyll
|
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
53
|
+
def url
|
54
|
+
static_file.url
|
55
|
+
end
|
56
|
+
|
57
57
|
def thumbnail?
|
58
58
|
image.width > width
|
59
59
|
end
|
@@ -76,14 +76,13 @@ module Jekyll
|
|
76
76
|
Jekyll.logger.info "Thumbnailing #{filename} => #{dest}"
|
77
77
|
thumbnail.write_to_file(dest)
|
78
78
|
else
|
79
|
+
Jekyll.logger.info "Copying #{filename} => #{dest}"
|
79
80
|
FileUtils.cp(filename, dest)
|
80
81
|
end
|
81
82
|
|
82
83
|
# Add it to the static files so Jekyll copies them. Once they
|
83
84
|
# are written they're copied when the site is loaded.
|
84
|
-
site.static_files <<
|
85
|
-
File.dirname(dest),
|
86
|
-
File.basename(dest))
|
85
|
+
site.static_files << static_file
|
87
86
|
|
88
87
|
# The file was updated, so it exists and is newer than source
|
89
88
|
!write?
|
@@ -99,6 +98,14 @@ module Jekyll
|
|
99
98
|
|
100
99
|
Jekyll.logger.info "Reduced #{dest} from #{before} to #{after} bytes (%#{pct})"
|
101
100
|
end
|
101
|
+
|
102
|
+
def relative_path
|
103
|
+
@relative_path ||= dest.sub(site.source, '').sub(%r{\A/}, '')
|
104
|
+
end
|
105
|
+
|
106
|
+
def static_file
|
107
|
+
@static_file ||= Jekyll::StaticFile.new(site, site.source, File.dirname(relative_path), File.basename(relative_path))
|
108
|
+
end
|
102
109
|
end
|
103
110
|
end
|
104
111
|
end
|
data/lib/jekyll-images.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'jekyll/images/cache'
|
4
|
+
|
5
|
+
Jekyll::Images::Cache.site = Jekyll.sites.first
|
6
|
+
|
7
|
+
require_relative 'jekyll/images/image'
|
3
8
|
require_relative 'jekyll/images/thumbnail'
|
4
9
|
require_relative 'jekyll/filters/thumbnail'
|
10
|
+
require_relative 'jekyll/filters/width'
|
11
|
+
require_relative 'jekyll/filters/height'
|
5
12
|
require_relative 'jekyll/images/oxipng'
|
6
13
|
require_relative 'jekyll/images/jpeg_optim'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-images
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- f
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-11-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -64,7 +64,11 @@ files:
|
|
64
64
|
- LICENSE
|
65
65
|
- README.md
|
66
66
|
- lib/jekyll-images.rb
|
67
|
+
- lib/jekyll/filters/height.rb
|
67
68
|
- lib/jekyll/filters/thumbnail.rb
|
69
|
+
- lib/jekyll/filters/width.rb
|
70
|
+
- lib/jekyll/images/cache.rb
|
71
|
+
- lib/jekyll/images/image.rb
|
68
72
|
- lib/jekyll/images/jpeg_optim.rb
|
69
73
|
- lib/jekyll/images/oxipng.rb
|
70
74
|
- lib/jekyll/images/runner.rb
|
@@ -99,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
99
103
|
- !ruby/object:Gem::Version
|
100
104
|
version: '0'
|
101
105
|
requirements: []
|
102
|
-
rubygems_version: 3.
|
106
|
+
rubygems_version: 3.1.2
|
103
107
|
signing_key:
|
104
108
|
specification_version: 4
|
105
109
|
summary: Optimizes images for Jekyll
|