jekyll_picture_tag 1.12.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.envrc +4 -0
- data/.github/workflows/code-checks.yml +33 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +31 -3
- data/.ruby-version +1 -1
- data/docs/.envrc +2 -0
- data/docs/devs/contributing/code.md +14 -4
- data/docs/devs/contributing/docs.md +24 -6
- data/docs/devs/contributing/setup.md +21 -1
- data/docs/devs/contributing/testing.md +19 -37
- data/docs/devs/releases.md +45 -4
- data/docs/index.md +43 -18
- data/docs/logo.png +0 -0
- data/docs/logo.svg +880 -0
- data/docs/users/configuration/disable.md +1 -1
- data/docs/users/configuration/ignore_missing.md +1 -1
- data/docs/users/configuration/kramdown_fix.md +1 -1
- data/docs/users/configuration/suppress_warnings.md +1 -1
- data/docs/users/configuration/urls.md +69 -0
- data/docs/users/deployment.md +49 -0
- data/docs/users/getting_started.md +55 -0
- data/docs/users/installation.md +18 -38
- data/docs/users/liquid_tag/argument_reference/crop.md +21 -36
- data/docs/users/liquid_tag/examples.md +12 -12
- data/docs/users/liquid_tag/index.md +1 -1
- data/docs/users/notes/{migration.md → migration_1.md} +1 -1
- data/docs/users/notes/migration_2.md +99 -0
- data/docs/users/presets/cropping.md +24 -25
- data/docs/users/presets/default.md +11 -2
- data/docs/users/presets/examples.md +77 -45
- data/docs/users/presets/fallback_image.md +1 -1
- data/docs/users/presets/html_attributes.md +1 -1
- data/docs/users/presets/image_formats.md +3 -3
- data/docs/users/presets/image_quality.md +96 -19
- data/docs/users/presets/index.md +19 -45
- data/docs/users/presets/link_source.md +1 -1
- data/docs/users/presets/media_queries.md +1 -1
- data/docs/users/presets/nomarkdown_override.md +1 -1
- data/docs/users/presets/pixel_ratio_srcsets.md +1 -1
- data/docs/users/presets/quality_width_graph.png +0 -0
- data/docs/users/presets/width_height_attributes.md +1 -1
- data/docs/users/presets/width_srcsets.md +61 -23
- data/docs/users/presets/writing_presets.md +65 -0
- data/docs/users/tutorial.md +97 -0
- data/jekyll_picture_tag.gemspec +38 -23
- data/lib/jekyll_picture_tag.rb +11 -10
- data/lib/jekyll_picture_tag/cache.rb +64 -3
- data/lib/jekyll_picture_tag/defaults/global.rb +18 -0
- data/lib/jekyll_picture_tag/defaults/presets.rb +57 -0
- data/lib/jekyll_picture_tag/images.rb +4 -0
- data/lib/jekyll_picture_tag/images/generated_image.rb +92 -0
- data/lib/jekyll_picture_tag/images/image_file.rb +104 -0
- data/lib/jekyll_picture_tag/{img_uri.rb → images/img_uri.rb} +3 -10
- data/lib/jekyll_picture_tag/{source_image.rb → images/source_image.rb} +44 -9
- data/lib/jekyll_picture_tag/instructions.rb +70 -6
- data/lib/jekyll_picture_tag/instructions/children/config.rb +128 -0
- data/lib/jekyll_picture_tag/instructions/children/context.rb +24 -0
- data/lib/jekyll_picture_tag/instructions/children/params.rb +90 -0
- data/lib/jekyll_picture_tag/instructions/children/parsers.rb +48 -0
- data/lib/jekyll_picture_tag/instructions/children/preset.rb +182 -0
- data/lib/jekyll_picture_tag/instructions/parents/conditional_instruction.rb +69 -0
- data/lib/jekyll_picture_tag/instructions/parents/env_instruction.rb +29 -0
- data/lib/jekyll_picture_tag/output_formats/basic.rb +5 -17
- data/lib/jekyll_picture_tag/parsers.rb +6 -0
- data/lib/jekyll_picture_tag/{instructions → parsers}/arg_splitter.rb +1 -1
- data/lib/jekyll_picture_tag/parsers/configuration.rb +28 -0
- data/lib/jekyll_picture_tag/{instructions → parsers}/html_attributes.rb +1 -1
- data/lib/jekyll_picture_tag/parsers/image_backend.rb +33 -0
- data/lib/jekyll_picture_tag/parsers/preset.rb +43 -0
- data/lib/jekyll_picture_tag/{instructions → parsers}/tag_parser.rb +15 -12
- data/lib/jekyll_picture_tag/router.rb +35 -93
- data/lib/jekyll_picture_tag/srcsets/basic.rb +4 -10
- data/lib/jekyll_picture_tag/utils.rb +24 -20
- data/lib/jekyll_picture_tag/version.rb +1 -1
- data/readme.md +46 -15
- metadata +168 -85
- data/.travis.yml +0 -8
- data/Dockerfile +0 -9
- data/docs/users/configuration/cdn.md +0 -35
- data/docs/users/configuration/relative_urls.md +0 -15
- data/docs/users/notes/input_checking.md +0 -6
- data/jekyll-picture-tag.gemspec +0 -52
- data/lib/jekyll-picture-tag.rb +0 -25
- data/lib/jekyll_picture_tag/cache/base.rb +0 -59
- data/lib/jekyll_picture_tag/cache/generated.rb +0 -20
- data/lib/jekyll_picture_tag/cache/source.rb +0 -19
- data/lib/jekyll_picture_tag/defaults/global.yml +0 -11
- data/lib/jekyll_picture_tag/defaults/presets.yml +0 -11
- data/lib/jekyll_picture_tag/generated_image.rb +0 -140
- data/lib/jekyll_picture_tag/instructions/configuration.rb +0 -121
- data/lib/jekyll_picture_tag/instructions/preset.rb +0 -107
- data/lib/jekyll_picture_tag/instructions/set.rb +0 -75
@@ -1,3 +1,64 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module PictureTag
|
4
|
+
# Store expensive bits of information between text files. Originally cached
|
5
|
+
# width & heights of images in addition to digests, now just image digests.
|
6
|
+
class Cache
|
7
|
+
def initialize(base_name)
|
8
|
+
@base_name = base_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
data[key]
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
raise ArgumentError unless template.keys.include? key
|
17
|
+
|
18
|
+
data[key] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
# Call after updating data.
|
22
|
+
def write
|
23
|
+
return if PictureTag.config['disable_disk_cache']
|
24
|
+
|
25
|
+
FileUtils.mkdir_p(File.join(base_directory, sub_directory))
|
26
|
+
|
27
|
+
File.open(filename, 'w+') do |f|
|
28
|
+
f.write JSON.generate(data)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def data
|
35
|
+
@data ||= if File.exist?(filename)
|
36
|
+
JSON.parse(File.read(filename)).transform_keys(&:to_sym)
|
37
|
+
else
|
38
|
+
template
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# /home/dave/my_blog/.jekyll-cache/jpt/(cache_dir)/assets/myimage.jpg.json
|
43
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
44
|
+
def base_directory
|
45
|
+
File.join(PictureTag.site.cache_dir, 'jpt')
|
46
|
+
end
|
47
|
+
|
48
|
+
# /home/dave/my_blog/.jekyll-cache/jpt/(cache_dir)/assets/myimage.jpg.json
|
49
|
+
# ^^^^^^^^
|
50
|
+
def sub_directory
|
51
|
+
File.dirname(@base_name)
|
52
|
+
end
|
53
|
+
|
54
|
+
# /home/dave/my_blog/.jekyll-cache/jpt/somefolder/myimage.jpg.json
|
55
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
56
|
+
def filename
|
57
|
+
File.join(base_directory, @base_name + '.json')
|
58
|
+
end
|
59
|
+
|
60
|
+
def template
|
61
|
+
{ digest: nil }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# Default settings for _config.yml
|
3
|
+
DEFAULT_CONFIG = {
|
4
|
+
'picture' => {
|
5
|
+
'source' => '',
|
6
|
+
'output' => 'generated',
|
7
|
+
'suppress_warnings' => false,
|
8
|
+
'relative_url' => true,
|
9
|
+
'cdn_environments' => ['production'],
|
10
|
+
'nomarkdown' => true,
|
11
|
+
'ignore_missing_images' => false,
|
12
|
+
'disabled' => false,
|
13
|
+
'fast_build' => false,
|
14
|
+
'ignore_baseurl' => false,
|
15
|
+
'baseurl_key' => 'baseurl'
|
16
|
+
}
|
17
|
+
}.freeze
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module PictureTag
|
2
|
+
DEFAULT_PRESET = { 'markup' => 'auto',
|
3
|
+
'formats' => ['original'],
|
4
|
+
'widths' => [400, 600, 800, 1000],
|
5
|
+
'fallback_width' => 800,
|
6
|
+
'fallback_format' => 'original',
|
7
|
+
'noscript' => false,
|
8
|
+
'link_source' => false,
|
9
|
+
'quality' => 75,
|
10
|
+
'format_quality' => { 'webp' => 50,
|
11
|
+
'avif' => 30,
|
12
|
+
'jp2' => 30 },
|
13
|
+
'data_sizes' => true,
|
14
|
+
'keep' => 'attention',
|
15
|
+
'dimension_attributes' => false,
|
16
|
+
'strip_metadata' => true,
|
17
|
+
'image_options' => {
|
18
|
+
'avif' => { 'compression' => 'av1', 'speed' => 8 }
|
19
|
+
} }.freeze
|
20
|
+
|
21
|
+
STOCK_PRESETS = {
|
22
|
+
'jpt-webp' => { 'formats' => %w[webp original] },
|
23
|
+
|
24
|
+
'jpt-avif' => { 'formats' => %w[avif webp original] },
|
25
|
+
|
26
|
+
'jpt-lazy' => { 'markup' => 'data_auto',
|
27
|
+
'noscript' => true,
|
28
|
+
'formats' => %w[webp original],
|
29
|
+
'attributes' => { 'parent' => 'class="lazy"' } },
|
30
|
+
|
31
|
+
'jpt-loaded' => { 'formats' => %w[avif jp2 webp original],
|
32
|
+
'dimension_attributes' => true },
|
33
|
+
|
34
|
+
'jpt-direct' => { 'markup' => 'direct_url',
|
35
|
+
'fallback_format' => 'webp',
|
36
|
+
'fallback_width' => 600 },
|
37
|
+
|
38
|
+
'jpt-thumbnail' => { 'base_width' => 250,
|
39
|
+
'pixel_ratios' => [1, 1.5, 2],
|
40
|
+
'formats' => %w[webp original],
|
41
|
+
'fallback_width' => 250,
|
42
|
+
'attributes' => { 'picture' => 'class="icon"' } },
|
43
|
+
|
44
|
+
'jpt-avatar' => { 'base_width' => 100,
|
45
|
+
'pixel_ratios' => [1, 1.5, 2],
|
46
|
+
'fallback_width' => 100,
|
47
|
+
'crop' => '1:1' }
|
48
|
+
}.freeze
|
49
|
+
|
50
|
+
STOCK_MEDIA_QUERIES = {
|
51
|
+
'jpt-mobile' => 'max-width: 480px',
|
52
|
+
'jpt-tablet' => 'max-width: 768',
|
53
|
+
'jpt-laptop' => 'max-width: 1024px',
|
54
|
+
'jpt-desktop' => 'max-width: 1200',
|
55
|
+
'jpt-wide' => 'min-width: 1201'
|
56
|
+
}.freeze
|
57
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'ruby-vips'
|
2
|
+
|
3
|
+
module PictureTag
|
4
|
+
# Represents a generated image, but not the file itself. Its purpose is to
|
5
|
+
# make its properties available for query, and hand them off to the ImageFile
|
6
|
+
# class for generation.
|
7
|
+
class GeneratedImage
|
8
|
+
attr_reader :width
|
9
|
+
|
10
|
+
def initialize(source_file:, width:, format:)
|
11
|
+
@source = source_file
|
12
|
+
@width = width
|
13
|
+
@raw_format = format
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
@format ||= process_format(@raw_format)
|
18
|
+
end
|
19
|
+
|
20
|
+
def exists?
|
21
|
+
File.exist?(absolute_filename)
|
22
|
+
end
|
23
|
+
|
24
|
+
def generate
|
25
|
+
generate_image unless @source.missing || exists?
|
26
|
+
end
|
27
|
+
|
28
|
+
# /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
|
29
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
30
|
+
def absolute_filename
|
31
|
+
@absolute_filename ||= File.join(PictureTag.dest_dir, name)
|
32
|
+
end
|
33
|
+
|
34
|
+
# /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
|
35
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
36
|
+
def name
|
37
|
+
@name ||= "#{@source.base_name}-#{@width}-#{id}.#{@format}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# https://example.com/assets/somefolder/myimage-100-123abc.jpg
|
41
|
+
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
42
|
+
def uri
|
43
|
+
ImgURI.new(name).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
# Post crop
|
47
|
+
def source_width
|
48
|
+
image.width
|
49
|
+
end
|
50
|
+
|
51
|
+
# Post crop
|
52
|
+
def source_height
|
53
|
+
image.height
|
54
|
+
end
|
55
|
+
|
56
|
+
def quality
|
57
|
+
PictureTag.quality(format, width)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Hash all inputs and truncate, so we know when they change without getting
|
63
|
+
# too long.
|
64
|
+
# /home/dave/my_blog/_site/generated/somefolder/myimage-100-1234abcde.jpg
|
65
|
+
# ^^^^^^^^^
|
66
|
+
def id
|
67
|
+
@id ||= Digest::MD5.hexdigest(settings.join)[0..8]
|
68
|
+
end
|
69
|
+
|
70
|
+
def settings
|
71
|
+
[@source.digest, @source.crop, @source.keep, quality]
|
72
|
+
end
|
73
|
+
|
74
|
+
def image
|
75
|
+
@image ||= Vips::Image.new_from_file @source.name
|
76
|
+
end
|
77
|
+
|
78
|
+
def generate_image
|
79
|
+
return if @source.missing
|
80
|
+
|
81
|
+
ImageFile.new(@source, self)
|
82
|
+
end
|
83
|
+
|
84
|
+
def process_format(format)
|
85
|
+
if format.casecmp('original').zero?
|
86
|
+
@source.ext
|
87
|
+
else
|
88
|
+
format.downcase
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# Basically a wrapper class for vips. Handles image operations.
|
3
|
+
# Vips returns new images for Crop, resize, and autorotate operations.
|
4
|
+
# Quality, metadata stripping, and format are applied on write.
|
5
|
+
#
|
6
|
+
# This deserves to be two classes and a factory, one for normal vips save and
|
7
|
+
# one for magicksave. This is illustrated by the fact that stubbing backend
|
8
|
+
# determination logic for its unit tests would basically require
|
9
|
+
# re-implementing it completely.
|
10
|
+
#
|
11
|
+
# I'm planning to implement standalone imagemagick as an alternative to vips,
|
12
|
+
# so when I add that I'll also do that refactoring. For now it works fine and
|
13
|
+
# it's not too bloated.
|
14
|
+
class ImageFile
|
15
|
+
def initialize(source, base)
|
16
|
+
@source = source
|
17
|
+
@base = base
|
18
|
+
|
19
|
+
build
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :source, :base
|
25
|
+
|
26
|
+
def build
|
27
|
+
notify
|
28
|
+
|
29
|
+
mkdir
|
30
|
+
|
31
|
+
image = load_image
|
32
|
+
|
33
|
+
image = process(image)
|
34
|
+
|
35
|
+
write(image)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Processing pipeline
|
39
|
+
def process(image)
|
40
|
+
image = crop(image) if source.crop?
|
41
|
+
|
42
|
+
image = resize(image)
|
43
|
+
|
44
|
+
image.autorot
|
45
|
+
end
|
46
|
+
|
47
|
+
def handler
|
48
|
+
PictureTag.backend.handler_for(@base.format)
|
49
|
+
end
|
50
|
+
|
51
|
+
def quality_key
|
52
|
+
handler == :vips ? :Q : :quality
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_opts
|
56
|
+
opts = PictureTag.preset['image_options'][@base.format] || {}
|
57
|
+
|
58
|
+
opts[:strip] = PictureTag.preset['strip_metadata']
|
59
|
+
|
60
|
+
# gifs don't accept a quality setting.
|
61
|
+
opts[quality_key] = base.quality unless base.format == 'gif'
|
62
|
+
|
63
|
+
opts.transform_keys(&:to_sym)
|
64
|
+
end
|
65
|
+
|
66
|
+
def load_image
|
67
|
+
Vips::Image.new_from_file source.name
|
68
|
+
end
|
69
|
+
|
70
|
+
def write(image)
|
71
|
+
case handler
|
72
|
+
when :vips
|
73
|
+
image.write_to_file(base.absolute_filename, **write_opts)
|
74
|
+
# If vips can't handle it, fall back to imagemagick.
|
75
|
+
when :magick
|
76
|
+
image.magicksave(base.absolute_filename, **write_opts)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Fix permissions. TODO - still necessary?
|
80
|
+
FileUtils.chmod(0o644, base.absolute_filename)
|
81
|
+
end
|
82
|
+
|
83
|
+
def notify
|
84
|
+
puts 'Generating new image file: ' + base.name
|
85
|
+
end
|
86
|
+
|
87
|
+
def resize(image)
|
88
|
+
image.resize(scale_value)
|
89
|
+
end
|
90
|
+
|
91
|
+
def crop(image)
|
92
|
+
image.smartcrop(*source.dimensions,
|
93
|
+
interesting: PictureTag.keep(@source.media_preset))
|
94
|
+
end
|
95
|
+
|
96
|
+
def scale_value
|
97
|
+
base.width.to_f / source.width
|
98
|
+
end
|
99
|
+
|
100
|
+
def mkdir
|
101
|
+
FileUtils.mkdir_p(File.dirname(base.absolute_filename))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -18,7 +18,7 @@ module PictureTag
|
|
18
18
|
# | domain | baseurl | directory | filename
|
19
19
|
def to_s
|
20
20
|
Addressable::URI.escape(
|
21
|
-
File.join(domain, baseurl, directory, @filename)
|
21
|
+
File.join(domain, PictureTag.baseurl, directory, @filename)
|
22
22
|
)
|
23
23
|
end
|
24
24
|
|
@@ -29,21 +29,14 @@ module PictureTag
|
|
29
29
|
# | domain | baseurl | j-p-t output dir | filename
|
30
30
|
def domain
|
31
31
|
if PictureTag.cdn?
|
32
|
-
PictureTag.
|
33
|
-
elsif PictureTag.
|
32
|
+
PictureTag.cdn_url
|
33
|
+
elsif PictureTag.relative_url
|
34
34
|
''
|
35
35
|
else
|
36
36
|
PictureTag.config['url'] || ''
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
# https://example.com/my-base-path/assets/generated-images/image.jpg
|
41
|
-
# ^^^^^^^^^^^^^
|
42
|
-
# | domain | baseurl | directory | filename
|
43
|
-
def baseurl
|
44
|
-
PictureTag.config['baseurl'] || ''
|
45
|
-
end
|
46
|
-
|
47
40
|
# https://example.com/my-base-path/assets/generated-images/image.jpg
|
48
41
|
# ^^^^^^^^^^^^^^^^^^^^^^^^
|
49
42
|
# | domain | baseurl | directory | filename
|
@@ -5,7 +5,7 @@ module PictureTag
|
|
5
5
|
class SourceImage
|
6
6
|
attr_reader :shortname, :missing, :media_preset
|
7
7
|
|
8
|
-
include MiniMagick
|
8
|
+
# include MiniMagick
|
9
9
|
|
10
10
|
def initialize(relative_filename, media_preset = nil)
|
11
11
|
# /home/dave/my_blog/assets/images/somefolder/myimage.jpg
|
@@ -21,12 +21,38 @@ module PictureTag
|
|
21
21
|
@digest ||= cache[:digest] || ''
|
22
22
|
end
|
23
23
|
|
24
|
+
def crop
|
25
|
+
PictureTag.crop(media_preset)
|
26
|
+
end
|
27
|
+
|
28
|
+
def crop?
|
29
|
+
!crop.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def keep
|
33
|
+
PictureTag.keep(media_preset)
|
34
|
+
end
|
35
|
+
|
36
|
+
def dimensions
|
37
|
+
[width, height]
|
38
|
+
end
|
39
|
+
|
24
40
|
def width
|
25
|
-
|
41
|
+
return raw_width unless crop?
|
42
|
+
|
43
|
+
[raw_width, (raw_height * cropped_aspect)].min.round
|
26
44
|
end
|
27
45
|
|
28
46
|
def height
|
29
|
-
|
47
|
+
return raw_height unless crop?
|
48
|
+
|
49
|
+
[raw_height, (raw_width / cropped_aspect)].min.round
|
50
|
+
end
|
51
|
+
|
52
|
+
def cropped_aspect
|
53
|
+
return Utils.aspect_float(raw_width, raw_height) unless crop?
|
54
|
+
|
55
|
+
Utils.aspect_float(*crop.split(':').map(&:to_f))
|
30
56
|
end
|
31
57
|
|
32
58
|
# /home/dave/my_blog/assets/images/somefolder/myimage.jpg
|
@@ -44,13 +70,23 @@ module PictureTag
|
|
44
70
|
# /home/dave/my_blog/assets/images/somefolder/myimage.jpg
|
45
71
|
# ^^^
|
46
72
|
def ext
|
47
|
-
@ext ||= File.extname(name)[1
|
73
|
+
@ext ||= File.extname(name)[1..].downcase
|
48
74
|
end
|
49
75
|
|
50
76
|
private
|
51
77
|
|
78
|
+
# pre-crop
|
79
|
+
def raw_width
|
80
|
+
@raw_width ||= @missing ? 999_999 : image.width
|
81
|
+
end
|
82
|
+
|
83
|
+
# pre-crop
|
84
|
+
def raw_height
|
85
|
+
@raw_height ||= @missing ? 999_999 : image.height
|
86
|
+
end
|
87
|
+
|
52
88
|
def cache
|
53
|
-
@cache ||= Cache
|
89
|
+
@cache ||= Cache.new(@shortname)
|
54
90
|
end
|
55
91
|
|
56
92
|
def missing?
|
@@ -75,14 +111,12 @@ module PictureTag
|
|
75
111
|
|
76
112
|
def update_cache
|
77
113
|
cache[:digest] = source_digest
|
78
|
-
cache[:width] = image.width
|
79
|
-
cache[:height] = image.height
|
80
114
|
|
81
115
|
cache.write
|
82
116
|
end
|
83
117
|
|
84
118
|
def image
|
85
|
-
@image ||= Image.
|
119
|
+
@image ||= Vips::Image.new_from_file(name)
|
86
120
|
end
|
87
121
|
|
88
122
|
def source_digest
|
@@ -90,7 +124,8 @@ module PictureTag
|
|
90
124
|
end
|
91
125
|
|
92
126
|
def missing_image_warning
|
93
|
-
"JPT Could not find #{name}.
|
127
|
+
"JPT Could not find #{name}. " \
|
128
|
+
'Your site will have broken images. Continuing.'
|
94
129
|
end
|
95
130
|
|
96
131
|
def missing_image_error
|