jekyll_picture_tag 1.7.0 → 1.10.1

Sign up to get free protection for your applications and to get access to all the features.
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.