From f9d75b3bcecc89cf7100111690aefbb6d0b95ef6 Mon Sep 17 00:00:00 2001 From: Deepak Jois Date: Wed, 17 Feb 2010 19:58:25 -0800 Subject: [PATCH 1/2] Adding image_height and image_width functions --- lib/compass/sass_extensions/functions.rb | 3 +- .../sass_extensions/functions/image_size.rb | 34 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 lib/compass/sass_extensions/functions/image_size.rb diff --git a/lib/compass/sass_extensions/functions.rb b/lib/compass/sass_extensions/functions.rb index c33a30121a..a76421bbbc 100644 --- a/lib/compass/sass_extensions/functions.rb +++ b/lib/compass/sass_extensions/functions.rb @@ -1,7 +1,7 @@ module Compass::SassExtensions::Functions end -%w(selectors enumerate urls display inline_image color_stop font_files).each do |func| +%w(selectors enumerate urls display inline_image image_size color_stop font_files).each do |func| require "compass/sass_extensions/functions/#{func}" end @@ -11,6 +11,7 @@ module Sass::Script::Functions include Compass::SassExtensions::Functions::Urls include Compass::SassExtensions::Functions::Display include Compass::SassExtensions::Functions::InlineImage + include Compass::SassExtensions::Functions::ImageSize include Compass::SassExtensions::Functions::ColorStop include Compass::SassExtensions::Functions::FontFiles end diff --git a/lib/compass/sass_extensions/functions/image_size.rb b/lib/compass/sass_extensions/functions/image_size.rb new file mode 100644 index 0000000000..addf7a5867 --- /dev/null +++ b/lib/compass/sass_extensions/functions/image_size.rb @@ -0,0 +1,34 @@ +module Compass::SassExtensions::Functions::ImageSize + def image_width(image_file) + width = compute_size(image_file).first + Sass::Script::Number.new(width,["px"]) + end + + def image_height(image_file) + height = compute_size(image_file).last + Sass::Script::Number.new(height, ["px"]) + end + +private + # Returns an array [width,height] containing image dimensions + def compute_size(image_path) + path = image_path.value + # Compute the real path to the image on the file stystem if the images_dir is set. + real_path = if Compass.configuration.images_dir + File.join(Compass.configuration.project_path, Compass.configuration.images_dir, path) + else + File.join(Compass.configuration.project_path, path) + end + case real_path + when /\.png$/i + IO.read(real_path)[0x10..0x18].unpack('NN') + when /\.gif$/i + IO.read(real_path)[6..10].unpack('SS') + when /\.jpe?g$/i + # FIXME jpgs are not straightforward + raise Compass::Error, "JPEG files are not supported yet." + else + raise Compass::Error, "File is either not an image, or is not supported." + end + end +end From a075a10f59345ad6aa6745c0079f875c4417dfdf Mon Sep 17 00:00:00 2001 From: Deepak Jois Date: Thu, 18 Feb 2010 09:58:16 -0800 Subject: [PATCH 2/2] Adding support for calculating JPG dimensions --- .../sass_extensions/functions/image_size.rb | 113 ++++++++++++++---- 1 file changed, 89 insertions(+), 24 deletions(-) diff --git a/lib/compass/sass_extensions/functions/image_size.rb b/lib/compass/sass_extensions/functions/image_size.rb index addf7a5867..453010bc83 100644 --- a/lib/compass/sass_extensions/functions/image_size.rb +++ b/lib/compass/sass_extensions/functions/image_size.rb @@ -1,34 +1,99 @@ module Compass::SassExtensions::Functions::ImageSize - def image_width(image_file) - width = compute_size(image_file).first + def image_width(image_file) + image_path = real_path(image_file) + width = ImageProperties.new(image_path).size.first Sass::Script::Number.new(width,["px"]) end - + def image_height(image_file) - height = compute_size(image_file).last + image_path = real_path(image_file) + height = ImageProperties.new(image_path).size.last Sass::Script::Number.new(height, ["px"]) end - + private - # Returns an array [width,height] containing image dimensions - def compute_size(image_path) - path = image_path.value + def real_path(image_file) + path = image_file.value # Compute the real path to the image on the file stystem if the images_dir is set. - real_path = if Compass.configuration.images_dir - File.join(Compass.configuration.project_path, Compass.configuration.images_dir, path) - else - File.join(Compass.configuration.project_path, path) - end - case real_path - when /\.png$/i - IO.read(real_path)[0x10..0x18].unpack('NN') - when /\.gif$/i - IO.read(real_path)[6..10].unpack('SS') - when /\.jpe?g$/i - # FIXME jpgs are not straightforward - raise Compass::Error, "JPEG files are not supported yet." + if Compass.configuration.images_dir + File.join(Compass.configuration.project_path, Compass.configuration.images_dir, path) else - raise Compass::Error, "File is either not an image, or is not supported." - end - end + File.join(Compass.configuration.project_path, path) + end + end + + class ImageProperties + def initialize(file) + @file = file + @file_type = File.extname(@file)[1..-1] + end + + def size + @dimensions ||= send("get_size_for_#{@file_type}") + end + + private + def get_size_for_png + IO.read(@file)[0x10..0x18].unpack('NN') + end + + def get_size_for_gif + size = IO.read(@file)[6..10].unpack('SS') + size.inspect + end + + def get_size_for_bmp + d = IO.read(@file)[14..28] + d[0] == 40 ? d[4..-1].unpack('LL') : d[4..8].unpack('SS') + end + + def get_size_for_jpg + get_size_for_jpeg + end + + def get_size_for_jpeg + jpeg = JPEG.new(@file) + [jpeg.width, jpeg.height] + end + end + + class JPEG + attr_reader :width, :height, :bits + + def initialize(file) + if file.kind_of? IO + examine(file) + else + File.open(file, 'rb') { |io| examine(io) } + end + end + + private + def examine(io) + raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI + + class << io + def readint; (readchar << 8) + readchar; end + def readframe; read(readint - 2); end + def readsof; [readint, readchar, readint, readint, readchar]; end + def next + c = readchar while c != 0xFF + c = readchar while c == 0xFF + c + end + end + + while marker = io.next + case marker + when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers + length, @bits, @height, @width, components = io.readsof + raise 'malformed JPEG' unless length == 8 + components * 3 + when 0xD9, 0xDA: break # EOI, SOS + when 0xFE: @comment = io.readframe # COM + when 0xE1: io.readframe # APP1, contains EXIF tag + else io.readframe # ignore frame + end + end + end +end end