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