jekyll-srcset-tag 0.1.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/lib/jekyll/srcset_tag/image/instance.rb +72 -0
- data/lib/jekyll/srcset_tag/image/source.rb +20 -0
- data/lib/jekyll/srcset_tag/image.rb +106 -0
- data/lib/jekyll/srcset_tag/resizer.rb +24 -0
- data/lib/jekyll/srcset_tag/srcset_source_tag.rb +46 -0
- data/lib/jekyll/srcset_tag/srcset_tag.rb +80 -0
- data/lib/jekyll/srcset_tag/version.rb +5 -0
- data/lib/jekyll-srcset-tag.rb +5 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 69a4d80e9d2114444f958b0372cd93b96d0af16d
|
4
|
+
data.tar.gz: a950dd78d6fce273fa55b21671e5ba888c66a5db
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a3768328c0f8bf41e00756dbb37d866527e0fbd6b099533f02cf3eb29ad2ef09caf502971069e640c11eb43c15ed634fa5d3ae6a67d06811d02f9d2f9ea9d636
|
7
|
+
data.tar.gz: ed06ca9b5025efe2ff0234641ddc2e05ff1d61f72fc89276909c02d2ea2cafda724de0bb9348faeeeca047ca019c87a173746622280775835fa514d582c13862
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module SrcsetTag
|
3
|
+
class Image::Instance
|
4
|
+
|
5
|
+
attr_reader :width, :height, :image, :extension, :image_width, :image_height, :output_width, :output_height,
|
6
|
+
:undersized
|
7
|
+
|
8
|
+
def initialize(width:, height:, extension:)
|
9
|
+
@width = width
|
10
|
+
@height = height
|
11
|
+
@extension = extension
|
12
|
+
end
|
13
|
+
|
14
|
+
def for_image!(image)
|
15
|
+
@image = image
|
16
|
+
@image_width = image[:width].to_i
|
17
|
+
@image_height = image[:height].to_i
|
18
|
+
calculate_output_dimensions!
|
19
|
+
end
|
20
|
+
|
21
|
+
def filename
|
22
|
+
output_width.to_s + 'x' + output_height.to_s + extension
|
23
|
+
end
|
24
|
+
|
25
|
+
def undersized?
|
26
|
+
@undersized
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
# This is pretty much taken verbatim from https://github.com/robwierzbowski/jekyll-picture-tag
|
32
|
+
def calculate_output_dimensions!
|
33
|
+
@undersized = false
|
34
|
+
image_ratio = image_width.to_f / image_height.to_f
|
35
|
+
|
36
|
+
generated_width = if width
|
37
|
+
width.to_f
|
38
|
+
elsif height
|
39
|
+
image_ratio * height.to_f
|
40
|
+
else
|
41
|
+
image_width.to_f
|
42
|
+
end
|
43
|
+
generated_height = if height
|
44
|
+
height.to_f
|
45
|
+
elsif width
|
46
|
+
width.to_f / image_ratio
|
47
|
+
else
|
48
|
+
image_height
|
49
|
+
end
|
50
|
+
|
51
|
+
generated_ratio = generated_width / generated_height
|
52
|
+
|
53
|
+
if image_width < generated_width || image_height < generated_height
|
54
|
+
@undersized = true
|
55
|
+
generated_width = if image_ratio > generated_ratio
|
56
|
+
image_width
|
57
|
+
else
|
58
|
+
image_height / generated_ratio
|
59
|
+
end
|
60
|
+
generated_height = if image_ratio > generated_ratio
|
61
|
+
image_height
|
62
|
+
else
|
63
|
+
image_width / generated_ratio
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@output_width = generated_width.round
|
68
|
+
@output_height = generated_height.round
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Jekyll
|
2
|
+
module SrcsetTag
|
3
|
+
class Image::Source
|
4
|
+
|
5
|
+
attr_reader :media, :size, :width, :height
|
6
|
+
|
7
|
+
def initialize(width: nil, height: nil, media: nil, size: nil)
|
8
|
+
@media = media
|
9
|
+
@size = size
|
10
|
+
@width = width
|
11
|
+
@height = height
|
12
|
+
end
|
13
|
+
|
14
|
+
def size_string
|
15
|
+
(media ? media + ' ' : '') + (size || '100vw')
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'cgi'
|
3
|
+
require 'mini_magick'
|
4
|
+
require_relative 'resizer'
|
5
|
+
|
6
|
+
module Jekyll
|
7
|
+
module SrcsetTag
|
8
|
+
class Image
|
9
|
+
|
10
|
+
attr_reader :source_path, :output_path, :web_output_path, :image_path, :ppi, :sources, :html_attributes
|
11
|
+
|
12
|
+
def initialize(source_path:, output_path:, web_output_path:, image_path:, ppi:, sources:, html_attributes:)
|
13
|
+
@source_path = source_path
|
14
|
+
@output_path = output_path
|
15
|
+
@web_output_path = web_output_path
|
16
|
+
@image_path = image_path
|
17
|
+
@ppi = ppi.respond_to?(:sort_by) ? ppi : ppi.split(',').map(&:to_i)
|
18
|
+
@sources = sources
|
19
|
+
@html_attributes = html_attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate_images!
|
23
|
+
unless images_exist?
|
24
|
+
original = MiniMagick::Image.open File.join(source_path, image_path)
|
25
|
+
instances.each { |instance| instance.for_image!(original) }
|
26
|
+
resize_images! uniq_instances, original
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def images_exist?
|
31
|
+
Dir.exist? output_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
def instances
|
35
|
+
@instances ||= create_instances
|
36
|
+
end
|
37
|
+
|
38
|
+
def uniq_instances
|
39
|
+
instances.uniq { |instance| [ instance.output_width, instance.output_height ] }
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_html
|
43
|
+
srcs = image_srcs
|
44
|
+
src = CGI.escape_html(srcs.last[0])
|
45
|
+
srcset = CGI.escape_html(srcs.map {|path, size| "#{path} #{size}w" }.join(', '))
|
46
|
+
sizes = CGI::escape_html(source_sizes.join(', '))
|
47
|
+
"<img src=\"#{src}\" srcset=\"#{srcset}\" sizes=\"#{sizes}\" #{html_attributes}/>\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
def digest
|
51
|
+
unless @digest
|
52
|
+
file = Digest::SHA1.file(File.join(source_path, image_path)).to_s
|
53
|
+
sizes = Digest::SHA1.hexdigest instances.map { |i| i.width.to_s + '-' + i.height.to_s }.join(' ')
|
54
|
+
@digest = Digest::SHA1.hexdigest file + sizes
|
55
|
+
end
|
56
|
+
@digest
|
57
|
+
end
|
58
|
+
|
59
|
+
def output_dir
|
60
|
+
File.join(output_path, image_path + '-' + digest.slice(0, 7))
|
61
|
+
end
|
62
|
+
|
63
|
+
def web_output_dir
|
64
|
+
File.join(web_output_path, image_path + '-' + digest.slice(0, 7))
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def create_instances
|
70
|
+
reverse_ppi = ppi.sort_by { |s| -s }
|
71
|
+
all_sources = sources.map do |source|
|
72
|
+
reverse_ppi.map { |ppi| [source, ppi] }
|
73
|
+
end.flatten(1)
|
74
|
+
all_sources.map do |(source, ppi)|
|
75
|
+
Instance.new width: (source.width ? (source.width.to_f * ppi).round : nil),
|
76
|
+
height: (source.height ? (source.height.to_f * ppi).round : nil),
|
77
|
+
extension: File.extname(image_path)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def image_srcs
|
82
|
+
uniq_instances.map do |instance|
|
83
|
+
[File.join(web_output_dir, instance.filename), instance.output_width.to_s]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def source_sizes
|
88
|
+
sources.map { |source| source.size_string }
|
89
|
+
end
|
90
|
+
|
91
|
+
def resize_images!(instances, original)
|
92
|
+
if instances.any? { |i| i.undersized }
|
93
|
+
warn "Warning:".yellow + " #{image_path} is smaller than the requested output file. " +
|
94
|
+
"It will be resized without upscaling."
|
95
|
+
end
|
96
|
+
instances.each do |instance|
|
97
|
+
Resizer::resize(original, output_dir, instance.filename, instance.output_width, instance.output_height)
|
98
|
+
puts "Generated #{File.join(output_dir, instance.filename)}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
require_relative 'image/instance'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module SrcsetTag
|
5
|
+
module Resizer
|
6
|
+
def self.resize(image, destination_dir, filename, width, height)
|
7
|
+
FileUtils.mkdir_p(destination_dir) unless File.exist?(destination_dir)
|
8
|
+
image.strip
|
9
|
+
if image['format'] == 'JPEG'
|
10
|
+
image.quality 80
|
11
|
+
image.depth 8
|
12
|
+
image.interlace "plane"
|
13
|
+
end
|
14
|
+
image.combine_options do |i|
|
15
|
+
i.resize "#{width}x#{height}^"
|
16
|
+
i.gravity "center"
|
17
|
+
i.crop "#{width}x#{height}+0+0"
|
18
|
+
end
|
19
|
+
|
20
|
+
image.write File.join(destination_dir, filename)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
module SrcsetTag
|
5
|
+
class SrcsetSourceTag < Liquid::Tag
|
6
|
+
|
7
|
+
def initialize(tag_name, markup, tokens)
|
8
|
+
@markup = markup
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def render(context)
|
13
|
+
render_markup = Liquid::Template.parse(@markup)
|
14
|
+
.render(context)
|
15
|
+
.gsub(/\\\{\\\{|\\\{\\%/, '\{\{' => '{{', '\{\%' => '{%')
|
16
|
+
hash = markup_to_hash(render_markup)
|
17
|
+
markup = hash.map { |(key, value)| "#{key}=\"#{CGI.escape_html(value)}\""}
|
18
|
+
'<source ' + markup.join(' ') + ' />'
|
19
|
+
end
|
20
|
+
|
21
|
+
def markup_to_hash(markup)
|
22
|
+
matches = markup.scan(markup_regex)
|
23
|
+
matches.each_with_object({}) do |match, memo|
|
24
|
+
key, value = match.split(':', 2)
|
25
|
+
memo[key.strip] = value.gsub(/\A("|')|("|')\Z/, '')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def markup_regex
|
30
|
+
%r{
|
31
|
+
\w+
|
32
|
+
\s*
|
33
|
+
\:
|
34
|
+
\s*
|
35
|
+
(?:
|
36
|
+
"(?:[^"\\]|\\.)*"
|
37
|
+
|
|
38
|
+
'(?:[^'\\]|\\.)*'
|
39
|
+
|
|
40
|
+
[^\s]+
|
41
|
+
)
|
42
|
+
}x
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'image'
|
2
|
+
require_relative 'image/source'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module Jekyll
|
6
|
+
module SrcsetTag
|
7
|
+
class SrcsetTag < Liquid::Block
|
8
|
+
|
9
|
+
def initialize(tag_name, markup, tokens)
|
10
|
+
@markup = markup
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def render(context)
|
15
|
+
render_markup = Liquid::Template.parse(@markup)
|
16
|
+
.render(context)
|
17
|
+
.gsub(/\\\{\\\{|\\\{\\%/, '\{\{' => '{{', '\{\%' => '{%')
|
18
|
+
|
19
|
+
# set keep files
|
20
|
+
settings = srcset_settings(context)
|
21
|
+
site = context.registers[:site]
|
22
|
+
site.config['keep_files'] << settings['output'] unless site.config['keep_files'].include?(settings['output'])
|
23
|
+
|
24
|
+
image = image File.join(site.source, settings['source']),
|
25
|
+
File.join(site.dest, settings['output']),
|
26
|
+
'/' + settings['output'],
|
27
|
+
render_markup,
|
28
|
+
sources(super)
|
29
|
+
image.generate_images!
|
30
|
+
image.to_html
|
31
|
+
end
|
32
|
+
|
33
|
+
def sources(content)
|
34
|
+
# return sources objects
|
35
|
+
html = Nokogiri::HTML(content)
|
36
|
+
html.css('source').map do |source|
|
37
|
+
Image::Source.new(width: source.attr('width'),
|
38
|
+
height: source.attr('height'),
|
39
|
+
media: source.attr('media'),
|
40
|
+
size: source.attr('size'))
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def image(source_path, output_path, web_output_path, markup, sources)
|
46
|
+
markup = markup_regex.match(markup)
|
47
|
+
unless markup
|
48
|
+
raise "srcset tag doesn't look right - it should be {% srcset image_src [ppi:1,2] [html_attributes] %}"
|
49
|
+
end
|
50
|
+
Image.new(source_path: source_path,
|
51
|
+
output_path: output_path,
|
52
|
+
web_output_path: web_output_path,
|
53
|
+
image_path: markup[:image_src],
|
54
|
+
ppi: markup[:ppi] || 1,
|
55
|
+
sources: sources,
|
56
|
+
html_attributes: markup[:html_attr])
|
57
|
+
end
|
58
|
+
|
59
|
+
def markup_regex
|
60
|
+
%r{
|
61
|
+
^
|
62
|
+
(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})
|
63
|
+
\s*
|
64
|
+
(ppi:(?<ppi>(\d(\.\d\d?)?,)*\d(\.\d\d?)?))?
|
65
|
+
\s*
|
66
|
+
(?<html_attr>[\s\S]+)?
|
67
|
+
$
|
68
|
+
}x
|
69
|
+
end
|
70
|
+
|
71
|
+
def srcset_settings(context)
|
72
|
+
settings = context.registers[:site].config['srcset']
|
73
|
+
settings ||= {}
|
74
|
+
settings['source'] ||= '_assets/images/fullsize'
|
75
|
+
settings['output'] ||= 'images/generated'
|
76
|
+
settings
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jekyll-srcset-tag
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kevin Dew
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Provides a block that can take a source image and generate it to all
|
14
|
+
sizes for srcset usage
|
15
|
+
email:
|
16
|
+
- kevindew@me.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/jekyll-srcset-tag.rb
|
22
|
+
- lib/jekyll/srcset_tag/image.rb
|
23
|
+
- lib/jekyll/srcset_tag/image/instance.rb
|
24
|
+
- lib/jekyll/srcset_tag/image/source.rb
|
25
|
+
- lib/jekyll/srcset_tag/resizer.rb
|
26
|
+
- lib/jekyll/srcset_tag/srcset_source_tag.rb
|
27
|
+
- lib/jekyll/srcset_tag/srcset_tag.rb
|
28
|
+
- lib/jekyll/srcset_tag/version.rb
|
29
|
+
homepage: https://github.com/kevindew/jekyll-srcset-tag
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 2.1.0
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 2.4.8
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: A Jekyll plugin to use img srcset-w images
|
53
|
+
test_files: []
|