diff --git a/README.md b/README.md index 472b952..a216624 100644 --- a/README.md +++ b/README.md @@ -45,11 +45,17 @@ responsive_image: - width: 1400 quality: 90 + # [Optional, Default: assets] + # The base directory where assets are stored. This is used to determine the + # `dirname` value in `output_path_format` below. + base_path: assets + # [Optional, Default: assets/resized/%{filename}-%{width}x%{height}.%{extension}] # The template used when generating filenames for resized images. Must be a # relative path. # # Parameters available are: + # %{dirname} Directory of the file relative to `base_path` (assets/sub/dir/some-file.jpg => sub/dir) # %{basename} Basename of the file (assets/some-file.jpg => some-file.jpg) # %{filename} Basename without the extension (assets/some-file.jpg => some-file) # %{extension} Extension of the file (assets/some-file.jpg => jpg) @@ -162,11 +168,12 @@ The following variables are available in the template: Image objects (like `original` and each object in `resized`) contain the following properties: -| Variable | Type | Description | -|-------------|---------|-------------------------------------------------------------------------| -| `path` | String | The path to the image. | -| `width` | Integer | The width of the image. | -| `height` | Integer | The height of the image. | -| `basename` | String | Basename of the file (`assets/some-file.jpg` => `some-file.jpg`). | -| `filename` | String | Basename without the extension (`assets/some-file.jpg` => `some-file`). | -| `extension` | String | Extension of the file (`assets/some-file.jpg` => `jpg`). | +| Variable | Type | Description | +|-------------|---------|----------------------------------------------------------------------------------------------| +| `path` | String | The path to the image. | +| `width` | Integer | The width of the image. | +| `height` | Integer | The height of the image. | +| `basename` | String | Basename of the file (`assets/some-file.jpg` => `some-file.jpg`). | +| `dirname` | String | Directory of the file relative to `base_path` (`assets/sub/dir/some-file.jpg` => `sub/dir`). | +| `filename` | String | Basename without the extension (`assets/some-file.jpg` => `some-file`). | +| `extension` | String | Extension of the file (`assets/some-file.jpg` => `jpg`). | diff --git a/features/fixtures/assets/subdir/test.png b/features/fixtures/assets/subdir/test.png new file mode 100644 index 0000000..e53ebca Binary files /dev/null and b/features/fixtures/assets/subdir/test.png differ diff --git a/features/image-generation.feature b/features/image-generation.feature new file mode 100644 index 0000000..b7a8e50 --- /dev/null +++ b/features/image-generation.feature @@ -0,0 +1,35 @@ +Feature: Responsive image generation + As a Jekyll user + I want to generate responsive images + In order to use them on my pages + + Scenario: Resizing images + Given I have a responsive_image configuration with: + """ + template: _includes/responsive-image.html + sizes: + - width: 100 + """ + + And I have a file "index.html" with "{% responsive_image path: assets/test.png alt: Foobar %}" + When I run Jekyll + Then the image "assets/resized/test-100x50.png" should have the dimensions "100x50" + + Scenario: Handling subdirectories + Given I have a responsive_image configuration with: + """ + template: _includes/responsive-image.html + output_path_format: assets/resized/%{dirname}/%{filename}-%{width}.%{extension} + sizes: + - width: 100 + """ + + And I have a file "index.html" with: + """ + {% responsive_image path: assets/test.png %} + {% responsive_image path: assets/subdir/test.png %} + """ + + When I run Jekyll + Then the file "assets/resized/test-100.png" should exist + And the file "assets/resized/subdir/test-100.png" should exist diff --git a/features/responsive-image-tag.feature b/features/responsive-image-tag.feature index 2fbb4eb..5546e94 100644 --- a/features/responsive-image-tag.feature +++ b/features/responsive-image-tag.feature @@ -69,7 +69,7 @@ Feature: Jekyll responsive_image tag Given I have a responsive_image configuration with: """ template: _includes/responsive-image.html - output_path_format: assets/%{basename}-resized/%{width}/%{filename}-%{height}.%{extension} + output_path_format: assets/%{dirname}/%{basename}-resized/%{width}/%{filename}-%{height}.%{extension} sizes: - width: 100 """ diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb index 56f4f9e..0990a53 100644 --- a/features/step_definitions/jekyll_steps.rb +++ b/features/step_definitions/jekyll_steps.rb @@ -36,6 +36,12 @@ Then /^the file "(.+)" should exist$/ do |path| assert File.exists?(path) end +Then /^the image "(.+)" should have the dimensions "(\d+)x(\d+)"$/ do |path, width, height| + img = Magick::Image::read(path).first + assert_equal "#{width}x#{height}", "#{img.columns}x#{img.rows}" + img.destroy! +end + def write_file(path, contents) File.open(path, 'w') do |f| f.write(contents) diff --git a/lib/jekyll/responsive_image/common.rb b/lib/jekyll/responsive_image/common.rb index d018fa9..40676e5 100644 --- a/lib/jekyll/responsive_image/common.rb +++ b/lib/jekyll/responsive_image/common.rb @@ -7,7 +7,9 @@ module Jekyll config = ResponsiveImage.defaults.dup.merge(site.config['responsive_image']).merge(:site_dest => site.dest) # Not very nice, but this is needed to create a clean path to add to keep_files - output_dir = format_output_path(config['output_path_format'], '*', '*', '*') + output_dir = format_output_path(config['output_path_format'], config['base_path'], '*', '*', '*') + output_dir = "#{File.dirname(output_dir)}/*" + site.config['keep_files'] << output_dir unless site.config['keep_files'].include?(output_dir) config diff --git a/lib/jekyll/responsive_image/defaults.rb b/lib/jekyll/responsive_image/defaults.rb index f47d4a9..6bd6532 100644 --- a/lib/jekyll/responsive_image/defaults.rb +++ b/lib/jekyll/responsive_image/defaults.rb @@ -2,6 +2,7 @@ module Jekyll class ResponsiveImage @defaults = { 'default_quality' => 85, + 'base_path' => 'assets', 'output_path_format' => 'assets/resized/%{filename}-%{width}x%{height}.%{extension}', 'sizes' => [], }.freeze diff --git a/lib/jekyll/responsive_image/image_processor.rb b/lib/jekyll/responsive_image/image_processor.rb index 51a02b0..7e7632f 100644 --- a/lib/jekyll/responsive_image/image_processor.rb +++ b/lib/jekyll/responsive_image/image_processor.rb @@ -10,7 +10,7 @@ module Jekyll img = Magick::Image::read(image_path).first { - original: image_hash(image_path, img.columns, img.rows), + original: image_hash(config['base_path'], image_path, img.columns, img.rows), resized: resize_handler.resize_image(img, config), } end diff --git a/lib/jekyll/responsive_image/resize_handler.rb b/lib/jekyll/responsive_image/resize_handler.rb index 68f5de3..614ca12 100644 --- a/lib/jekyll/responsive_image/resize_handler.rb +++ b/lib/jekyll/responsive_image/resize_handler.rb @@ -13,8 +13,8 @@ module Jekyll next unless needs_resizing?(img, width) - filepath = format_output_path(config['output_path_format'], img.filename, width, height) - resized.push(image_hash(filepath, width, height)) + filepath = format_output_path(config['output_path_format'], config['base_path'], img.filename, width, height) + resized.push(image_hash(config['base_path'], filepath, width, height)) # Don't resize images more than once next if File.exists?(filepath) diff --git a/lib/jekyll/responsive_image/utils.rb b/lib/jekyll/responsive_image/utils.rb index bceb0de..fbe612e 100644 --- a/lib/jekyll/responsive_image/utils.rb +++ b/lib/jekyll/responsive_image/utils.rb @@ -1,3 +1,5 @@ +require 'pathname' + module Jekyll class ResponsiveImage module Utils @@ -9,22 +11,31 @@ module Jekyll result end - def format_output_path(format, path, width, height) - params = symbolize_keys(image_hash(path, width, height)) - format % params + def format_output_path(format, base_path, image_path, width, height) + params = symbolize_keys(image_hash(base_path, image_path, width, height)) + + Pathname.new(format % params).cleanpath.to_s end # Build a hash containing image information - def image_hash(path, width, height) + def image_hash(base_path, image_path, width, height) { - 'path' => path, - 'basename' => File.basename(path), - 'filename' => File.basename(path, '.*'), - 'extension' => File.extname(path).delete('.'), + 'path' => image_path, + 'dirname' => relative_dirname(base_path, image_path), + 'basename' => File.basename(image_path), + 'filename' => File.basename(image_path, '.*'), + 'extension' => File.extname(image_path).delete('.'), 'width' => width, 'height' => height, } end + + def relative_dirname(base_path, image_path) + path = Pathname.new(image_path).expand_path + base = Pathname.new(base_path).expand_path + + path.relative_path_from(base).dirname.to_s.delete('.') + end end end end