jekyll_picture_tag 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abfaaaa312c42464c11595294a11c10848f810cb6c1c63ce085b73b557501f8f
4
- data.tar.gz: 31c075ac80ee1ee500999b4f54c05d1b0b29b4a13230a3f84914dc4b9a035325
3
+ metadata.gz: fa7bf95094ae98a78cd4ff1d40fd70d74378590d68a39273300ba216280a9794
4
+ data.tar.gz: 9e552372626ff7f1a54b8bacc902112b7cfd9c65ce01c6d8957fd411ff88a1ce
5
5
  SHA512:
6
- metadata.gz: 5372b24c10a7049e20f1e2546a2f20cb2c0714cd4f8f8482e7005f503f9b192fe00ad5b4e07599e715cb280dad366a4477d3dd85ad5fc82743ac24309bf1688b
7
- data.tar.gz: 66640daa48af3f8507a0d0675bd0fc6527a77c02401cdc06bc3ce967d946c61e53233a1a51b0e31812e5dbb462fb2cb37a42681e9b6fa1b00e31a9b7ea8763e0
6
+ metadata.gz: 8a7a4c78be31edc35758dc6fa5f5f90a0ba0bcc5801f3ebf570b13ba649d04f4b2df88472c8b583439b9e3888537e26f9eb3678a364abe5ef6d299a65b5fe216
7
+ data.tar.gz: aab45d2868253d91d82e8ce63b0fab117a394427bc6b4a5248cf395b5a29e29e9bddbcfcdb8e4a365e087d3bde93a06bedfc16a8c37b9bef71aac2479d4fd84f
@@ -65,7 +65,12 @@ picture:
65
65
 
66
66
  *Default:* `false`
67
67
 
68
- Normally, JPT will raise an error if a source image is missing, causing the entire site build to fail. This setting allows you to bypass this behavior and continue the build, either for certain build environments or all the time. I highly encourage you to set this to `development`, and set the jekyll build environment to `production` when you build for production so you don't shoot yourself in the foot (publish a site with broken images). You can read more about Jekyll environments [here](https://jekyllrb.com/docs/configuration/environments/).
68
+ Normally, JPT will raise an error if a source image is missing, causing the entire site build to
69
+ fail. This setting allows you to bypass this behavior and continue the build, either for certain
70
+ build environments or all the time. I highly encourage you to set this to `development`, and set
71
+ the jekyll build environment to `production` when you build for production so you don't shoot
72
+ yourself in the foot (publish a site with broken images). You can read more about Jekyll
73
+ environments [here](https://jekyllrb.com/docs/configuration/environments/).
69
74
 
70
75
  * **Use Relative Urls**
71
76
 
@@ -111,10 +116,58 @@ picture:
111
116
 
112
117
  *Example:* `nomarkdown: false`
113
118
 
114
- *Default*: `true`
119
+ *Default:* `true`
115
120
 
116
121
  Whether or not to surround j-p-t's output with a `{::nomarkdown}..{:/nomarkdown}` block when called
117
122
  from within a markdown file.
118
123
 
119
124
  This setting is overridden by the same setting in a preset. See [the notes]({{ site.baseurl
120
125
  }}/notes) for more detailed information.
126
+
127
+ * **Fast Build**
128
+
129
+ *Format:* `fast_build: (true|false|environment|array of environments)`
130
+
131
+ *Examples:*
132
+
133
+ - `fast_build: true`
134
+
135
+ - `fast_build: development`
136
+
137
+ - `fast_build: [development, staging]`
138
+
139
+ *Default:* `false`
140
+
141
+ Makes a tradeoff: Speeds repeated build times for sites with many images, by assuming that the
142
+ filename alone is enough to uniquely identify a source image. This doesn't speed up image
143
+ generation, just detection of whether or not it's necessary.
144
+
145
+ Ordinarily, JPT generates an MD5 hash for every source image, every site build. This ensures that
146
+ if you replace one image with another, but keep the filename the same, JPT will correctly generate
147
+ images for the new file. If you have many large images and/or limited hardware, this can take some
148
+ time and make the development process painful. Enable this setting to skip MD5 hash checking on
149
+ existing generated images (most of the time), and just assume that if the filename, format, and
150
+ width match then it's the right one. If there are multiple possible matches (resulting from
151
+ leftover generated images from previous filename replacements), it'll compute a hash instead of
152
+ guessing randomly.
153
+
154
+ * **Disable Jekyll Picture Tag**
155
+
156
+ *Format:* `disabled: (true|false|environment|array of environments)`
157
+
158
+ *Examples:*
159
+
160
+ - `disabled: true`
161
+
162
+ - `disabled: development`
163
+
164
+ - `disabled: [development, staging]`
165
+
166
+ *Default:* `false`
167
+
168
+ Disable image and markup generation entirely. Useful for debugging, or to speed up site builds
169
+ when you're working on something else.
170
+
171
+ Hint: If you're going to toggle this on and off frequently, you might just use an environment
172
+ variable. Set this to something like `nopics`, and then start the Jekyll server with something
173
+ like `JEKYLL_ENV=nopics bundle exec jekyll serve` when you don't want image generation.
@@ -2,6 +2,13 @@
2
2
  ---
3
3
  # Release History
4
4
 
5
+ * 1.9.0 Feb 2, 2020
6
+ * Add `fast_build` global setting
7
+ * Add `disabled` global setting
8
+ * Reduce unnecessary disk IO; sites with many source images should see build times improve when
9
+ no new images need to be generated.
10
+ * Add support for empty attributes; specifically so best-practice for decorative images (`alt=""`)
11
+ is possible.
5
12
  * 1.8.0 Nov 25, 2019
6
13
  * Add `data_sizes` setting for the `data_` family of output formats.
7
14
  * 1.7.1 Nov 14, 2019
@@ -18,9 +18,9 @@ require_relative 'jekyll_picture_tag/router'
18
18
  #
19
19
  # Description: Easy responsive images for Jekyll.
20
20
  #
21
- # Download: https://github.com/rbuchberger/jekyll_picture_tag
22
- # Documentation: https://github.com/rbuchberger/jekyll_picture_tag/readme.md
23
- # Issues: https://github.com/rbuchberger/jekyll_picture_tag/issues
21
+ # Download: https://rubygems.org/gems/jekyll_picture_tag
22
+ # Documentation: https://rbuchberger.github.io/jekyll_picture_tag/
23
+ # Issues: https://github.com/rbuchberger/jekyll_picture_tag/
24
24
  #
25
25
  # Syntax:
26
26
  # {% picture [preset] img.jpg [media_query: alt-img.jpg] [attributes] %}
@@ -39,30 +39,47 @@ require_relative 'jekyll_picture_tag/router'
39
39
  #
40
40
  # See the documentation for full configuration and usage instructions.
41
41
  module PictureTag
42
+ # The router module is important. If you're looking for the actual code which
43
+ # handles a `PictureTag.(some method)`, start there.
42
44
  extend Router
45
+
43
46
  ROOT_PATH = __dir__
44
47
 
45
48
  # This is the actual liquid tag, which provides the interface with Jekyll.
46
49
  class Picture < Liquid::Tag
50
+ # First jekyll initializes our class with a few arguments, of which we only
51
+ # care about the params (arguments passed to the liquid tag). Jekyll makes
52
+ # no attempt to parse them; they're given as a string.
47
53
  def initialize(tag_name, raw_params, tokens)
48
54
  @raw_params = raw_params
49
55
  super
50
56
  end
51
57
 
58
+ # Then jekyll calls the 'render' method and passes it a mostly undocumented
59
+ # context object, which appears to hold the entire site including its
60
+ # configuration and the parsed _data dir.
52
61
  def render(context)
53
- # Jekyll passes in a mostly undocumented context object, which appears to
54
- # hold the entire site, including configuration and the _data dir.
62
+ setup(context)
63
+
64
+ if PictureTag.disabled?
65
+ ''
66
+ else
67
+ PictureTag.output_class.new.to_s
68
+ end
69
+ end
70
+
71
+ private
72
+
73
+ def setup(context)
55
74
  PictureTag.context = context
56
75
 
57
- # The instruction set depends on both the context and the tag parameters:
76
+ # Now that we have both the tag parameters and the context object, we can
77
+ # build our instruction set.
58
78
  PictureTag.instructions = Instructions::Set.new(@raw_params)
59
79
 
60
80
  # We need to explicitly prevent jekyll from overwriting our generated
61
- # files:
81
+ # image files:
62
82
  Utils.keep_files
63
-
64
- # Return a string:
65
- PictureTag.output_class.new.to_s
66
83
  end
67
84
  end
68
85
  end
@@ -7,3 +7,5 @@ picture:
7
7
  cdn_environments: ['production']
8
8
  nomarkdown: true
9
9
  ignore_missing_images: false
10
+ disabled: false
11
+ fast_build: false
@@ -1,8 +1,7 @@
1
1
  require 'mini_magick'
2
2
 
3
3
  module PictureTag
4
- # Generated Image
5
- # Represents a generated source file.
4
+ # Represents a generated image file.
6
5
  class GeneratedImage
7
6
  attr_reader :width, :format
8
7
  include MiniMagick
@@ -11,28 +10,90 @@ module PictureTag
11
10
  @source = source_file
12
11
  @width = width
13
12
  @format = process_format format
13
+ end
14
14
 
15
- generate_image unless File.exist?(absolute_filename) || @source.missing
15
+ def exists?
16
+ File.exist?(absolute_filename)
16
17
  end
17
18
 
18
- def name
19
- "#{@source.base_name}-#{@width}-#{@source.digest}.#{@format}"
19
+ def generate
20
+ generate_image unless @source.missing || exists?
20
21
  end
21
22
 
23
+ # /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
24
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22
25
  def absolute_filename
23
26
  @absolute_filename ||= File.join(PictureTag.dest_dir, name)
24
27
  end
25
28
 
29
+ # /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
30
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31
+ def name
32
+ name_left + digest + name_right
33
+ end
34
+
35
+ # https://example.com/assets/images/myimage-100-123abc.jpg
36
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26
37
  def uri
27
38
  ImgURI.new(name).to_s
28
39
  end
29
40
 
30
41
  private
31
42
 
43
+ # /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
44
+ # ^^^^^^^^^^^^^^^^^^^^^^^
45
+ def name_left
46
+ "#{@source.base_name}-#{@width}-"
47
+ end
48
+
49
+ # /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
50
+ # ^^^^^^
51
+ def digest
52
+ guess_digest if !@source.digest_guess && PictureTag.fast_build?
53
+
54
+ @source.digest
55
+ end
56
+
57
+ # /home/dave/my_blog/_site/generated/somefolder/myimage-100-123abc.jpg
58
+ # ^^^^
59
+ def name_right
60
+ '.' + @format
61
+ end
62
+
63
+ # Used for the fast build option: look for a file which matches everything
64
+ # we know about the destination file without calculating a digest on the
65
+ # source file, and if it exists we assume it's the right one.
66
+ def guess_digest
67
+ matches = dest_glob
68
+ return unless matches.length == 1
69
+
70
+ # Start and finish of the destination image's hash value
71
+ finish = -name_right.length
72
+ start = finish - 6
73
+
74
+ # The source image keeps track of this guess, so we hand it off:
75
+ @source.digest_guess = matches.first[start...finish]
76
+ end
77
+
78
+ # Returns a list of images which are probably correct.
79
+ def dest_glob
80
+ Dir.glob File.join(PictureTag.dest_dir, name_left + '?' * 6 + name_right)
81
+ end
82
+
32
83
  def image
33
84
  @image ||= Image.open(@source.name)
34
85
  end
35
86
 
87
+ def dest_dir
88
+ File.dirname absolute_filename
89
+ end
90
+
91
+ def generate_image
92
+ puts 'Generating new image file: ' + name
93
+ process_image
94
+ write_image
95
+ end
96
+
36
97
  def process_image
37
98
  image.combine_options do |i|
38
99
  i.resize "#{@width}x"
@@ -44,12 +105,6 @@ module PictureTag
44
105
  image.quality PictureTag.quality(@format)
45
106
  end
46
107
 
47
- def generate_image
48
- puts 'Generating new image file: ' + name
49
- process_image
50
- write_image
51
- end
52
-
53
108
  def write_image
54
109
  check_dest_dir
55
110
 
@@ -60,8 +115,7 @@ module PictureTag
60
115
 
61
116
  # Make sure destination directory exists
62
117
  def check_dest_dir
63
- dir = File.dirname absolute_filename
64
- FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
118
+ FileUtils.mkdir_p(dest_dir) unless Dir.exist?(dest_dir)
65
119
  end
66
120
 
67
121
  def process_format(format)
@@ -38,28 +38,64 @@ module PictureTag
38
38
  end
39
39
 
40
40
  def continue_on_missing?
41
- setting = pconfig['ignore_missing_images']
42
-
43
- # Config setting can be a string, an array, or a boolean
44
- if setting.is_a? Array
45
- setting.include? jekyll_env
46
- elsif setting.is_a? String
47
- setting == jekyll_env
48
- else
49
- setting
50
- end
41
+ env_check pconfig['ignore_missing_images']
42
+ rescue ArgumentError
43
+ raise ArgumentError,
44
+ <<~HEREDOC
45
+ continue_on_missing setting invalid. Must be either a boolean
46
+ (true/false), an environment name, or an array of environment
47
+ names.
48
+ HEREDOC
51
49
  end
52
50
 
53
51
  def cdn?
54
52
  pconfig['cdn_url'] && pconfig['cdn_environments'].include?(jekyll_env)
55
53
  end
56
54
 
55
+ def disabled?
56
+ env_check pconfig['disabled']
57
+ rescue ArgumentError
58
+ raise ArgumentError,
59
+ <<~HEREDOC
60
+ "disabled" setting invalid. Must be either a boolean
61
+ (true/false), an environment name, or an array of environment
62
+ names.
63
+ HEREDOC
64
+ end
65
+
66
+ def fast_build?
67
+ env_check pconfig['fast_build']
68
+ rescue ArgumentError
69
+ raise ArgumentError,
70
+ <<~HEREDOC
71
+ "fast_build" setting invalid. Must be either a boolean
72
+ (true/false), an environment name, or an array of environment
73
+ names.
74
+ HEREDOC
75
+ end
76
+
57
77
  private
58
78
 
59
79
  def content
60
80
  @content ||= setting_merge(defaults, PictureTag.site.config)
61
81
  end
62
82
 
83
+ # There are a few config settings which can either be booleans,
84
+ # environment names, or arrays of environment names. This method works it
85
+ # out and returns a boolean.
86
+ def env_check(setting)
87
+ if setting.is_a? Array
88
+ setting.include? jekyll_env
89
+ elsif setting.is_a? String
90
+ setting == jekyll_env
91
+ elsif [true, false].include? setting
92
+ setting
93
+ else
94
+ raise ArgumentError,
95
+ "#{setting} must either be a string, an array, or a boolean."
96
+ end
97
+ end
98
+
63
99
  def setting_merge(default, jekyll)
64
100
  jekyll.merge default do |_key, config_setting, default_setting|
65
101
  if default_setting.respond_to? :merge
@@ -69,8 +69,20 @@ 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
+ fallback = GeneratedImage.new(
75
+ source_file: PictureTag.source_images.first,
76
+ format: PictureTag.fallback_format,
77
+ width: PictureTag.fallback_width
78
+ )
79
+
80
+ return fallback if fallback.exists?
81
+
82
+ build_new_fallback_image
83
+ end
84
+
85
+ def build_new_fallback_image
74
86
  GeneratedImage.new(
75
87
  source_file: PictureTag.source_images.first,
76
88
  format: PictureTag.fallback_format,
@@ -69,6 +69,14 @@ module PictureTag
69
69
  config.pconfig
70
70
  end
71
71
 
72
+ def disabled?
73
+ config.disabled?
74
+ end
75
+
76
+ def fast_build?
77
+ config.fast_build?
78
+ end
79
+
72
80
  # Preset forwarding
73
81
 
74
82
  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,17 +53,39 @@ 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
70
66
 
71
- small_targets = targets.dup.delete_if { |t| t >= image_width }
67
+ def checked_targets
68
+ if target_files.any? { |f| f.width > @source_image.width }
72
69
 
73
- small_targets.push image_width
70
+ small_source_warn
74
71
 
75
- small_targets
72
+ files = target_files.reject { |f| f.width >= @source_image.width }
73
+ files.push(generate_file(@source_image.width))
74
+ end
75
+
76
+ files || target_files
77
+ end
78
+
79
+ def target_files
80
+ @target_files ||= widths.collect { |w| generate_file(w) }
81
+ end
82
+
83
+ def small_source_warn
84
+ Utils.warning(
85
+ " #{@source_image.shortname} is #{@source_image.width}px wide,"\
86
+ " smaller than at least one size in the set #{widths}. Will not"\
87
+ ' enlarge.'
88
+ )
76
89
  end
77
90
 
78
91
  def generate_file(width)
@@ -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)
@@ -1,3 +1,3 @@
1
1
  module PictureTag
2
- VERSION = '1.8.0'.freeze
2
+ VERSION = '1.9.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll_picture_tag
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Wierzbowski
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-11-25 00:00:00.000000000 Z
13
+ date: 2020-02-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler