class Jekyll::Picture
Constants
- VERSION
Public Class Methods
new(tag_name, markup, tokens)
click to toggle source
Calls superclass method
# File lib/jekyll-plugin-gkpicturetag.rb, line 30 def initialize(tag_name, markup, tokens) @markup = markup super end
Public Instance Methods
generate_image(instance, site_source, site_dest, image_source, image_dest, baseurl, debug)
click to toggle source
<picture class=“img-responsive”>
<source srcset="/img/illus/home-future-workplace.jpg, /img/illus/home-future-workplace@2x.jpg 2x"> <img class="img-responsive" src="/img/illus/home-future-workplace.jpg" alt="Future Workplace">
</picture>
# File lib/jekyll-plugin-gkpicturetag.rb, line 176 def generate_image(instance, site_source, site_dest, image_source, image_dest, baseurl, debug) begin digest = Digest::MD5.hexdigest(File.read(File.join(site_source, image_source, instance[:src]))).slice!(0..5) rescue Errno::ENOENT warn "Warning:".yellow + " source image #{instance[:src]} is missing." return "" end image_dir = File.dirname(instance[:src]) ext = File.extname(instance[:src]) basename = File.basename(instance[:src], ext) size = FastImage.size(File.join(site_source, image_source, instance[:src])) orig_width = size[0] orig_height = size[1] orig_ratio = orig_width*1.0/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 gen_width = gen_width / 2 gen_height = gen_height / 2 gen_name = "#{basename}-#{gen_width.round}by#{gen_height.round}-#{digest}#{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) 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 puts "Generating #{gen_name}" if !debug image = MiniMagick::Image.open(File.join(site_source, image_source, instance[:src])) # 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" end image.write gen_dest_file end # Return path relative to the site root for html Pathname.new(File.join(baseurl, image_dest, image_dir, gen_name)).cleanpath end
generate_image2x(instance, site_source, site_dest, image_source, image_dest, baseurl, debug)
click to toggle source
# File lib/jekyll-plugin-gkpicturetag.rb, line 249 def generate_image2x(instance, site_source, site_dest, image_source, image_dest, baseurl, debug) begin digest = Digest::MD5.hexdigest(File.read(File.join(site_source, image_source, instance[:src]))).slice!(0..5) rescue Errno::ENOENT warn "Warning:".yellow + " source image #{instance[:src]} is missing." return "" end image_dir = File.dirname(instance[:src]) ext = File.extname(instance[:src]) basename = File.basename(instance[:src], ext) size = FastImage.size(File.join(site_source, image_source, instance[:src])) orig_width = size[0] orig_height = size[1] orig_ratio = orig_width*1.0/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 gen_name = "#{basename}-#{gen_width.round}by#{gen_height.round}-#{digest}#{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) 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 puts "Generating #{gen_name}" if !debug image = MiniMagick::Image.open(File.join(site_source, image_source, instance[:src])) # 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" end image.write gen_dest_file end # Return path relative to the site root for html Pathname.new(File.join(baseurl, image_dest, image_dir, gen_name)).cleanpath end
render(context)
click to toggle source
# File lib/jekyll-plugin-gkpicturetag.rb, line 35 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] debug = site.config['debug'] settings = site.config['picture'] url = site.config['url'] markup = /^(?:(?<preset>[^\s.:\/]+)\s+)?(?<image_src>[^\s]+\.[a-zA-Z0-9]{3,4})\s*(?<source_src>(?:(source_[^\s.:\/]+:\s+[^\s]+\.[a-zA-Z0-9]{3,4})\s*)+)?(?<html_attr>[\s\S]+)?$/.match(render_markup) preset = settings['presets'][ markup[:preset] ] || settings['presets']['default'] raise "Picture Tag can't read this tag. Try {% picture [preset] path/to/img.jpg [source_key: path/to/alt-img.jpg] [attr=\"value\"] %}." unless markup # Assign defaults settings['source'] ||= '.' settings['output'] ||= 'generated' settings['markup'] ||= 'picture' # Prevent Jekyll from erasing our generated files site.config['keep_files'] << settings['output'] unless site.config['keep_files'].include?(settings['output']) # Deep copy preset for single instance manipulation instance = Marshal.load(Marshal.dump(preset)) # Process alternate source images source_src = if markup[:source_src] Hash[ *markup[:source_src].gsub(/:/, '').split ] else {} end # Process html attributes html_attr = if markup[:html_attr] Hash[ *markup[:html_attr].scan(/(?<attr>[^\s="]+)(?:="(?<value>[^"]+)")?\s?/).flatten ] else {} end if instance['attr'] html_attr = instance.delete('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 } # Prepare ppi variables ppi = if instance['ppi'] then instance.delete('ppi').sort.reverse else nil end # this might work??? ppi = instance.delete('ppi'){ |ppi| [nil] }.sort.reverse ppi_sources = {} # Switch width and height keys to the symbols that generate_image() expects begin instance.each { |key, source| # raise "Preset #{key} is missing a width or a height" if !source['width'] and !source['height'] instance[key][:width] = instance[key].delete('width') / 2 if source['width'] instance[key][:height] = instance[key].delete('height') / 2 if source['height'] } rescue # warn "Info (Picture-Tag): ".yellow + "No width and height. Take original size." end # Store keys in an array for ordering the instance sources source_keys = instance.keys # used to escape markdown parsing rendering below markdown_escape = "\ " # Raise some exceptions before we start expensive processing raise "Picture Tag can't find the \"#{markup[:preset]}\" preset. Check picture: presets in _config.yml for a list of presets." unless preset raise "Picture Tag can't find this preset source. Check picture: presets: #{markup[:preset]} in _config.yml for a list of sources." unless (source_src.keys - source_keys).empty? # Process instance # Add image paths for each source instance.each_key { |key| instance[key][:src] = source_src[key] || markup[:image_src] } # Construct ppi sources # Generates -webkit-device-ratio and resolution: dpi media value for cross browser support # Reference: http://www.brettjankord.com/2012/11/28/cross-browser-retinahigh-resolution-media-queries/ if ppi instance.each { |key, source| ppi.each { |p| if p != 1 ppi_key = "#{key}-x#{p}" ppi_sources[ppi_key] = { :width => if source[:width] then (source[:width].to_f * p).round else nil end, :height => if source[:height] then (source[:height].to_f * p).round else nil end, 'media' => if source['media'] "#{source['media']} and (-webkit-min-device-pixel-ratio: #{p}), #{source['media']} and (min-resolution: #{(p * 96).round}dpi)" else "(-webkit-min-device-pixel-ratio: #{p}), (min-resolution: #{(p * 96).to_i}dpi)" end, :src => source[:src] } # Add ppi_key to the source keys order source_keys.insert(source_keys.index(key), ppi_key) end } } instance.merge!(ppi_sources) end # Generate resized images instance.each { |key, source| instance[key][:generated_src] = generate_image(source, site.source, site.dest, settings['source'], settings['output'], site.config["baseurl"], debug) instance[key][:generated2x_src] = generate_image2x(source, site.source, site.dest, settings['source'], settings['output'], site.config["baseurl"], debug) } # Construct and return tag source_tags = '' source_keys.each do |source| warn "Info (Picture-Tag): ".yellow + "" + instance[source][:generated_src].to_s.green + "\n | ".yellow + instance[source][:generated2x_src].to_s.blue if debug media = " media=\"#{instance[source]['media']}\"" unless source == 'source_default' source_tags += "#{markdown_escape * 4}<source srcset=\"#{instance[source][:generated_src]}, #{instance[source][:generated2x_src]} 2x\"#{media}>\n" end # Note: we can't indent html output because markdown parsers will turn 4 spaces into code blocks # Note: Added backslash+space escapes to bypass markdown parsing of indented code below -WD picture_tag = "<picture>\n"\ "#{source_tags}"\ "#{markdown_escape * 4}<img src=\"#{instance['source_default'][:generated_src]}\" #{html_attr_string}>\n"\ "#{markdown_escape * 2}</picture>\n" # Return the markup! picture_tag end