jekyll-picture-tag-latest 1.3.0
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/examples/_config.yml +4 -0
- data/examples/_data/picture.yml +85 -0
- data/examples/post.md +18 -0
- data/jekyll-picture-tag-latest.gemspec +40 -0
- data/lib/jekyll-picture-tag.rb +67 -0
- data/lib/jekyll-picture-tag/defaults/global.yml +11 -0
- data/lib/jekyll-picture-tag/defaults/presets.yml +7 -0
- data/lib/jekyll-picture-tag/generated_image.rb +68 -0
- data/lib/jekyll-picture-tag/instructions.rb +105 -0
- data/lib/jekyll-picture-tag/instructions/configuration.rb +117 -0
- data/lib/jekyll-picture-tag/instructions/html_attributes.rb +59 -0
- data/lib/jekyll-picture-tag/instructions/preset.rb +61 -0
- data/lib/jekyll-picture-tag/instructions/tag_parser.rb +48 -0
- data/lib/jekyll-picture-tag/output_formats.rb +9 -0
- data/lib/jekyll-picture-tag/output_formats/auto.rb +15 -0
- data/lib/jekyll-picture-tag/output_formats/basics.rb +105 -0
- data/lib/jekyll-picture-tag/output_formats/data_attributes.rb +44 -0
- data/lib/jekyll-picture-tag/output_formats/data_auto.rb +14 -0
- data/lib/jekyll-picture-tag/output_formats/data_img.rb +8 -0
- data/lib/jekyll-picture-tag/output_formats/data_picture.rb +8 -0
- data/lib/jekyll-picture-tag/output_formats/direct_url.rb +13 -0
- data/lib/jekyll-picture-tag/output_formats/img.rb +24 -0
- data/lib/jekyll-picture-tag/output_formats/picture.rb +66 -0
- data/lib/jekyll-picture-tag/source_image.rb +62 -0
- data/lib/jekyll-picture-tag/srcsets.rb +3 -0
- data/lib/jekyll-picture-tag/srcsets/basics.rb +78 -0
- data/lib/jekyll-picture-tag/srcsets/pixel_ratio.rb +32 -0
- data/lib/jekyll-picture-tag/srcsets/width.rb +45 -0
- data/lib/jekyll-picture-tag/utils.rb +67 -0
- data/lib/jekyll-picture-tag/version.rb +3 -0
- data/migration.md +178 -0
- data/readme.md +823 -0
- metadata +205 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# Similar to Auto, but sets data-src (and so on) instead of src
|
4
|
+
class DataAuto < Auto
|
5
|
+
def self.new
|
6
|
+
if PictureTag::Utils.count_srcsets > 1
|
7
|
+
DataPicture.new
|
8
|
+
else
|
9
|
+
DataImg.new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# Represents a bare url you can use in another context, such as a direct
|
4
|
+
# link, but keep the resizing functionality
|
5
|
+
class DirectUrl
|
6
|
+
include PictureTag::OutputFormats::Basics
|
7
|
+
|
8
|
+
def to_s
|
9
|
+
build_base_img.src
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# Represents a bare <img> tag with a srcset attribute.
|
4
|
+
# Used when <picture> is unnecessary.
|
5
|
+
class Img
|
6
|
+
include PictureTag::OutputFormats::Basics
|
7
|
+
|
8
|
+
def srcset
|
9
|
+
build_srcset(nil, PictureTag.preset['formats'].first)
|
10
|
+
end
|
11
|
+
|
12
|
+
def base_markup
|
13
|
+
img = build_base_img
|
14
|
+
|
15
|
+
add_srcset(img, srcset)
|
16
|
+
add_sizes(img, srcset)
|
17
|
+
|
18
|
+
img.attributes << PictureTag.html_attributes['parent']
|
19
|
+
|
20
|
+
img
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module OutputFormats
|
3
|
+
# Represents a <picture> tag, enclosing at least 2 <source> tags and an
|
4
|
+
# <img> tag.
|
5
|
+
class Picture
|
6
|
+
include Basics
|
7
|
+
|
8
|
+
def srcsets
|
9
|
+
sets = []
|
10
|
+
|
11
|
+
PictureTag.preset['formats'].each do |format|
|
12
|
+
# We have 2 dimensions here: formats, and source images. Formats are
|
13
|
+
# provided in the order they must be returned, source images are
|
14
|
+
# provided in the reverse (least to most preferable) and must be
|
15
|
+
# flipped. We'll use an intermediate value to accomplish this.
|
16
|
+
format_set = []
|
17
|
+
|
18
|
+
# Source images are defined in the tag params, and associated with
|
19
|
+
# media queries. The base (first provided) image has a key of nil.
|
20
|
+
PictureTag.source_images.each_key do |media|
|
21
|
+
format_set << build_srcset(media, format)
|
22
|
+
end
|
23
|
+
sets.concat format_set.reverse
|
24
|
+
end
|
25
|
+
|
26
|
+
sets
|
27
|
+
end
|
28
|
+
|
29
|
+
def build_sources
|
30
|
+
srcsets.collect { |s| build_source(s) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_source(srcset)
|
34
|
+
source = SingleTag.new(
|
35
|
+
'source',
|
36
|
+
attributes: PictureTag.html_attributes['source']
|
37
|
+
)
|
38
|
+
|
39
|
+
# Sizes will be the same for all sources. There's some redundant markup
|
40
|
+
# here, but I don't think it's worth the effort to prevent.
|
41
|
+
add_sizes(source, srcset)
|
42
|
+
add_media(source, srcset)
|
43
|
+
add_srcset(source, srcset)
|
44
|
+
|
45
|
+
source.type = srcset.mime_type
|
46
|
+
|
47
|
+
source
|
48
|
+
end
|
49
|
+
|
50
|
+
def base_markup
|
51
|
+
picture = DoubleTag.new(
|
52
|
+
'picture',
|
53
|
+
attributes: PictureTag.html_attributes['picture'],
|
54
|
+
content: build_sources << build_base_img,
|
55
|
+
|
56
|
+
# Markdown fix requires removal of line breaks:
|
57
|
+
oneline: PictureTag.nomarkdown?
|
58
|
+
)
|
59
|
+
|
60
|
+
picture.attributes << PictureTag.html_attributes['parent']
|
61
|
+
|
62
|
+
picture
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# Handles a given source image file and its properties. Provides a speed
|
3
|
+
# advantage by storing expensive file reads and writes in instance variables,
|
4
|
+
# to be reused by many different source images.
|
5
|
+
class SourceImage
|
6
|
+
attr_reader :name, :shortname
|
7
|
+
|
8
|
+
def initialize(relative_filename)
|
9
|
+
@shortname = relative_filename
|
10
|
+
@name = grab_file relative_filename
|
11
|
+
end
|
12
|
+
|
13
|
+
def size
|
14
|
+
@size ||= build_size
|
15
|
+
end
|
16
|
+
|
17
|
+
def width
|
18
|
+
size[:width]
|
19
|
+
end
|
20
|
+
|
21
|
+
def aspect_ratio
|
22
|
+
@aspect_ratio ||= size[:width].to_f / size[:height].to_f
|
23
|
+
end
|
24
|
+
|
25
|
+
def digest
|
26
|
+
@digest ||= Digest::MD5.hexdigest(File.read(@name))[0..5]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Includes path relative to default sorce folder, and the original filename.
|
30
|
+
def base_name
|
31
|
+
@shortname.delete_suffix File.extname(@shortname)
|
32
|
+
end
|
33
|
+
|
34
|
+
# File exention
|
35
|
+
def ext
|
36
|
+
# [1..-1] will strip the leading period.
|
37
|
+
@ext ||= File.extname(@name)[1..-1].downcase
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def build_size
|
43
|
+
width, height = FastImage.size(@name)
|
44
|
+
|
45
|
+
{
|
46
|
+
width: width,
|
47
|
+
height: height
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
# Turn a relative filename into an absolute one, and make sure it exists.
|
52
|
+
def grab_file(source_file)
|
53
|
+
source_name = File.join(PictureTag.config.source_dir, source_file)
|
54
|
+
|
55
|
+
unless File.exist? source_name
|
56
|
+
raise "Jekyll Picture Tag could not find #{source_name}."
|
57
|
+
end
|
58
|
+
|
59
|
+
source_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# Handles srcset generation, which also handles file generation.
|
3
|
+
module Srcsets
|
4
|
+
# Basic functionality for a srcset, which also handles file generation.
|
5
|
+
# Classes including this module must implement the to_a method, which
|
6
|
+
# accomplishes the following:
|
7
|
+
# - Return an array of srcset entries.
|
8
|
+
# - Call generate_file for each entry, giving it the desired width in
|
9
|
+
# pixels.
|
10
|
+
module Basics
|
11
|
+
require 'fastimage'
|
12
|
+
require 'mime-types'
|
13
|
+
attr_reader :media, :source_image
|
14
|
+
|
15
|
+
def initialize(media:, format:)
|
16
|
+
@media = media # Associated Media Query, can be nil
|
17
|
+
|
18
|
+
# Output format:
|
19
|
+
@format = Utils.process_format(format, media)
|
20
|
+
|
21
|
+
@source_image = PictureTag.source_images[@media]
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
to_a.join(', ')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Allows us to add a type attribute to whichever element contains this
|
29
|
+
# srcset.
|
30
|
+
def mime_type
|
31
|
+
MIME::Types.type_for(@format).first.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
# Some srcsets have them, for those that don't return nil.
|
35
|
+
def sizes
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check our source image size vs requested sizes
|
40
|
+
def check_widths(targets)
|
41
|
+
if targets.any? { |t| t > @source_image.width }
|
42
|
+
handle_small_source(targets, @source_image.width)
|
43
|
+
else
|
44
|
+
targets
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generates an HTML attribute
|
49
|
+
def media_attribute
|
50
|
+
"(#{PictureTag.media_presets[@media]})"
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def handle_small_source(targets, image_width)
|
56
|
+
PictureTag::Utils.warning(
|
57
|
+
" #{@source_image.shortname} is #{image_width}px wide, smaller than" \
|
58
|
+
" at least one size in the set #{targets}. Will not enlarge."
|
59
|
+
)
|
60
|
+
|
61
|
+
small_targets = targets.dup.delete_if { |t| t >= image_width }
|
62
|
+
|
63
|
+
small_targets.push image_width
|
64
|
+
|
65
|
+
small_targets
|
66
|
+
end
|
67
|
+
|
68
|
+
def generate_file(width)
|
69
|
+
GeneratedImage.new(
|
70
|
+
source_file: @source_image,
|
71
|
+
width: width,
|
72
|
+
format: @format
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Srcsets
|
3
|
+
# Creates a srcset in the "(filename) (pixel_ratio)x" format.
|
4
|
+
# Example: "img.jpg 1x, img2.jpg 1.5x, img3.jpg 2x"
|
5
|
+
class PixelRatio
|
6
|
+
include Basics
|
7
|
+
|
8
|
+
def to_a
|
9
|
+
widths.collect { |w| build_srcset_entry(w) }
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def widths
|
15
|
+
target = PictureTag.preset['pixel_ratios'].collect do |p|
|
16
|
+
p * PictureTag.preset['base_width']
|
17
|
+
end
|
18
|
+
|
19
|
+
check_widths target
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_srcset_entry(width)
|
23
|
+
# We have to recalculate the pixel ratio after verifying our source
|
24
|
+
# image is large enough.
|
25
|
+
pixel_ratio = (width.to_f / PictureTag.preset['base_width']).round(2)
|
26
|
+
file = generate_file(width)
|
27
|
+
|
28
|
+
"#{PictureTag.build_url(file.name)} #{pixel_ratio}x"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module PictureTag
|
2
|
+
module Srcsets
|
3
|
+
# Creates a srcset in the "(filename) (width)w, (...)" format.
|
4
|
+
# Example: "img.jpg 400w, img2.jpg 600w, img3.jpg 800w"
|
5
|
+
class Width
|
6
|
+
include Basics
|
7
|
+
|
8
|
+
def to_a
|
9
|
+
widths.collect { |w| build_srcset_entry(w) }
|
10
|
+
end
|
11
|
+
|
12
|
+
# Sizes html attribute. Since it's intimately related to srcset, we
|
13
|
+
# generate it at the same time.
|
14
|
+
def sizes
|
15
|
+
preset_sizes = PictureTag.preset['sizes'] || {}
|
16
|
+
preset_size = PictureTag.preset['size']
|
17
|
+
size_set = []
|
18
|
+
|
19
|
+
preset_sizes.each_pair do |media, size|
|
20
|
+
size_set << build_size_entry(media, size)
|
21
|
+
end
|
22
|
+
|
23
|
+
size_set << preset_size if preset_size
|
24
|
+
|
25
|
+
size_set.any? ? size_set.join(', ') : nil
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def widths
|
31
|
+
check_widths PictureTag.widths(@media)
|
32
|
+
end
|
33
|
+
|
34
|
+
def build_srcset_entry(width)
|
35
|
+
file = generate_file(width)
|
36
|
+
|
37
|
+
"#{PictureTag.build_url(file.name)} #{file.width}w"
|
38
|
+
end
|
39
|
+
|
40
|
+
def build_size_entry(media, size)
|
41
|
+
"(#{PictureTag.media_presets[media]}) #{size}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module PictureTag
|
2
|
+
# This is a little module to hold logic that doesn't fit other places. If it
|
3
|
+
# starts getting big, refactor.
|
4
|
+
module Utils
|
5
|
+
# Configure Jekyll to keep our generated files
|
6
|
+
def self.keep_files
|
7
|
+
dest_dir = PictureTag.config['picture']['output']
|
8
|
+
|
9
|
+
# Chop a slash off the end, if it's there. Doesn't work otherwise.
|
10
|
+
dest_dir = dest_dir[0..-2] if dest_dir =~ %r{/\z}
|
11
|
+
|
12
|
+
return if PictureTag.site.config['keep_files'].include?(dest_dir)
|
13
|
+
|
14
|
+
PictureTag.site.config['keep_files'] << dest_dir
|
15
|
+
end
|
16
|
+
|
17
|
+
# Print a warning to the console
|
18
|
+
def self.warning(message)
|
19
|
+
return if PictureTag.config['picture']['suppress_warnings']
|
20
|
+
|
21
|
+
warn 'Jekyll Picture Tag Warning: '.yellow + message
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parse a liquid template; allows liquid variables to be included as tag
|
25
|
+
# params.
|
26
|
+
def self.liquid_lookup(params)
|
27
|
+
Liquid::Template.parse(params).render(PictureTag.context)
|
28
|
+
|
29
|
+
# This gsub allows people to include template code for javascript
|
30
|
+
# libraries such as handlebar.js. It adds complication and I'm not sure
|
31
|
+
# it has much value now, so I'm commenting it out. If someone has a use
|
32
|
+
# case for it we can add it back in.
|
33
|
+
# .gsub(/\\\{\\\{|\\\{\\%/, '\{\{' => '{{', '\{\%' => '{%')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Allows us to use 'original' as a format name.
|
37
|
+
def self.process_format(format, media)
|
38
|
+
if format.casecmp('original').zero?
|
39
|
+
PictureTag.source_images[media].ext
|
40
|
+
else
|
41
|
+
format.downcase
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Used for auto markup configuration and such
|
46
|
+
def self.count_srcsets
|
47
|
+
formats = PictureTag.preset['formats'].length
|
48
|
+
source_images = PictureTag.source_images.length
|
49
|
+
|
50
|
+
formats * source_images
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns whether or not the current page is a markdown file.
|
54
|
+
def self.markdown_page?
|
55
|
+
page_name = PictureTag.page['name']
|
56
|
+
page_ext = PictureTag.page['ext']
|
57
|
+
ext = page_ext ? page_ext : File.extname(page_name)
|
58
|
+
|
59
|
+
ext.casecmp('.md').zero? || ext.casecmp('.markdown').zero?
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the widest source image
|
63
|
+
def self.biggest_source
|
64
|
+
PictureTag.source_images.values.max_by(&:width)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|