jekyll_picture_tag 1.11.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +4 -0
  3. data/.github/workflows/code-checks.yml +33 -0
  4. data/.gitignore +3 -0
  5. data/.rubocop.yml +31 -3
  6. data/.ruby-version +1 -1
  7. data/docs/.envrc +2 -0
  8. data/docs/Gemfile +4 -2
  9. data/docs/Gemfile.lock +14 -12
  10. data/docs/_config.yml +6 -10
  11. data/docs/devs/contributing/code.md +54 -0
  12. data/docs/devs/contributing/docs.md +31 -0
  13. data/docs/devs/contributing/index.md +15 -0
  14. data/docs/devs/contributing/setup.md +33 -0
  15. data/docs/devs/contributing/testing.md +23 -0
  16. data/docs/devs/index.md +7 -0
  17. data/docs/devs/releases.md +118 -0
  18. data/docs/index.md +67 -31
  19. data/docs/logo.png +0 -0
  20. data/docs/logo.svg +880 -0
  21. data/docs/users/configuration/directories.md +34 -0
  22. data/docs/users/configuration/disable.md +24 -0
  23. data/docs/users/configuration/fast_build.md +28 -0
  24. data/docs/users/configuration/ignore_missing.md +23 -0
  25. data/docs/users/configuration/index.md +29 -0
  26. data/docs/users/configuration/kramdown_fix.md +20 -0
  27. data/docs/users/configuration/suppress_warnings.md +16 -0
  28. data/docs/users/configuration/urls.md +69 -0
  29. data/docs/users/getting_started.md +55 -0
  30. data/docs/users/index.md +7 -0
  31. data/docs/users/installation.md +32 -0
  32. data/docs/users/liquid_tag/argument_reference/alternate_images.md +18 -0
  33. data/docs/users/liquid_tag/argument_reference/attributes.md +42 -0
  34. data/docs/users/liquid_tag/argument_reference/base_image.md +12 -0
  35. data/docs/users/liquid_tag/argument_reference/crop.md +33 -0
  36. data/docs/users/liquid_tag/argument_reference/link.md +16 -0
  37. data/docs/users/liquid_tag/argument_reference/preset.md +17 -0
  38. data/docs/users/liquid_tag/argument_reference/readme.md +9 -0
  39. data/docs/users/liquid_tag/examples.md +81 -0
  40. data/docs/users/liquid_tag/index.md +31 -0
  41. data/docs/users/notes/git_lfs.md +7 -0
  42. data/docs/users/notes/github_pages.md +5 -0
  43. data/docs/users/notes/html_attributes.md +5 -0
  44. data/docs/users/notes/index.md +6 -0
  45. data/docs/users/notes/kramdown_bug.md +41 -0
  46. data/docs/users/notes/managing_images.md +21 -0
  47. data/docs/{migration.md → users/notes/migration_1.md} +1 -1
  48. data/docs/users/notes/migration_2.md +99 -0
  49. data/docs/users/presets/cropping.md +60 -0
  50. data/docs/users/presets/default.md +32 -0
  51. data/docs/users/presets/examples.md +111 -0
  52. data/docs/users/presets/fallback_image.md +28 -0
  53. data/docs/users/presets/html_attributes.md +26 -0
  54. data/docs/users/presets/image_formats.md +21 -0
  55. data/docs/users/presets/image_quality.md +120 -0
  56. data/docs/users/presets/index.md +75 -0
  57. data/docs/users/presets/link_source.md +16 -0
  58. data/docs/users/presets/markup_formats/fragments.md +48 -0
  59. data/docs/users/presets/markup_formats/javascript_friendly.md +57 -0
  60. data/docs/users/presets/markup_formats/readme.md +43 -0
  61. data/docs/users/presets/markup_formats/standard_html.md +25 -0
  62. data/docs/users/presets/media_queries.md +36 -0
  63. data/docs/users/presets/nomarkdown_override.md +17 -0
  64. data/docs/users/presets/pixel_ratio_srcsets.md +32 -0
  65. data/docs/users/presets/quality_width_graph.png +0 -0
  66. data/docs/users/presets/width_height_attributes.md +34 -0
  67. data/docs/users/presets/width_srcsets.md +123 -0
  68. data/docs/users/presets/writing_presets.md +65 -0
  69. data/docs/users/tutorial.md +97 -0
  70. data/jekyll_picture_tag.gemspec +38 -23
  71. data/lib/jekyll_picture_tag.rb +11 -10
  72. data/lib/jekyll_picture_tag/cache.rb +64 -3
  73. data/lib/jekyll_picture_tag/defaults/global.rb +18 -0
  74. data/lib/jekyll_picture_tag/defaults/presets.rb +57 -0
  75. data/lib/jekyll_picture_tag/images.rb +4 -0
  76. data/lib/jekyll_picture_tag/images/generated_image.rb +92 -0
  77. data/lib/jekyll_picture_tag/images/image_file.rb +90 -0
  78. data/lib/jekyll_picture_tag/{img_uri.rb → images/img_uri.rb} +3 -10
  79. data/lib/jekyll_picture_tag/{source_image.rb → images/source_image.rb} +44 -9
  80. data/lib/jekyll_picture_tag/instructions.rb +70 -6
  81. data/lib/jekyll_picture_tag/instructions/children/config.rb +128 -0
  82. data/lib/jekyll_picture_tag/instructions/children/context.rb +24 -0
  83. data/lib/jekyll_picture_tag/instructions/children/params.rb +90 -0
  84. data/lib/jekyll_picture_tag/instructions/children/parsers.rb +41 -0
  85. data/lib/jekyll_picture_tag/instructions/children/preset.rb +182 -0
  86. data/lib/jekyll_picture_tag/instructions/parents/conditional_instruction.rb +69 -0
  87. data/lib/jekyll_picture_tag/instructions/parents/env_instruction.rb +29 -0
  88. data/lib/jekyll_picture_tag/output_formats/basic.rb +5 -17
  89. data/lib/jekyll_picture_tag/parsers.rb +5 -0
  90. data/lib/jekyll_picture_tag/{instructions → parsers}/arg_splitter.rb +1 -1
  91. data/lib/jekyll_picture_tag/parsers/configuration.rb +28 -0
  92. data/lib/jekyll_picture_tag/{instructions → parsers}/html_attributes.rb +1 -1
  93. data/lib/jekyll_picture_tag/parsers/preset.rb +43 -0
  94. data/lib/jekyll_picture_tag/{instructions → parsers}/tag_parser.rb +15 -12
  95. data/lib/jekyll_picture_tag/router.rb +35 -93
  96. data/lib/jekyll_picture_tag/srcsets/basic.rb +4 -10
  97. data/lib/jekyll_picture_tag/utils.rb +24 -20
  98. data/lib/jekyll_picture_tag/version.rb +1 -1
  99. data/readme.md +15 -13
  100. metadata +215 -93
  101. data/.travis.yml +0 -8
  102. data/Dockerfile +0 -9
  103. data/docs/_layouts/directory.html +0 -32
  104. data/docs/assets/style.css +0 -31
  105. data/docs/contributing.md +0 -109
  106. data/docs/example_presets.md +0 -116
  107. data/docs/global_configuration.md +0 -173
  108. data/docs/installation.md +0 -45
  109. data/docs/notes.md +0 -91
  110. data/docs/output.md +0 -63
  111. data/docs/presets.md +0 -391
  112. data/docs/releases.md +0 -70
  113. data/docs/usage.md +0 -157
  114. data/jekyll-picture-tag.gemspec +0 -52
  115. data/lib/jekyll-picture-tag.rb +0 -25
  116. data/lib/jekyll_picture_tag/cache/base.rb +0 -59
  117. data/lib/jekyll_picture_tag/cache/generated.rb +0 -20
  118. data/lib/jekyll_picture_tag/cache/source.rb +0 -19
  119. data/lib/jekyll_picture_tag/defaults/global.yml +0 -11
  120. data/lib/jekyll_picture_tag/defaults/presets.yml +0 -11
  121. data/lib/jekyll_picture_tag/generated_image.rb +0 -140
  122. data/lib/jekyll_picture_tag/instructions/configuration.rb +0 -121
  123. data/lib/jekyll_picture_tag/instructions/preset.rb +0 -103
  124. data/lib/jekyll_picture_tag/instructions/set.rb +0 -71
@@ -0,0 +1,97 @@
1
+ ---
2
+ sort: 3
3
+ ---
4
+
5
+ # Tutorial
6
+
7
+ ## Hello, world!
8
+
9
+ Once you've followed the [installation](installation) instructions, it's a good
10
+ time to make sure we're set up correctly. Drop an image or two in the site root
11
+ (or `source` directory if you [configured it](configuration/directories)), pick
12
+ some page and write the following (substitute the image filename as
13
+ appropriate):
14
+
15
+ {% raw %}
16
+ ```
17
+ {% picture my_image.jpg %}
18
+ ```
19
+ {% endraw %}
20
+
21
+ Build/serve the site and check it out! Your image should be there, and if you inspect it with the
22
+ dev tools you should see an `<img>` tag with a `srcset` attribute. You're officially serving
23
+ responsive images.
24
+
25
+ ## Webp
26
+
27
+ JPT includes several built-in presets and media queries, documented in the
28
+ [examples](presets/examples). They're intended as a starting point and a learning tool, not for
29
+ production use. Don't dig to deeply into that link just yet, try them out first:
30
+
31
+ {% raw %}
32
+ ```
33
+ {% picture jpt-webp my_image.jpg %}
34
+ ```
35
+ {% endraw %}
36
+
37
+ Now instead of a lone `<img>` tag, you get a `<picture>` surrounding two `<source>`s and an `<img>`.
38
+ The first source contains webp images, and the second contains jpgs. Success! Lighthouse is happier
39
+ and happier.
40
+
41
+ ## Alt text
42
+
43
+ Good web developers add alt text. JPT makes this easy:
44
+
45
+ {% raw %}
46
+ ```
47
+ {% picture my_image.jpg --alt Happy Puppy %}
48
+ ```
49
+ {% endraw %}
50
+
51
+ ## Crop
52
+
53
+
54
+ {% raw %}
55
+ ```
56
+ {% picture my_image.jpg 16:9 %}
57
+ ```
58
+ {% endraw %}
59
+
60
+ Feeling cinematic? If you don't like how the image gets cropped, you can adjust it:
61
+
62
+ {% raw %}
63
+ ```
64
+ {% picture my_image.jpg 16:9 center %}
65
+ ```
66
+ {% endraw %}
67
+
68
+ Your options are `attention` (which is the default), `entropy`, and `center`.
69
+
70
+ ## Art Direction
71
+
72
+ (Usually means "Cropping, but only sometimes.")
73
+
74
+ Art direction is tricky to understand; I know it tripped me up for awhile when learning the subject.
75
+ Here's a short explanation, along with a demo: Let's pretend that we have some image which looks
76
+ good on desktop, but on a mobile screen it's hard to see the subject. Resolution isn't the problem,
77
+ the image just needs to be cropped for smaller screens. JPT makes this easy:
78
+
79
+ {% raw %}
80
+ ```
81
+ {% picture my_image.jpg 2:1 jpt-mobile: my_image.jpg 1:1 %}
82
+ ```
83
+ {% endraw %}
84
+
85
+ This tag is pretty complicated, so here's a breakdown in plain english:
86
+ * Use the default preset.
87
+ * use my_image.jpg as the base image.
88
+ * Crop it to a 2:1 aspect ratio.
89
+ * When the media query named 'jpt-mobile' is true, also use my_image.jpg
90
+ * but this time crop it square.
91
+
92
+ Now adjust the browser width. When skinny, you should see a square crop of your image, and when it's
93
+ wide you should see a 2:1 crop of the same image. That's art direction. Note that there's no
94
+ requirement at all for them to be the same image, and you don't have to use JPT to do the cropping.
95
+
96
+ There are several more liquid tag examples [here](liquid_tag/examples) that you may want to look
97
+ over, as well as the [liquid tag instructions](liquid_tag).
@@ -4,43 +4,58 @@ require 'jekyll_picture_tag/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'jekyll_picture_tag'
7
- spec.version = PictureTag::VERSION
8
7
  spec.authors = ['Robert Wierzbowski', 'Brendan Tobolaski',
9
8
  'Robert Buchberger']
10
9
  spec.email = ['robert@buchberger.cc']
11
-
10
+ spec.homepage = 'https://github.com/rbuchberger/jekyll_picture_tag'
11
+ spec.metadata = { 'documentation_uri' =>
12
+ 'https://rbuchberger.github.io/jekyll_picture_tag/' }
13
+ spec.license = 'BSD-3-Clause'
12
14
  spec.summary = 'Easy responsive images for Jekyll.'
13
15
  spec.description = <<-HEREDOC
14
- Jekyll Picture Tag is a liquid tag that adds responsive images to your
15
- Jekyll static site.Jekyll Picture Tag automatically creates resized source
16
- images, is fully configurable, and covers all use cases including art
17
- direction and resolution switching — with a little YAML configuration and a
18
- simple template tag.
16
+ Jekyll Picture Tag adds responsive images to your Jekyll static site. It
17
+ automatically creates resized source images, is fully configurable, and
18
+ covers all use cases, including art direction and resolution switching, with
19
+ a little YAML configuration and a simple template tag.
19
20
  HEREDOC
20
- spec.homepage = 'https://github.com/rbuchberger/jekyll_picture_tag'
21
- spec.license = 'BSD-3-Clause'
22
- spec.require_paths = ['lib']
23
21
 
22
+ spec.version = PictureTag::VERSION
23
+ spec.require_paths = ['lib']
24
24
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
- f.match(%r{^(test|spec|features)/})
25
+ f.match(%r{^(test)/})
26
26
  end
27
27
 
28
- spec.required_ruby_version = ['>= 2.5', '< 3']
28
+ spec.required_ruby_version = ['>= 2.6', '< 4.0']
29
+
30
+ # addressable is used to url-encode image filenames.
31
+ spec.add_runtime_dependency 'addressable', '~> 2.6'
32
+ # Jekyll versions older than 4.0 are not supported.
33
+ spec.add_runtime_dependency 'jekyll', '~> 4.0'
34
+ # MIME types are needed for <source> tags' type= attributes.
35
+ spec.add_runtime_dependency 'mime-types', '~> 3.0'
36
+ # objective_elements handles HTML generation.
37
+ spec.add_runtime_dependency 'objective_elements', '~> 1.1'
38
+ # rainbow is used to colorize terminal output.
39
+ spec.add_runtime_dependency 'rainbow', '~> 3.0'
40
+ # ruby-vips interfaces with libvips.
41
+ spec.add_runtime_dependency 'ruby-vips', '~> 2.0.17'
29
42
 
43
+ # libvips handles all image processing operations.
44
+ spec.requirements << 'libvips'
45
+
46
+ # Development dependencies are not installed when using this gem. You can
47
+ # ignore these, unless you are working on JPT itself.
30
48
  spec.add_development_dependency 'bundler', '~> 2.0'
31
- spec.add_development_dependency 'minitest', '~> 5.11'
49
+ spec.add_development_dependency 'minitest', '~> 5.14'
50
+ spec.add_development_dependency 'minitest-rg'
32
51
  spec.add_development_dependency 'mocha', '~> 1.9'
33
- spec.add_development_dependency 'nokogiri', '~> 1.10'
52
+ spec.add_development_dependency 'nokogiri', '~> 1.1'
34
53
  spec.add_development_dependency 'pry'
35
54
  spec.add_development_dependency 'rake', '~> 12.3'
36
- spec.add_development_dependency 'rubocop'
37
- spec.add_development_dependency 'simplecov'
55
+ spec.add_development_dependency 'rubocop', '~> 1.7.0'
56
+ spec.add_development_dependency 'rubocop-minitest', '~> 0.10.0'
57
+ spec.add_development_dependency 'rubocop-performance', '~> 1.9.0'
58
+ spec.add_development_dependency 'rubocop-rake', '~> 0.5.0'
59
+ spec.add_development_dependency 'simplecov', '~> 0.20.0'
38
60
  spec.add_development_dependency 'solargraph'
39
-
40
- spec.add_dependency 'addressable', '~> 2.6'
41
- spec.add_dependency 'mime-types', '~> 3'
42
- spec.add_dependency 'mini_magick', '~> 4'
43
- spec.add_dependency 'objective_elements', '~> 1.1.2'
44
-
45
- spec.add_runtime_dependency 'jekyll', '< 5'
46
61
  end
@@ -1,15 +1,16 @@
1
1
  require 'jekyll'
2
2
  require 'objective_elements'
3
3
 
4
- require_relative 'jekyll_picture_tag/generated_image'
4
+ require_relative 'jekyll_picture_tag/cache'
5
+ require_relative 'jekyll_picture_tag/images'
5
6
  require_relative 'jekyll_picture_tag/instructions'
6
7
  require_relative 'jekyll_picture_tag/output_formats'
7
- require_relative 'jekyll_picture_tag/source_image'
8
+ require_relative 'jekyll_picture_tag/parsers'
9
+ require_relative 'jekyll_picture_tag/router'
8
10
  require_relative 'jekyll_picture_tag/srcsets'
9
11
  require_relative 'jekyll_picture_tag/utils'
10
- require_relative 'jekyll_picture_tag/img_uri'
11
- require_relative 'jekyll_picture_tag/router'
12
- require_relative 'jekyll_picture_tag/cache'
12
+ require_relative 'jekyll_picture_tag/defaults/presets'
13
+ require_relative 'jekyll_picture_tag/defaults/global'
13
14
 
14
15
  # Title: Jekyll Picture Tag
15
16
  # Authors: Rob Wierzbowski : @robwierzbowski
@@ -62,7 +63,9 @@ module PictureTag
62
63
  def render(context)
63
64
  setup(context)
64
65
 
65
- if PictureTag.disabled?
66
+ if PictureTag.disabled? || PictureTag.raw_params.empty?
67
+ Utils.warning 'You have called JPT without any arguments.'
68
+
66
69
  ''
67
70
  else
68
71
  PictureTag.output_class.new.to_s
@@ -72,11 +75,9 @@ module PictureTag
72
75
  private
73
76
 
74
77
  def setup(context)
78
+ PictureTag.clear_instructions
75
79
  PictureTag.context = context
76
-
77
- # Now that we have both the tag parameters and the context object, we can
78
- # build our instruction set.
79
- PictureTag.instructions = Instructions::Set.new(@raw_params)
80
+ PictureTag.raw_params = @raw_params
80
81
 
81
82
  # We need to explicitly prevent jekyll from overwriting our generated
82
83
  # image files:
@@ -1,3 +1,64 @@
1
- require_relative 'cache/base'
2
- require_relative 'cache/source'
3
- require_relative 'cache/generated'
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,4 @@
1
+ require_relative 'images/image_file'
2
+ require_relative 'images/generated_image'
3
+ require_relative 'images/img_uri'
4
+ require_relative 'images/source_image'
@@ -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