Compare commits
4 Commits
master
...
big-ass-re
Author | SHA1 | Date |
---|---|---|
Joseph Wynn | ba17ce94f0 | |
Joseph Wynn | 08557ce751 | |
Joseph Wynn | 665b60cad9 | |
Joseph Wynn | b3d81de179 |
|
@ -2,7 +2,7 @@ sudo: false
|
|||
language: ruby
|
||||
bundler_args: --without debug
|
||||
before_script: bundle exec jekyll --version
|
||||
script: bundle exec rake features_with_coveralls
|
||||
script: bundle exec rake rubocop features_with_coveralls
|
||||
rvm:
|
||||
- 2.2
|
||||
- 2.1
|
||||
|
|
8
Gemfile
8
Gemfile
|
@ -3,10 +3,10 @@ gemspec
|
|||
|
||||
group :development do
|
||||
gem 'rake'
|
||||
gem 'cucumber', '~> 2.1'
|
||||
gem 'test-unit', '~> 3.1'
|
||||
|
||||
gem 'coveralls', :require => false
|
||||
gem 'cucumber', '~> 2.4'
|
||||
gem 'test-unit', '~> 3.1', require: false
|
||||
gem 'rubocop', '~> 0.43', require: false
|
||||
gem 'coveralls', require: false
|
||||
|
||||
platform :ruby_18, :ruby_19 do
|
||||
gem 'simplecov', '>= 0.10', '< 0.12'
|
||||
|
|
5
Rakefile
5
Rakefile
|
@ -1,4 +1,5 @@
|
|||
require 'bundler'
|
||||
require 'rubocop/rake_task'
|
||||
|
||||
begin
|
||||
Bundler.setup(:default, :development)
|
||||
|
@ -13,12 +14,14 @@ require 'jekyll/responsive_image/version'
|
|||
require 'cucumber/rake/task'
|
||||
require 'coveralls/rake/task'
|
||||
|
||||
RuboCop::RakeTask.new
|
||||
|
||||
Cucumber::Rake::Task.new(:features)
|
||||
|
||||
Coveralls::RakeTask.new
|
||||
task :features_with_coveralls => [:features, 'coveralls:push']
|
||||
|
||||
task :default => [:features]
|
||||
task :default => [:rubocop, :features]
|
||||
|
||||
task :release do |t|
|
||||
system "gem build jekyll-responsive_image.gemspec"
|
||||
|
|
|
@ -39,16 +39,17 @@ Feature: Responsive image generation
|
|||
And the file "_site/assets/resized/subdir/test-100.png" should exist
|
||||
|
||||
Scenario: Honouring Jekyll 'source' configuration
|
||||
Given I have copied my site to "sub-dir/my-site-copy"
|
||||
Given I have copied my site to "my-site-copy/src"
|
||||
And I have a configuration with:
|
||||
"""
|
||||
source: sub-dir/my-site-copy
|
||||
source: my-site-copy/src
|
||||
responsive_image:
|
||||
template: _includes/responsive-image.html
|
||||
output_path_format: assets/resized/%{dirname}/%{width}/%{basename}
|
||||
sizes:
|
||||
- width: 100
|
||||
"""
|
||||
And I have a file "sub-dir/my-site-copy/index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png %}"
|
||||
And I have a file "my-site-copy/src/index.html" with "{% responsive_image path: assets/subdir/test.png %}"
|
||||
When I run Jekyll
|
||||
Then the image "sub-dir/my-site-copy/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should have the dimensions "100x50"
|
||||
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
|
||||
Then the image "my-site-copy/src/assets/resized/subdir/test-100x50.png" should have the dimensions "100x50"
|
||||
And the file "_site/assets/resized/subdir/test-100x50.png" should exist
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
include Test::Unit::Assertions
|
||||
|
||||
When /^I run Jekyll$/ do
|
||||
run_jekyll
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ if ENV['CI']
|
|||
Coveralls.wear!
|
||||
end
|
||||
|
||||
require 'test/unit'
|
||||
require 'test/unit/assertions'
|
||||
require 'jekyll/responsive_image'
|
||||
|
||||
TEST_DIR = File.join('/', 'tmp', 'jekyll')
|
||||
|
@ -14,3 +14,5 @@ def run_jekyll(options = {})
|
|||
site = Jekyll::Site.new(options)
|
||||
site.process
|
||||
end
|
||||
|
||||
World(Test::Unit::Assertions)
|
||||
|
|
|
@ -1 +1 @@
|
|||
<img src="{{ site.baseurl }}/{{ path }}">
|
||||
<img src="{{ site.baseurl }}/{{ original.path }}">
|
||||
|
|
|
@ -1 +1 @@
|
|||
<img alt="{{ alt }}" src="/{{ path }}" title="{{ title }}" srcset="{% for i in resized %}/{{ i.path }} {{ i.width }}w,{% endfor %}/{{ original.path }} {{ original.width }}w">
|
||||
<img alt="{{ alt }}" src="/{{ original.path }}" title="{{ title }}" srcset="{% for i in resized %}/{{ i.path }} {{ i.width }}w,{% endfor %}/{{ original.path }} {{ original.width }}w">
|
||||
|
|
|
@ -5,12 +5,12 @@ require 'jekyll'
|
|||
require 'rmagick'
|
||||
|
||||
require 'jekyll/responsive_image/version'
|
||||
require 'jekyll/responsive_image/defaults'
|
||||
require 'jekyll/responsive_image/utils'
|
||||
require 'jekyll/responsive_image/config'
|
||||
require 'jekyll/responsive_image/render_cache'
|
||||
require 'jekyll/responsive_image/image'
|
||||
require 'jekyll/responsive_image/image_processor'
|
||||
require 'jekyll/responsive_image/resize_handler'
|
||||
require 'jekyll/responsive_image/common'
|
||||
require 'jekyll/responsive_image/image_resizer'
|
||||
require 'jekyll/responsive_image/renderer'
|
||||
require 'jekyll/responsive_image/tag'
|
||||
require 'jekyll/responsive_image/block'
|
||||
require 'jekyll/responsive_image/extra_image_generator'
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class Block < Liquid::Block
|
||||
include Jekyll::ResponsiveImage::Common
|
||||
|
||||
def render(context)
|
||||
attributes = YAML.load(super)
|
||||
render_responsive_image(context, attributes)
|
||||
Renderer.new(context.registers[:site], attributes).render
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module Common
|
||||
include Jekyll::ResponsiveImage::Utils
|
||||
|
||||
def make_config(site)
|
||||
ResponsiveImage.defaults.dup
|
||||
.merge(site.config['responsive_image'])
|
||||
.merge(:site_source => site.source, :site_dest => site.dest)
|
||||
end
|
||||
|
||||
def keep_resized_image!(site, image)
|
||||
keep_dir = File.dirname(image['path'])
|
||||
site.config['keep_files'] << keep_dir unless site.config['keep_files'].include?(keep_dir)
|
||||
end
|
||||
|
||||
def render_responsive_image(context, attributes)
|
||||
cache_key = attributes.to_s
|
||||
result = attributes['cache'] ? RenderCache.get(cache_key) : nil
|
||||
|
||||
if result.nil?
|
||||
site = context.registers[:site]
|
||||
config = make_config(site)
|
||||
|
||||
absolute_image_path = site.in_source_dir(attributes['path'].to_s)
|
||||
image = ImageProcessor.process(absolute_image_path, attributes['path'], config)
|
||||
attributes['original'] = image[:original]
|
||||
attributes['resized'] = image[:resized]
|
||||
|
||||
attributes['resized'].each { |resized| keep_resized_image!(site, resized) }
|
||||
|
||||
image_template = site.in_source_dir(attributes['template'] || config['template'])
|
||||
partial = File.read(image_template)
|
||||
template = Liquid::Template.parse(partial)
|
||||
|
||||
result = template.render!(attributes.merge(site.site_payload))
|
||||
|
||||
|
||||
RenderCache.set(cache_key, result)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module Jekyll
|
||||
module ResponsiveImage
|
||||
class Config
|
||||
DEFAULTS = {
|
||||
'default_quality' => 85,
|
||||
'base_path' => 'assets',
|
||||
'output_path_format' => 'assets/resized/%{filename}-%{width}x%{height}.%{extension}',
|
||||
'sizes' => [],
|
||||
'extra_images' => []
|
||||
}
|
||||
|
||||
def initialize(site)
|
||||
@site = site
|
||||
end
|
||||
|
||||
def to_h
|
||||
DEFAULTS.merge(@site.config['responsive_image'])
|
||||
.merge(site_source: @site.source, site_dest: @site.dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
@defaults = {
|
||||
'default_quality' => 85,
|
||||
'base_path' => 'assets',
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class ExtraImageGenerator < Jekyll::Generator
|
||||
include Jekyll::ResponsiveImage::Common
|
||||
|
||||
def generate(site)
|
||||
config = make_config(site)
|
||||
renderer = Renderer.new(site, {})
|
||||
config = Config.new(site).to_h
|
||||
|
||||
config['extra_images'].each do |pathspec|
|
||||
Dir.glob(site.in_source_dir(pathspec)) do |image_path|
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
require 'pathname'
|
||||
|
||||
module Jekyll
|
||||
module ResponsiveImage
|
||||
class Image
|
||||
def initialize(path, width, height, config)
|
||||
@path = path.force_encoding(Encoding::UTF_8)
|
||||
@width = width
|
||||
@height = height
|
||||
@config = config
|
||||
end
|
||||
|
||||
# The directory name, relative to base_path
|
||||
def dirname
|
||||
base_path = Pathname.new(File.join(@config[:site_source], @config['base_path']))
|
||||
image_path = Pathname.new(File.join(@config[:site_source], @path))
|
||||
|
||||
image_path.relative_path_from(base_path).dirname.to_s.delete('.')
|
||||
end
|
||||
|
||||
def to_h
|
||||
{
|
||||
'basename' => File.basename(@path),
|
||||
'dirname' => dirname,
|
||||
'extension' => File.extname(@path).delete('.'),
|
||||
'filename' => File.basename(@path, '.*'),
|
||||
'height' => @height,
|
||||
'path' => @path,
|
||||
'width' => @width
|
||||
}
|
||||
end
|
||||
|
||||
def to_liquid
|
||||
to_h
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,22 +1,19 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class ImageProcessor
|
||||
include ResponsiveImage::Utils
|
||||
|
||||
def process(absolute_image_path, relative_image_path, config)
|
||||
raise SyntaxError.new("Invalid image path specified: #{absolute_image_path}") unless File.file?(absolute_image_path)
|
||||
|
||||
resize_handler = ResizeHandler.new
|
||||
img = Magick::Image::read(absolute_image_path).first
|
||||
|
||||
{
|
||||
original: image_hash(config['base_path'], relative_image_path, img.columns, img.rows),
|
||||
resized: resize_handler.resize_image(img, config),
|
||||
}
|
||||
def self.process(path, config)
|
||||
self.new.process(path, config)
|
||||
end
|
||||
|
||||
def self.process(absolute_image_path, relative_image_path, config)
|
||||
self.new.process(absolute_image_path, relative_image_path, config)
|
||||
def process(path, config)
|
||||
raise SyntaxError.new("Invalid image path specified: #{path}") unless File.file?(path)
|
||||
|
||||
image = Magick::Image::read(path).first
|
||||
|
||||
{
|
||||
original: Image.new(image.filename, image.columns, image.rows, config),
|
||||
resized: ImageResizer.resize(image, config),
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
module Jekyll
|
||||
module ResponsiveImage
|
||||
class ImageResizer
|
||||
def self.resize(image, config)
|
||||
self.new.resize(image, config)
|
||||
end
|
||||
|
||||
def resize(image, config)
|
||||
results = []
|
||||
|
||||
config['sizes'].each do |size|
|
||||
width = size['width']
|
||||
ratio = width.to_f / image.columns.to_f
|
||||
height = (image.rows.to_f * ratio).round
|
||||
|
||||
next unless needs_resizing?(image, width)
|
||||
|
||||
image_path = image.filename
|
||||
source_img = Image.new(image_path, width, height, config)
|
||||
site_source_path = format_output_path(config['output_path_format'], source_img.to_h)
|
||||
|
||||
resized_img = Image.new(site_source_path, width, height, config)
|
||||
results.push(resized_img)
|
||||
|
||||
# Don't resize images more than once
|
||||
next if File.exist?(site_source_path)
|
||||
|
||||
site_dest_path = File.join(config[:site_dest], site_source_path)
|
||||
ensure_output_dir_exists!(site_source_path)
|
||||
ensure_output_dir_exists!(site_dest_path)
|
||||
|
||||
Jekyll.logger.info "Generating #{site_source_path}"
|
||||
|
||||
resized = image.scale(ratio)
|
||||
resized.write(site_source_path) do |i|
|
||||
i.quality = size['quality'] || config['default_quality']
|
||||
end
|
||||
|
||||
# Ensure the generated file is copied to the _site directory
|
||||
Jekyll.logger.info "Copying image to #{site_dest_path}"
|
||||
FileUtils.copy_file(site_source_path, site_dest_path)
|
||||
end
|
||||
|
||||
results
|
||||
end
|
||||
|
||||
def format_output_path(format, image_hash)
|
||||
params = symbolize_keys(image_hash)
|
||||
|
||||
Pathname.new(format % params).cleanpath.to_s
|
||||
end
|
||||
|
||||
def symbolize_keys(hash)
|
||||
hash.each_with_object({}){ |(key, val), h| h[key.to_sym] = val }
|
||||
end
|
||||
|
||||
def needs_resizing?(image, width)
|
||||
image.columns > width
|
||||
end
|
||||
|
||||
def ensure_output_dir_exists!(path)
|
||||
dir = File.dirname(path)
|
||||
|
||||
unless Dir.exist?(dir)
|
||||
Jekyll.logger.info "Creating output directory #{dir}"
|
||||
FileUtils.mkdir_p(dir)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class RenderCache
|
||||
attr_accessor :store
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
module Jekyll
|
||||
module ResponsiveImage
|
||||
class Renderer
|
||||
attr_reader :site, :attributes
|
||||
|
||||
def initialize(site, attributes)
|
||||
@site = site
|
||||
@attributes = attributes
|
||||
end
|
||||
|
||||
def render
|
||||
cache_key = attributes.to_s
|
||||
result = attributes['cache'] ? RenderCache.get(cache_key) : nil
|
||||
|
||||
if result.nil?
|
||||
config = Config.new(site).to_h
|
||||
|
||||
image = ImageProcessor.process(attributes['path'], config)
|
||||
template_vars = attributes.merge(site.site_payload)
|
||||
.merge('original' => image[:original], 'resized' => image[:resized])
|
||||
|
||||
image_template = site.in_source_dir(attributes['template'] || config['template'])
|
||||
template = Liquid::Template.parse(File.read(image_template))
|
||||
result = template.render(template_vars)
|
||||
|
||||
RenderCache.set(cache_key, result)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,6 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class ResizeHandler
|
||||
include ResponsiveImage::Utils
|
||||
|
||||
def resize_image(img, config)
|
||||
resized = []
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
class Tag < Liquid::Tag
|
||||
include Jekyll::ResponsiveImage::Common
|
||||
|
||||
def initialize(tag_name, markup, tokens)
|
||||
super
|
||||
|
||||
|
@ -15,7 +13,7 @@ module Jekyll
|
|||
end
|
||||
|
||||
def render(context)
|
||||
render_responsive_image(context, @attributes)
|
||||
Renderer.new(context.registers[:site], @attributes).render
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
require 'pathname'
|
||||
|
||||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
module Utils
|
||||
def keep_resized_image!(site, image)
|
||||
keep_dir = File.dirname(image['path'])
|
||||
site.config['keep_files'] << keep_dir unless site.config['keep_files'].include?(keep_dir)
|
||||
end
|
||||
|
||||
def symbolize_keys(hash)
|
||||
result = {}
|
||||
hash.each_key do |key|
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
module Jekyll
|
||||
class ResponsiveImage
|
||||
module ResponsiveImage
|
||||
VERSION = '1.0.0.pre3'.freeze
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue