jekyll_picture_tag 1.7.0 → 1.10.1

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.solargraph.yml +15 -0
  4. data/.travis.yml +4 -7
  5. data/Dockerfile +9 -0
  6. data/docs/Gemfile +4 -0
  7. data/docs/Gemfile.lock +249 -0
  8. data/docs/_config.yml +13 -0
  9. data/docs/_layouts/directory.html +32 -0
  10. data/docs/assets/style.css +31 -0
  11. data/{contributing.md → docs/contributing.md} +57 -15
  12. data/docs/{examples/_data/picture.yml → example_presets.md} +36 -25
  13. data/docs/global_configuration.md +61 -3
  14. data/docs/index.md +114 -0
  15. data/docs/installation.md +36 -21
  16. data/docs/migration.md +4 -0
  17. data/docs/notes.md +64 -58
  18. data/docs/output.md +63 -0
  19. data/docs/presets.md +175 -221
  20. data/docs/releases.md +64 -0
  21. data/docs/usage.md +91 -79
  22. data/jekyll_picture_tag.gemspec +3 -1
  23. data/lib/jekyll_picture_tag.rb +27 -10
  24. data/lib/jekyll_picture_tag/defaults/global.yml +2 -0
  25. data/lib/jekyll_picture_tag/defaults/presets.yml +2 -0
  26. data/lib/jekyll_picture_tag/generated_image.rb +105 -19
  27. data/lib/jekyll_picture_tag/instructions.rb +1 -0
  28. data/lib/jekyll_picture_tag/instructions/arg_splitter.rb +68 -0
  29. data/lib/jekyll_picture_tag/instructions/configuration.rb +47 -11
  30. data/lib/jekyll_picture_tag/instructions/html_attributes.rb +14 -8
  31. data/lib/jekyll_picture_tag/instructions/preset.rb +34 -14
  32. data/lib/jekyll_picture_tag/instructions/set.rb +18 -8
  33. data/lib/jekyll_picture_tag/instructions/tag_parser.rb +59 -69
  34. data/lib/jekyll_picture_tag/output_formats/basic.rb +35 -6
  35. data/lib/jekyll_picture_tag/output_formats/data_attributes.rb +4 -1
  36. data/lib/jekyll_picture_tag/router.rb +16 -0
  37. data/lib/jekyll_picture_tag/source_image.rb +6 -1
  38. data/lib/jekyll_picture_tag/srcsets/basic.rb +45 -19
  39. data/lib/jekyll_picture_tag/srcsets/pixel_ratio.rb +1 -3
  40. data/lib/jekyll_picture_tag/srcsets/width.rb +1 -1
  41. data/lib/jekyll_picture_tag/utils.rb +18 -0
  42. data/lib/jekyll_picture_tag/version.rb +1 -1
  43. data/readme.md +43 -200
  44. metadata +49 -13
  45. data/docs/examples/_config.yml +0 -10
  46. data/docs/examples/post.md +0 -46
  47. data/docs/readme.md +0 -23
@@ -69,12 +69,30 @@ module PictureTag
69
69
  element.media = srcset.media_attribute if srcset.media
70
70
  end
71
71
 
72
- # File, not HTML
72
+ # GeneratedImage class, not HTML
73
73
  def build_fallback_image
74
+ return fallback_candidate if fallback_candidate.exists?
75
+
76
+ build_new_fallback_image
77
+ end
78
+
79
+ def fallback_candidate
80
+ @fallback_candidate ||= GeneratedImage.new(
81
+ source_file: PictureTag.source_images.first,
82
+ format: PictureTag.fallback_format,
83
+ width: PictureTag.fallback_width,
84
+ crop: PictureTag.crop,
85
+ gravity: PictureTag.gravity
86
+ )
87
+ end
88
+
89
+ def build_new_fallback_image
74
90
  GeneratedImage.new(
75
91
  source_file: PictureTag.source_images.first,
76
92
  format: PictureTag.fallback_format,
77
- width: checked_fallback_width
93
+ width: checked_fallback_width,
94
+ crop: PictureTag.crop,
95
+ gravity: PictureTag.gravity
78
96
  )
79
97
  end
80
98
 
@@ -95,15 +113,26 @@ module PictureTag
95
113
  content.add_parent anchor
96
114
  end
97
115
 
116
+ def source
117
+ PictureTag.source_images.first
118
+ end
119
+
120
+ def source_width
121
+ if PictureTag.crop
122
+ fallback_candidate.cropped_source_width
123
+ else
124
+ source.width
125
+ end
126
+ end
127
+
98
128
  def checked_fallback_width
99
- source = PictureTag.source_images.first
100
129
  target = PictureTag.fallback_width
101
130
 
102
- if target > source.width
131
+ if target > source_width
103
132
  Utils.warning "#{source.shortname} is smaller than the " \
104
- "requested fallback width of #{target}px. Using #{source.width}" \
133
+ "requested fallback width of #{target}px. Using #{source_width}" \
105
134
  ' px instead.'
106
- source.width
135
+ source_width
107
136
  else
108
137
  target
109
138
  end
@@ -18,7 +18,10 @@ module PictureTag
18
18
  end
19
19
 
20
20
  def add_sizes(element, srcset)
21
- element.attributes << { 'data-sizes' => srcset.sizes } if srcset.sizes
21
+ return unless srcset.sizes
22
+
23
+ attribute = PictureTag.preset['data_sizes'] ? 'data-sizes' : 'sizes'
24
+ element.attributes << { attribute => srcset.sizes }
22
25
  end
23
26
 
24
27
  def build_noscript(base_content)
@@ -47,6 +47,14 @@ module PictureTag
47
47
  @instructions.source_images
48
48
  end
49
49
 
50
+ def crop(media = nil)
51
+ @instructions.crop(media)
52
+ end
53
+
54
+ def gravity(media = nil)
55
+ @instructions.gravity(media)
56
+ end
57
+
50
58
  # Config Forwarding
51
59
 
52
60
  def source_dir
@@ -69,6 +77,14 @@ module PictureTag
69
77
  config.pconfig
70
78
  end
71
79
 
80
+ def disabled?
81
+ config.disabled?
82
+ end
83
+
84
+ def fast_build?
85
+ config.fast_build?
86
+ end
87
+
72
88
  # Preset forwarding
73
89
 
74
90
  def widths(media)
@@ -4,6 +4,7 @@ module PictureTag
4
4
  # to be reused by many different generated images.
5
5
  class SourceImage
6
6
  attr_reader :name, :shortname, :missing, :media_preset
7
+ attr_accessor :digest_guess
7
8
  include MiniMagick
8
9
 
9
10
  def initialize(relative_filename, media_preset = nil)
@@ -23,12 +24,16 @@ module PictureTag
23
24
  def digest
24
25
  @digest ||= if @missing
25
26
  'x' * 6
27
+ elsif PictureTag.fast_build? && @digest_guess
28
+ # Digest guess will be handed off to this class by the first
29
+ # generated image which needs it (via attr_accessor).
30
+ @digest_guess
26
31
  else
27
32
  Digest::MD5.hexdigest(File.read(@name))[0..5]
28
33
  end
29
34
  end
30
35
 
31
- # Includes path relative to default sorce folder, and the original filename.
36
+ # Includes path relative to default source folder and the original filename.
32
37
  def base_name
33
38
  @shortname.delete_suffix File.extname(@shortname)
34
39
  end
@@ -24,7 +24,7 @@ module PictureTag
24
24
  end
25
25
 
26
26
  def files
27
- @files ||= widths.collect { |w| generate_file(w) }
27
+ @files ||= build_files
28
28
  end
29
29
 
30
30
  def to_a
@@ -46,15 +46,6 @@ module PictureTag
46
46
  nil
47
47
  end
48
48
 
49
- # Check our source image size vs requested sizes
50
- def check_widths(targets)
51
- if targets.any? { |t| t > @source_image.width }
52
- handle_small_source(targets, @source_image.width)
53
- else
54
- targets
55
- end
56
- end
57
-
58
49
  # Generates an HTML attribute
59
50
  def media_attribute
60
51
  "(#{PictureTag.media_presets[@media]})"
@@ -62,24 +53,59 @@ module PictureTag
62
53
 
63
54
  private
64
55
 
65
- def handle_small_source(targets, image_width)
66
- Utils.warning(
67
- " #{@source_image.shortname} is #{image_width}px wide, smaller than" \
68
- " at least one size in the set #{targets}. Will not enlarge."
69
- )
56
+ def build_files
57
+ # By 'files', we mean the GeneratedImage class.
58
+ return target_files if target_files.all?(&:exists?)
59
+
60
+ # This triggers GeneratedImage to actually build an image file.
61
+ files = checked_targets
62
+ files.each(&:generate)
63
+
64
+ files
65
+ end
66
+
67
+ def checked_targets
68
+ if target_files.any? { |f| f.width > source_width }
70
69
 
71
- small_targets = targets.dup.delete_if { |t| t >= image_width }
70
+ small_source_warn
72
71
 
73
- small_targets.push image_width
72
+ files = target_files.reject { |f| f.width >= source_width }
73
+ files.push(generate_file(source_width))
74
+ end
75
+
76
+ files || target_files
77
+ end
78
+
79
+ def source_width
80
+ @source_width ||= if PictureTag.crop(@media)
81
+ target_files.first.cropped_source_width
82
+ else
83
+ @source_image.width
84
+ end
85
+ end
74
86
 
75
- small_targets
87
+ def target_files
88
+ @target_files ||= widths.collect { |w| generate_file(w) }
89
+ end
90
+
91
+ def small_source_warn
92
+ Utils.warning(
93
+ <<~HEREDOC
94
+ #{@source_image.shortname}
95
+ is #{source_width}px wide (after cropping, if applicable),
96
+ smaller than at least one size in the set #{widths}.
97
+ Will not enlarge.
98
+ HEREDOC
99
+ )
76
100
  end
77
101
 
78
102
  def generate_file(width)
79
103
  GeneratedImage.new(
80
104
  source_file: @source_image,
81
105
  width: width,
82
- format: @input_format
106
+ format: @input_format,
107
+ crop: PictureTag.crop(@media),
108
+ gravity: PictureTag.gravity(@media)
83
109
  )
84
110
  end
85
111
  end
@@ -6,11 +6,9 @@ module PictureTag
6
6
  private
7
7
 
8
8
  def widths
9
- target = PictureTag.preset['pixel_ratios'].collect do |p|
9
+ PictureTag.preset['pixel_ratios'].collect do |p|
10
10
  p * PictureTag.preset['base_width']
11
11
  end
12
-
13
- check_widths target
14
12
  end
15
13
 
16
14
  def build_srcset_entry(file)
@@ -22,7 +22,7 @@ module PictureTag
22
22
  private
23
23
 
24
24
  def widths
25
- check_widths PictureTag.widths(@media)
25
+ PictureTag.widths(@media)
26
26
  end
27
27
 
28
28
  def build_srcset_entry(file)
@@ -2,6 +2,24 @@ module PictureTag
2
2
  # This is a little module to hold logic that doesn't fit other places. If it
3
3
  # starts getting big, refactor.
4
4
  module Utils
5
+ # These are valid ImageMagick gravity arguments (relevant to our use
6
+ # case):
7
+ GRAVITIES =
8
+ %w[center
9
+ north
10
+ northeast
11
+ east
12
+ southeast
13
+ south
14
+ southwest
15
+ west
16
+ northwest].freeze
17
+
18
+ # This is an attempt to recognize valid imagemagick geometry arguments
19
+ # with regex. It only tries to match values which don't preserve aspect
20
+ # ratio, as they're the ones people might actually need here.
21
+ GEOMETRY_REGEX = /\A\d*%?[x:]?\d*[%!]?([+-]\d+){,2}\Z/i.freeze
22
+
5
23
  class << self
6
24
  # Configure Jekyll to keep our generated files
7
25
  def keep_files
@@ -1,3 +1,3 @@
1
1
  module PictureTag
2
- VERSION = '1.7.0'.freeze
2
+ VERSION = '1.10.1'.freeze
3
3
  end
data/readme.md CHANGED
@@ -1,216 +1,59 @@
1
1
  # Jekyll Picture Tag
2
2
 
3
- **Easy responsive images for Jekyll.**
3
+ **Responsive Images done correctly.**
4
4
 
5
- It's easy to throw an image on a webpage and call it a day. Doing justice to your users by serving
6
- it efficiently on all browsers and screen sizes is tedious and tricky. Tedious, tricky things should be
7
- automated.
5
+ It's simple to throw a photo on a page and call it a day, but doing justice to users on all
6
+ different browsers and devices is tedious and tricky. Tedious, tricky things should be automated.
8
7
 
9
- Jekyll Picture Tag is a liquid tag that adds responsive images to your [Jekyll](http://jekyllrb.com)
10
- static site. It automatically creates resized, reformatted source images, is fully configurable,
11
- implements sensible defaults, and solves both the art direction and resolution switching problems,
12
- with a little YAML configuration and a simple template tag. It offers several different output
13
- formats, and can be configured to work with JavaScript libraries such as
14
- [LazyLoad](https://github.com/verlok/lazyload).
8
+ Jekyll Picture Tag automatically builds cropped, resized, and reformatted images, builds several
9
+ kinds of markup, offers extensive configuration while requiring none, and solves both the art
10
+ direction and resolution switching problems with a little YAML configuration and a simple template
11
+ tag.
15
12
 
16
- ## Documentation
13
+ ## Why use Responsive Images?
17
14
 
18
- It's all in the [`docs`](docs/) folder:
15
+ **Performance:** The fastest sites are static sites, but if you plonk a 2mb picture of your dog at
16
+ the top of a blog post you throw it all away. Responsive images allow you to keep your site fast,
17
+ without compromising image quality.
19
18
 
20
- * [Installation](docs/installation.md)
21
- * [Usage](docs/usage.md)
22
- * [Global settings](docs/global_configuration.md)
23
- * [Presets](docs/presets.md)
24
- * [Other notes](docs/notes.md)
25
- * [Contribute](contributing.md)
26
- * [Release History](#release-history)
27
- * [License](LICENSE.txt)
19
+ **Design:** Your desktop image may not work well on mobile, regardless of its resolution. We often
20
+ want to do more than just resize images for different screen sizes, we want to crop them or use a
21
+ different image entirely.
28
22
 
29
23
  ## Why use Jekyll Picture Tag?
30
24
 
31
- **Performance:** The fastest sites are static sites, but when you plonk a 2mb picture of your dog at
32
- the top of a blog post you're throwing it all away.
25
+ **Developer Sanity:** If you want to serve multiple images in multiple formats and resolutions, you
26
+ have a litany of markup to write and a big pile of images to generate and organize. Jekyll Picture
27
+ Tag is your responsive images minion - give it simple instructions and it'll handle the rest.
33
28
 
34
- **Design:** Your desktop image may not work well on mobile, regardless of its resolution. We often
35
- want to do more than just resize images for different screen sizes, we want to crop them or use a
36
- different image entirely.
29
+ ## Features
37
30
 
38
- **Developer Sanity:** Image downloading starts before the browser has parsed your CSS and
39
- JavaScript; this gets them on the page *fast*, but it leads to some ridiculously verbose markup.
40
- To serve responsive images correctly, we must:
31
+ * Generate piles of cropped, resized, and converted image files.
32
+ * Generate corresponding markup in several different formats.
33
+ * Configure it easily, or not at all.
34
+ * Make Lighthouse happy.
41
35
 
42
- - Generate, name, and organize the required images (formats \* resolutions \* source images)
43
- - Inform the browser about the image itself-- format, size, URI, and the screen sizes where it
44
- should be used.
45
- - Inform the browser how large the space for that image on the page will be (which also probably
46
- has associated media queries).
36
+ ## Documentation:
47
37
 
48
- It's a lot. It's tedious and complicated. Jekyll Picture Tag makes it easy.
38
+ https://rbuchberger.github.io/jekyll_picture_tag/
49
39
 
50
- ## Features
40
+ ## Changelog:
41
+
42
+ https://rbuchberger.github.io/jekyll_picture_tag/releases
43
+
44
+ Latest versions:
45
+
46
+ * 1.10.0 May 11, 2020
47
+ * **Image Cropping support!** access the power of ImageMagick's `crop` function.
48
+ * Don't issue a warning when `default` preset is not found.
49
+ * Documentation improvements
50
+ * 1.10.1 July 2, 2020
51
+ * Bugfix for erroneously regenerated images
52
+
53
+ ## Help Wanted
51
54
 
52
- * Automatic generation of resized, converted image files.
53
- * Automatic generation of complex markup in several different formats.
54
- * No configuration required, extensive configuration available.
55
- * `sizes` attribute assistance.
56
- * Optionally, automatically link to the source image. Or manually link to anywhere else, with just a
57
- tag parameter!
58
-
59
- ## Quick start / Demo
60
-
61
- **All configuration is optional.** Here's the simplest possible use case:
62
-
63
- Add j_p_t to your gemfile:
64
-
65
- ```ruby
66
- group :jekyll_plugins do
67
- gem 'jekyll_picture_tag'
68
- end
69
- ```
70
-
71
- Run `bundle install`
72
-
73
- Put this liquid tag somewhere:
74
-
75
- `{% picture test.jpg %}`
76
-
77
- Get this in your generated site:
78
-
79
- ```html
80
- <!-- Formatted for readability -->
81
-
82
- <img src="/generated/test-800-195f7d.jpg"
83
- srcset="
84
- /generated/test-400-195f7d.jpg 400w,
85
- /generated/test-600-195f7d.jpg 600w,
86
- /generated/test-800-195f7d.jpg 800w,
87
- /generated/test-1000-195f7d.jpg 1000w
88
- ">
89
- ```
90
-
91
- ### Look man, that's cool and all but I just want webp.
92
-
93
- Create `_data/picture.yml`, add the following:
94
-
95
- ```yml
96
- markup_presets:
97
- default:
98
- formats: [webp, original]
99
- ```
100
-
101
- If you get errors, make sure you have imagemagick installed with a webp delegate.
102
-
103
- ### Here's a more complex example:
104
-
105
- ```yml
106
- # _data/picture.yml
107
-
108
- media_presets:
109
- mobile: 'max-width: 600px'
110
-
111
- markup_presets:
112
- default:
113
- widths: [600, 900, 1200]
114
- formats: [webp, original]
115
- sizes:
116
- mobile: 80vw
117
- size: 500px
118
- ```
119
-
120
- Write this:
121
-
122
- `{% picture test.jpg mobile: test2.jpg --alt Alternate Text %}`
123
-
124
- Get this:
125
-
126
- ```html
127
- <!-- Formatted for readability -->
128
-
129
- <picture>
130
- <source
131
- sizes="(max-width: 600px) 80vw, 600px"
132
- media="(max-width: 600px)"
133
- srcset="
134
- /generated/test2-600-21bb6f.webp 600w,
135
- /generated/test2-900-21bb6f.webp 900w,
136
- /generated/test2-1200-21bb6f.webp 1200w
137
- "
138
- type="image/webp">
139
- <source
140
- sizes="(max-width: 600px) 80vw, 600px"
141
- srcset="
142
- /generated/test-600-195f7d.webp 600w,
143
- /generated/test-900-195f7d.webp 900w,
144
- /generated/test-1200-195f7d.webp 1200w
145
- "
146
- type="image/webp">
147
- <source
148
- sizes="(max-width: 600px) 80vw, 600px"
149
- media="(max-width: 600px)"
150
- srcset="
151
- /generated/test2-600-21bb6f.jpg 600w,
152
- /generated/test2-900-21bb6f.jpg 900w,
153
- /generated/test2-1200-21bb6f.jpg 1200w
154
- "
155
- type="image/jpeg">
156
- <source
157
- sizes="(max-width: 600px) 80vw, 600px"
158
- srcset="
159
- /generated/test-600-195f7d.jpg 600w,
160
- /generated/test-900-195f7d.jpg 900w,
161
- /generated/test-1200-195f7d.jpg 1200w
162
- "
163
- type="image/jpeg">
164
- <img src="/generated/test-800-195f7d.jpg" alt="Alternate Text">
165
- </picture>
166
- ```
167
-
168
- Jekyll Picture Tag ultimately relies on [ImageMagick](https://www.imagemagick.org/script/index.php)
169
- for image conversions, so it must be installed on your system. There's a very good chance you
170
- already have it. If you want to build webp images, you will need to install a webp delegate for it
171
- as well.
172
-
173
- ## Release History
174
-
175
- * 1.7.0 Aug 12, 2019
176
- * Add support for setting generated image quality, either generally or specific to given
177
- formats.
178
- * Add support for spaces and other url-encoded characters in filenames
179
- * Documentation restructure - Moved it out of the wiki, into the `docs` folder.
180
- * Bugfix: Fallback image width will now be checked against source image width.
181
- * Bugfix: Minor fix to nomarkdown wrapper output
182
- * link_source will now target the base source image, rather than finding the biggest one.
183
- * Remove fastimage dependency, add addressable dependency.
184
- * Moderately significant refactoring and code cleanup
185
- * Decent set of tests added
186
- * 1.6.0 Jul 2, 2019:
187
- * Missing Preset warning respects `data_dir` setting
188
- * Add `continue_on_missing` option
189
- * 1.5.0 Jun 26, 2019:
190
- * better `{::nomarkdown}` necessity detection
191
- * allow user to override `{::nomarkdown}` autodetection
192
- * 1.4.0 Jun 26, 2019:
193
- * Rename gem from `jekyll-picture-tag` to `jekyll_picture_tag`, allowing us to use rubygems again.
194
- * Add new output format: `naked_srcset`.
195
- * 1.3.1 Jun 21, 2019: Bugfix
196
- * 1.3.0 Jun 7, 2019:
197
- * Initial compatibility with Jekyll 4.0
198
- * bugfixes
199
- * change to generated image naming-- The first build after this update will be longer, and you
200
- might want to clear out your generated images.
201
- * 1.2.0 Feb 9, 2019:
202
- * Add nomarkdown fix
203
- * noscript option
204
- * relative url option
205
- * anchor tag wrappers
206
- * 1.1.0 Jan 22, 2019:
207
- * Add direct_url markup format,
208
- * auto-orient images before stripping metadata
209
- * 1.0.2 Jan 18, 2019: Fix ruby version specification
210
- * 1.0.1 Jan 13, 2019: Added ruby version checking
211
- * **1.0.0** Nov 27, 2018: Rewrite from the ground up. See the [migration guide](docs/migration.md).
212
- * 0.2.2 Aug 2, 2013: Bugfixes
213
- * 0.2.1 Jul 17, 2013: Refactor again, add Liquid parsing.
214
- * 0.2.0 Jul 14, 2013: Rewrite code base, bring in line with Jekyll Image Tag.
215
- * 0.1.1 Jul 5, 2013: Quick round of code improvements.
216
- * 0.1.0 Jul 5, 2013: Initial release.
55
+ Writing code is only part of the job; often the harder part is knowing what needs to be changed. Any
56
+ and all feedback is greatly appreciated, especially in regards to documentation. What are your pain
57
+ points? See the [contributing
58
+ guidelines](https://rbuchberger.github.io/jekyll_picture_tag/contributing), or the
59
+ [issues](https://github.com/rbuchberger/jekyll_picture_tag/issues) page for more.