public
anonymous / image_size.rb
Last active

Nanoc filter that computes image dimensions and injects height and width attributes into img tags for much faster and smoother image loading in browsers

  • Download Gist
image_size.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
# vim: set ts=2 sw=2 et ai ft=ruby:
 
# Idea from here:
# http://userprimary.net/posts/2011/01/10/optimizing-nanoc-based-websites/
# Also uses code from other filters that are shipped with Nanoc itself.
#
# Implementation enhanced by Pascal Bleser <loki@fosdem.org>,
# under either GPL2 (GNU General Public License) or ASL2.1 (Apache Software License)
# or BSD-3-Clause, as you wish (short version: do whatever you want with it ;)).
#
# Put this file into lib/helpers/ (or lib/filters/, would be better structured)
# and add an invocation of "filter :imagesize" in your Rules, e.g. like this:
# compile '*' do
# filter :imagesize unless item.binary?
# end
 
class ImageSizeFilter < Nanoc::Filter
 
type :text
identifier :imagesize
 
@@SELECTORS = [ 'img' ]
 
def run(content, params={})
# Set assigns so helper function can be used
@item_rep = assigns[:item_rep] if @item_rep.nil?
selectors = params.fetch(:select) { @@SELECTORS }
namespaces = params[:namespaces] || {}
require 'nokogiri'
klass = ::Nokogiri::HTML
add_image_size(content, selectors, namespaces, klass, 'xhtml')
end
 
protected
def add_image_size(content, selectors, namespaces, klass, type)
# Ensure that all prefixes are strings
namespaces = namespaces.inject({}) { |new, (prefix, uri)| new.merge(prefix.to_s => uri) }
doc = content =~ /<html[\s>]/ ? klass.parse(content) : klass.fragment(content)
selectors.map { |sel| "#{sel}" }.each do |selector|
doc.xpath(selector, namespaces)
.select { |node| node.is_a? Nokogiri::XML::Element }
.select { |img| img.has_attribute?('src') }
.each do |img|
path = img['src']
dimensions = image_size(path)
dimensions.each{|k,v| img[k.to_s] = v.to_s}
end
end
result = doc.send("to_#{type}")
result
end
 
def image_size(path)
require 'image_size'
path = '/' + path unless path[0, 1] == '/'
img = ImageSize.new(IO.read("output#{path}"))
{ :height => img.height, :width => img.width }
end
 
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.