Skip to content

Instantly share code, notes, and snippets.

@wjdp
Created November 1, 2016 23:26
Show Gist options
  • Save wjdp/d65dbf5cc51d740f802a48db25ef93f9 to your computer and use it in GitHub Desktop.
Save wjdp/d65dbf5cc51d740f802a48db25ef93f9 to your computer and use it in GitHub Desktop.
NTHP Image Tag plugin before deletion
# Title: Jekyll Image Tag
# Modified by: Will Pimblett: @wjdp
# Changes made to speed up (15 seconds -> 0.01 seconds) mean that images that
# change DO NOT get updated if the filenames still match
# Original Authors: Rob Wierzbowski : @robwierzbowski
#
# Description: Better images for Jekyll.
#
# Download: https://github.com/robwierzbowski/jekyll-image-tag
# Documentation: https://github.com/robwierzbowski/jekyll-image-tag/readme.md
# Issues: https://github.com/robwierzbowski/jekyll-image-tag/issues
#
# Syntax: {% image [preset or WxH] path/to/img.jpg [attr="value"] %}
# Example: {% image poster.jpg alt="The strange case of Dr. Jekyll" %}
# {% image gallery poster.jpg alt="The strange case of Dr. Jekyll" class="gal-img" data-selected %}
# {% image 350xAUTO poster.jpg alt="The strange case of Dr. Jekyll" class="gal-img" data-selected %}
#
# See the documentation for full configuration and usage instructions.
require 'fileutils'
require 'pathname'
require 'mini_magick'
$itime = 0
module Jekyll
class Image < Liquid::Tag
def initialize(tag_name, markup, tokens)
@markup = markup
super
end
def render(context)
# Render any liquid variables in tag arguments and unescape template code
render_markup = Liquid::Template.parse(@markup).render(context).gsub(/\\\{\\\{|\\\{\\%/, '\{\{' => '{{', '\{\%' => '{%')
# Gather settings
site = context.registers[:site]
settings = site.config['image']
markup = /^(?:(?<preset>[^\s.:\/]+)\s+)?(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})\s*(?<html_attr>[\s\S]+)?$/.match(render_markup)
preset = settings['presets'][ markup[:preset] ]
raise "Image Tag can't read this tag. Try {% image [preset or WxH] path/to/img.jpg [attr=\"value\"] %}." unless markup
# Assign defaults
settings['source'] ||= '.'
settings['output'] ||= 'generated'
# Prevent Jekyll from erasing our generated files
site.config['keep_files'] << settings['output'] unless site.config['keep_files'].include?(settings['output'])
# Process instance
instance = if preset
{
:width => preset['width'],
:height => preset['height'],
:src => markup[:image_src]
}
elsif dim = /^(?:(?<width>\d+)|auto)(?:x)(?:(?<height>\d+)|auto)$/i.match(markup[:preset])
{
:width => dim['width'],
:height => dim['height'],
:src => markup[:image_src]
}
else
{ :src => markup[:image_src] }
end
# Process html attributes
html_attr = if markup[:html_attr]
Hash[ *markup[:html_attr].scan(/(?<attr>[^\s="]+)(?:="(?<value>[^"]+)")?\s?/).flatten ]
else
{}
end
if preset && preset['attr']
html_attr = preset['attr'].merge(html_attr)
end
html_attr_string = html_attr.inject('') { |string, attrs|
if attrs[1]
string << "#{attrs[0]}=\"#{attrs[1]}\" "
else
string << "#{attrs[0]} "
end
}
# Raise some exceptions before we start expensive processing
raise "Image Tag can't find the \"#{markup[:preset]}\" preset. Check image: presets in _config.yml for a list of presets." unless preset || dim || markup[:preset].nil?
# Generate resized images
# t1 = Time.now
generated_src = generate_image(instance, site.source, site.dest, settings['source'], settings['output'])
# t2 = Time.now
# puts "imagegen" + ": " + (t2-t1).to_s
# $itime = $itime + (t2-t1)
# puts $itime
unless generated_src
return
end
generated_src = File.join(site.baseurl, generated_src) unless site.baseurl.empty?
# Return the markup!
"<img src=\"#{generated_src}\" #{html_attr_string}>"
end
def generate_image(instance, site_source, site_dest, image_source, image_dest)
image_source_path = File.join(site_source, image_source, instance[:src])
unless File.exists?image_source_path
Jekyll.logger.error "Missing: #{image_source_path}"
return false
end
image_dir = File.dirname(instance[:src])
ext = File.extname(instance[:src])
basename = File.basename(instance[:src], ext)
if instance[:width]
w = instance[:width].round
else
w = ""
end
if instance[:height]
h = instance[:height].round
else
h = ""
end
gen_name = "#{basename}-#{w}x#{h}#{ext}"
gen_dest_dir = File.join(site_dest, image_dest, image_dir)
gen_dest_file = File.join(gen_dest_dir, gen_name)
# Generate resized files
unless File.exists?(gen_dest_file)
# A
image = MiniMagick::Image.open(image_source_path)
image.coalesce
orig_width = image[:width].to_f
orig_height = image[:height].to_f
orig_ratio = orig_width/orig_height
gen_width = if instance[:width]
instance[:width].to_f
elsif instance[:height]
orig_ratio * instance[:height].to_f
else
orig_width
end
gen_height = if instance[:height]
instance[:height].to_f
elsif instance[:width]
instance[:width].to_f / orig_ratio
else
orig_height
end
gen_ratio = gen_width/gen_height
# Don't allow upscaling. If the image is smaller than the requested dimensions, recalculate.
if orig_width < gen_width || orig_height < gen_height
undersize = true
gen_width = if orig_ratio < gen_ratio then orig_width else orig_height * gen_ratio end
gen_height = if orig_ratio > gen_ratio then orig_height else orig_width/gen_ratio end
end
# A
warn "Warning:".yellow + " #{instance[:src]} is smaller than the requested output file. It will be resized without upscaling." if undersize
# If the destination directory doesn't exist, create it
FileUtils.mkdir_p(gen_dest_dir) unless File.exist?(gen_dest_dir)
# Let people know their images are being generated
Jekyll.logger.info "Generating #{gen_name}"
# Scale and crop
image.combine_options do |i|
i.resize "#{gen_width}x#{gen_height}^"
i.gravity "center"
i.crop "#{gen_width}x#{gen_height}+0+0"
i.layers "Optimize"
end
image.write gen_dest_file
end
# Return path relative to the site root for html
Pathname.new(File.join('/', image_dest, image_dir, gen_name)).cleanpath
end
end
end
Liquid::Template.register_tag('image', Jekyll::Image)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment