mirror of
https://github.com/wildlyinaccurate/jekyll-responsive-image.git
synced 2025-07-04 00:00:41 -04:00
Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dda6d748c8 | ||
|
a31c454ed1 | ||
|
f2be2c53be | ||
|
6cc3a082a1 | ||
|
2f7c0124eb | ||
|
25c6695da4 | ||
|
7679f4b8f5 | ||
|
82e868966c | ||
|
fbc35b8ef9 | ||
|
749e6cc068 | ||
|
fa00c4c9cf | ||
|
4b75f67558 | ||
|
307f3c6284 | ||
|
f3103be702 | ||
|
5715734bde | ||
|
8cb3c53dd7 | ||
|
16ab99deac | ||
|
91a540c266 | ||
|
48c36e75b9 | ||
|
9d6f549855 | ||
|
4d90cd177e | ||
|
3d7f0e609b | ||
|
6444d327de | ||
|
b9791014de | ||
|
6d323718cf | ||
|
0153b9fb9e | ||
|
6533035416 | ||
|
855c3a70e4 | ||
|
bc61757f2a | ||
|
38e3b1f92f | ||
|
3cf3bc7be3 | ||
|
d902ec743d | ||
|
c559bcced3 | ||
|
b76e2d3365 | ||
|
1df929e20d | ||
|
7a3dbf1ab9 | ||
|
ac86fb2440 | ||
|
aaaabbc2c0 |
10
.github/stale.yml
vendored
Normal file
10
.github/stale.yml
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
daysUntilStale: 18
|
||||||
|
daysUntilClose: 3
|
||||||
|
staleLabel: stale
|
||||||
|
exemptLabels:
|
||||||
|
- pinned
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
closeComment: false
|
@ -5,8 +5,8 @@ bundler_args: --without debug
|
|||||||
before_script: bundle exec jekyll --version
|
before_script: bundle exec jekyll --version
|
||||||
script: bundle exec rake features_with_coveralls
|
script: bundle exec rake features_with_coveralls
|
||||||
rvm:
|
rvm:
|
||||||
|
- '2.6'
|
||||||
|
- '2.5'
|
||||||
- '2.4'
|
- '2.4'
|
||||||
- '2.3'
|
- '2.3'
|
||||||
- '2.2'
|
- '2.2'
|
||||||
- '2.1'
|
|
||||||
- '2.0'
|
|
||||||
|
2
Gemfile
2
Gemfile
@ -4,7 +4,7 @@ gemspec
|
|||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
gem 'rake'
|
gem 'rake'
|
||||||
gem 'cucumber', '~> 2.4'
|
gem 'cucumber', '~> 3.1'
|
||||||
gem 'test-unit', '~> 3.2'
|
gem 'test-unit', '~> 3.2'
|
||||||
|
|
||||||
gem 'simplecov', :require => false
|
gem 'simplecov', :require => false
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2014 Joseph Wynn
|
Copyright (c) 2018 Joseph Wynn
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
265
README.md
265
README.md
@ -1,31 +1,130 @@
|
|||||||
# jekyll-responsive-image
|
# jekyll-responsive-image
|
||||||
|
|
||||||
A [Jekyll](http://jekyllrb.com/) plugin and utility for automatically resizing images. Its intended use is for sites which want to display responsive images using something like [`srcset`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#Specifications) or [Imager.js](https://github.com/BBC-News/Imager.js/).
|
A [Jekyll](http://jekyllrb.com/) plugin for automatically resizing images. Fully configurable and unopinionated, jekyll-responsive-image allows you to display responsive images however you like: using [`<img srcset>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Img#attr-srcset), [`<picture>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/picture), or [Imager.js](https://github.com/BBC-News/Imager.js/).
|
||||||
|
|
||||||
[](https://travis-ci.org/wildlyinaccurate/jekyll-responsive-image)
|
[](https://travis-ci.org/wildlyinaccurate/jekyll-responsive-image)
|
||||||
[](https://coveralls.io/repos/github/wildlyinaccurate/jekyll-responsive-image/badge.svg?branch=master)
|
[](https://coveralls.io/repos/github/wildlyinaccurate/jekyll-responsive-image/badge.svg?branch=master)
|
||||||
[](https://gemnasium.com/wildlyinaccurate/jekyll-responsive-images)
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
First, install the gem:
|
This plugin can be installed in three steps:
|
||||||
|
|
||||||
|
### 1. Install the gem
|
||||||
|
|
||||||
|
Either add `jekyll-responsive-image` to your Gemfile, or run the following command to install the gem:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ gem install jekyll-responsive-image
|
$ gem install jekyll-responsive-image
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you can either add it to the `gems` section of your `_config.yml`:
|
Then you can either add `jekyll-responsive-image` to the `plugins` section of your `_config.yml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
gems:
|
plugins:
|
||||||
- jekyll-responsive-image
|
- jekyll-responsive-image
|
||||||
```
|
```
|
||||||
|
Note: If you are using a Jekyll version less than 3.5.0, use the `gems` key instead of `plugins`.
|
||||||
|
|
||||||
Or you can copy the contents of [`responsive_image.rb`](lib/jekyll-responsive-image.rb) into your `_plugins` directory.
|
Or you can copy the contents of [`responsive_image.rb`](lib/jekyll-responsive-image.rb) into your `_plugins` directory.
|
||||||
|
|
||||||
## Configuration
|
### 2. Create an image template file
|
||||||
|
|
||||||
An example configuration is below.
|
You will need to create a template in order to use the `responsive_image` and `responsive_image_block` tags. Normally the template lives in your `_includes/` directory. Not sure where to start? [Take a look at the sample templates](sample-templates).
|
||||||
|
|
||||||
|
For more advanced templates, see the [**Templates**](#templates) section below.
|
||||||
|
|
||||||
|
### 3. Configure the plugin
|
||||||
|
|
||||||
|
You **must** have a `responsive_image` block in your `_config.yml` for this plugin to work. At a minimum, your `responsive_image` configuration should have a template path and a list of sizes.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
responsive_image:
|
||||||
|
template: _includes/responsive-image.html
|
||||||
|
sizes:
|
||||||
|
- width: 320
|
||||||
|
- width: 480
|
||||||
|
- width: 800
|
||||||
|
```
|
||||||
|
|
||||||
|
For a list of all the available configuration options, see the [**All configuration options**](#all-configuration-options) section below.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Replace your images with the `responsive_image` tag, specifying the path to the image in the `path` attribute.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% responsive_image path: assets/my-file.jpg %}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can override the template on a per-image basis by specifying the `template` attribute.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% responsive_image path: assets/my-file.jpg template: _includes/another-template.html %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Any extra attributes will be passed straight to the template as variables.
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% responsive_image path: assets/image.jpg alt: "Lorem ipsum..." title: "Lorem ipsum..." %}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Liquid variables as attributes
|
||||||
|
|
||||||
|
You can use Liquid variables as attributes with the `responsive_image_block` tag. This tag works in exactly the same way as the `responsive_image` tag, but is implemented as a block tag to allow for more complex logic.
|
||||||
|
|
||||||
|
> **Important!** The attributes in the `responsive_image_block` tag are parsed as YAML, so whitespace and indentation are significant!
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% assign path = 'assets/test.png' %}
|
||||||
|
{% assign alt = 'Lorem ipsum...' %}
|
||||||
|
|
||||||
|
{% responsive_image_block %}
|
||||||
|
path: {{ path }}
|
||||||
|
alt: {{ alt }}
|
||||||
|
{% if title %}
|
||||||
|
title: {{ title }}
|
||||||
|
{% endif %}
|
||||||
|
{% endresponsive_image_block %}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
It's easy to build your own custom templates to render images however you want using the template variables provided by jekyll-responsive-image.
|
||||||
|
|
||||||
|
### Template Variables
|
||||||
|
|
||||||
|
The following variables are available in the template:
|
||||||
|
|
||||||
|
| Variable | Type | Description |
|
||||||
|
|------------|---------------|------------------------------------------------------------------------------------------------------|
|
||||||
|
| `path` | String | The path of the unmodified image. This is always the same as the `path` attribute passed to the tag. |
|
||||||
|
| `resized` | Array<Object> | An array of all the resized images. Each image is an **Image Object**. |
|
||||||
|
| `original` | Object | An **Image Object** containing information about the original image. |
|
||||||
|
| `*` | String | Any other attributes will be passed to the template verbatim as strings (see below). |
|
||||||
|
|
||||||
|
Any other attributes that are given to the `responsive_image` or `responsive_image_block` tags will be available in the template. For example the following tag will provide an `{{ alt }}` variable to the template:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% responsive_image path: assets/my-file.jpg alt: "A description of the image" %}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Image Objects
|
||||||
|
|
||||||
|
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`). |
|
||||||
|
| `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`). |
|
||||||
|
|
||||||
|
## All configuration options
|
||||||
|
|
||||||
|
A full list of all of the available configuration options is below.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
responsive_image:
|
responsive_image:
|
||||||
@ -95,136 +194,24 @@ responsive_image:
|
|||||||
- assets/avatars/*.{jpeg,jpg}
|
- assets/avatars/*.{jpeg,jpg}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Troubleshooting
|
||||||
|
|
||||||
Replace your images with the `responsive_image` tag, specifying the path to the image in the `path` attribute.
|
### Error: Can't install RMagick
|
||||||
|
|
||||||
```twig
|
`jekyll-responsive-image` uses `rmagick` which is currently incompatible with ImageMagick 7. If you get an error like:
|
||||||
{% responsive_image path: assets/my-file.jpg %}
|
|
||||||
|
```
|
||||||
|
Can't install RMagick 2.16.0. Can't find MagickWand.h
|
||||||
```
|
```
|
||||||
|
|
||||||
You can override the template on a per-image basis by specifying the `template` attribute.
|
Then you will need to install ImageMagick 6. If you are using Homebrew on Mac OS, this can be done with the following commands:
|
||||||
|
|
||||||
```twig
|
```
|
||||||
{% responsive_image path: assets/my-file.jpg template: _includes/another-template.html %}
|
$ brew uninstall imagemagick
|
||||||
|
$ brew install imagemagick@6 && brew link imagemagick@6 --force
|
||||||
```
|
```
|
||||||
|
|
||||||
Any extra attributes will be passed straight to the template as variables.
|
## Caching
|
||||||
|
|
||||||
```twig
|
|
||||||
{% responsive_image path: assets/image.jpg alt: "Lorem ipsum..." title: "Lorem ipsum..." %}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Liquid variables as attributes
|
|
||||||
|
|
||||||
You can use Liquid variables as attributes with the `responsive_image_block` tag. This tag works in exactly the same way as the `responsive_image` tag, but is implemented as a block tag to allow for more complex logic.
|
|
||||||
|
|
||||||
> **Important!** The attributes in the `responsive_image_block` tag are parsed as YAML, so whitespace and indentation are significant!
|
|
||||||
|
|
||||||
```twig
|
|
||||||
{% assign path = 'assets/test.png' %}
|
|
||||||
{% assign alt = 'Lorem ipsum...' %}
|
|
||||||
|
|
||||||
{% responsive_image_block %}
|
|
||||||
path: {{ path }}
|
|
||||||
alt: {{ alt }}
|
|
||||||
{% if title %}
|
|
||||||
title: {{ title }}
|
|
||||||
{% endif %}
|
|
||||||
{% endresponsive_image_block %}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Template
|
|
||||||
|
|
||||||
You will need to create a template in order to use the `responsive_image` tag. Below are some sample templates to get you started.
|
|
||||||
|
|
||||||
#### Responsive images with `srcset`
|
|
||||||
|
|
||||||
```twig
|
|
||||||
{% capture srcset %}
|
|
||||||
{% for i in resized %}
|
|
||||||
/{{ i.path }} {{ i.width }}w,
|
|
||||||
{% endfor %}
|
|
||||||
{% endcapture %}
|
|
||||||
|
|
||||||
<img src="/{{ path }}" alt="{{ alt }}" srcset="{{ srcset | strip_newlines }}">
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Responsive image with `srcset` where the largest resized image is the default
|
|
||||||
|
|
||||||
> **Note:** This is useful if you don't want your originals to appear on your site. For example, if you're uploading full-res images directly from a device.
|
|
||||||
|
|
||||||
```twig
|
|
||||||
{% capture srcset %}
|
|
||||||
{% for i in resized %}
|
|
||||||
/{{ i.path }} {{ i.width }}w,
|
|
||||||
{% endfor %}
|
|
||||||
{% endcapture %}
|
|
||||||
|
|
||||||
{% assign largest = resized | sort: 'width' | last %}
|
|
||||||
|
|
||||||
<img src="/{{ largest.path }}" alt="{{ alt }}" srcset="{{ srcset | strip_newlines }}">
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Responsive images with `<picture>`
|
|
||||||
|
|
||||||
```twig
|
|
||||||
<picture>
|
|
||||||
{% for i in resized %}
|
|
||||||
<source media="(min-width: {{ i.width }}px)" srcset="/{{ i.path }}">
|
|
||||||
{% endfor %}
|
|
||||||
<img src="/{{ path }}">
|
|
||||||
</picture>
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Responsive images using [Imager.js](https://github.com/BBC-News/Imager.js/)
|
|
||||||
|
|
||||||
> **Note:** This template assumes an `output_path_format` of `assets/resized/%{width}/%{basename}`
|
|
||||||
|
|
||||||
```twig
|
|
||||||
{% assign smallest = resized | sort: 'width' | first %}
|
|
||||||
|
|
||||||
<div class="responsive-image">
|
|
||||||
<img class="responsive-image__placeholder" src="/{{ smallest.path }}">
|
|
||||||
<div class="responsive-image__delayed" data-src="/assets/resized/{width}/{{ original.basename }}"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
new Imager('.responsive-image__delayed', {
|
|
||||||
availableWidths: [{{ resized | map: 'width' | join: ', ' }}]
|
|
||||||
onImagesReplaced: function() {
|
|
||||||
$('.responsive-image__placeholder').hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Template Variables
|
|
||||||
|
|
||||||
The following variables are available in the template:
|
|
||||||
|
|
||||||
| Variable | Type | Description |
|
|
||||||
|----------- |--------|------------------------------------------------------------------------------------------------------|
|
|
||||||
| `path` | String | The path of the unmodified image. This is always the same as the `path` attribute passed to the tag. |
|
|
||||||
| `resized` | Array | An array of all the resized images. Each image is an **Image Object**. |
|
|
||||||
| `original` | Object | An **Image Object** containing information about the original image. |
|
|
||||||
| `*` | String | Any other attributes will be passed to the template verbatim as strings. |
|
|
||||||
|
|
||||||
#### Image Objects
|
|
||||||
|
|
||||||
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`). |
|
|
||||||
| `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`). |
|
|
||||||
|
|
||||||
### Caching
|
|
||||||
|
|
||||||
You may be able to speed up the build of large sites by enabling render caching. This is usually only effective when the same image is used many times, for example a header image that is rendered in every post.
|
You may be able to speed up the build of large sites by enabling render caching. This is usually only effective when the same image is used many times, for example a header image that is rendered in every post.
|
||||||
|
|
||||||
@ -248,3 +235,21 @@ responsive_image:
|
|||||||
sizes:
|
sizes:
|
||||||
- ...
|
- ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
If you'd like to contribute to this repository, here's how you can set it up for development:
|
||||||
|
|
||||||
|
1. Fork this repository
|
||||||
|
2. Clone the fork to your local machine
|
||||||
|
3. Install [ImageMagick](http://www.imagemagick.org/) (if you haven't already)
|
||||||
|
4. Run `bundle install`
|
||||||
|
5. Run the tests like this: `cucumber`
|
||||||
|
|
||||||
|
If you'd like your Jekyll project to use your local fork directly, you can add the `:path` parameter to your gem command in the project's Gemfile:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
gem 'jekyll-responsive-image', :path => "/your/local/path/to/jekyll-responsive-image"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you'd like your changes to be considered for the original repository, simply submit a pull request after you've made your changes. Please make sure all tests pass.
|
||||||
|
@ -15,6 +15,25 @@ Feature: Extra image generation
|
|||||||
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
|
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
|
||||||
And the file "_site/assets/resized/progressive-100x50.jpeg" should exist
|
And the file "_site/assets/resized/progressive-100x50.jpeg" should exist
|
||||||
|
|
||||||
|
Scenario: Specifying a recursive glob pattern
|
||||||
|
Given I have a responsive_image configuration with:
|
||||||
|
"""
|
||||||
|
sizes:
|
||||||
|
- width: 100
|
||||||
|
extra_images:
|
||||||
|
- assets/**/*
|
||||||
|
"""
|
||||||
|
And I have a file "index.html" with "Hello, world!"
|
||||||
|
When I run Jekyll
|
||||||
|
Then the image "assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should have the dimensions "100x50"
|
||||||
|
And the image "assets/resized/exif-rotation-100x50.jpeg" should have the dimensions "100x50"
|
||||||
|
And the image "assets/resized/progressive-100x50.jpeg" should have the dimensions "100x50"
|
||||||
|
And the image "assets/resized/test-100x50.png" should have the dimensions "100x50"
|
||||||
|
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
|
||||||
|
And the file "_site/assets/resized/exif-rotation-100x50.jpeg" should exist
|
||||||
|
And the file "_site/assets/resized/progressive-100x50.jpeg" should exist
|
||||||
|
And the file "_site/assets/resized/test-100x50.png" should exist
|
||||||
|
|
||||||
Scenario: Honouring Jekyll 'source' configuration
|
Scenario: Honouring Jekyll 'source' configuration
|
||||||
Given I have copied my site to "sub-dir/my-site-copy"
|
Given I have copied my site to "sub-dir/my-site-copy"
|
||||||
And I have a configuration with:
|
And I have a configuration with:
|
||||||
|
12
features/plugin.feature
Normal file
12
features/plugin.feature
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Feature: General plugin usage
|
||||||
|
Scenario: No config at all
|
||||||
|
Given I have no configuration
|
||||||
|
When I run Jekyll
|
||||||
|
Then there should be no errors
|
||||||
|
|
||||||
|
Scenario: Config with empty responsive_image block
|
||||||
|
Given I have a responsive_image configuration with:
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
When I run Jekyll
|
||||||
|
Then there should be no errors
|
@ -13,6 +13,20 @@ Feature: Jekyll responsive_image_block tag
|
|||||||
When I run Jekyll
|
When I run Jekyll
|
||||||
Then I should see "<img alt=\"Lorem ipsum\" src=\"/assets/everybody-loves-jalapeño-pineapple-cornbread.png\" title=\"Magic rainbow adventure!\"" in "_site/index.html"
|
Then I should see "<img alt=\"Lorem ipsum\" src=\"/assets/everybody-loves-jalapeño-pineapple-cornbread.png\" title=\"Magic rainbow adventure!\"" in "_site/index.html"
|
||||||
|
|
||||||
|
Scenario: Tabs for indentation
|
||||||
|
Given I have a responsive_image configuration with "template" set to "_includes/responsive-image.html"
|
||||||
|
And I have a file "index.html" with:
|
||||||
|
"""
|
||||||
|
{% assign path = 'assets/everybody-loves-jalapeño-pineapple-cornbread.png' %}
|
||||||
|
{% responsive_image_block %}
|
||||||
|
path: {{ path }}
|
||||||
|
title: Magic rainbow adventure!
|
||||||
|
alt: Lorem ipsum
|
||||||
|
{% endresponsive_image_block %}
|
||||||
|
"""
|
||||||
|
When I run Jekyll
|
||||||
|
Then I should see "<img alt=\"Lorem ipsum\" src=\"/assets/everybody-loves-jalapeño-pineapple-cornbread.png\" title=\"Magic rainbow adventure!\"" in "_site/index.html"
|
||||||
|
|
||||||
Scenario: Global variables available in templates
|
Scenario: Global variables available in templates
|
||||||
Given I have a file "index.html" with:
|
Given I have a file "index.html" with:
|
||||||
"""
|
"""
|
||||||
@ -56,4 +70,4 @@ Feature: Jekyll responsive_image_block tag
|
|||||||
path: {{ path }}
|
path: {{ path }}
|
||||||
{% endresponsive_image_block %}
|
{% endresponsive_image_block %}
|
||||||
"""
|
"""
|
||||||
Then Jekyll should throw a "SyntaxError"
|
Then Jekyll should throw a "Magick::ImageMagickError"
|
||||||
|
@ -6,6 +6,10 @@ Then /^Jekyll should throw a "(.+)"$/ do |error_class|
|
|||||||
assert_raise(Object.const_get(error_class)) { run_jekyll }
|
assert_raise(Object.const_get(error_class)) { run_jekyll }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Then /^there should be no errors$/ do
|
||||||
|
# Implicit pass
|
||||||
|
end
|
||||||
|
|
||||||
Given /^I have copied my site to "(.+)"$/ do |path|
|
Given /^I have copied my site to "(.+)"$/ do |path|
|
||||||
new_site_dir = File.join(TEST_DIR, path)
|
new_site_dir = File.join(TEST_DIR, path)
|
||||||
|
|
||||||
@ -16,6 +20,10 @@ Given /^I have copied my site to "(.+)"$/ do |path|
|
|||||||
.each { |f| FileUtils.mv(f, new_site_dir) }
|
.each { |f| FileUtils.mv(f, new_site_dir) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Given /^I have no configuration$/ do
|
||||||
|
write_file('_config.yml', '')
|
||||||
|
end
|
||||||
|
|
||||||
Given /^I have a configuration with:$/ do |config|
|
Given /^I have a configuration with:$/ do |config|
|
||||||
write_file('_config.yml', config)
|
write_file('_config.yml', config)
|
||||||
end
|
end
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
{% assign largest = resized | sort: 'width' | last %}
|
||||||
|
|
||||||
<img alt="{{ alt }}" src="/{{ original.path }}" title="{{ title }}" srcset="{% for i in resized %}/{{ i.path }} {{ i.width }}w,{% endfor %}/{{ original.path }} {{ original.width }}w">
|
<img alt="{{ alt }}" src="/{{ original.path }}" title="{{ title }}" srcset="{% for i in resized %}/{{ i.path }} {{ i.width }}w,{% endfor %}/{{ original.path }} {{ original.width }}w">
|
||||||
|
@ -22,6 +22,6 @@ Gem::Specification.new do |spec|
|
|||||||
spec.executables = []
|
spec.executables = []
|
||||||
spec.require_paths = ['lib']
|
spec.require_paths = ['lib']
|
||||||
|
|
||||||
spec.add_runtime_dependency 'jekyll', ['>= 2.0', "< 4.0"]
|
spec.add_runtime_dependency 'jekyll', ['>= 2.0', "< 5.0"]
|
||||||
spec.add_runtime_dependency 'rmagick', ['>= 2.0', '< 3.0']
|
spec.add_runtime_dependency 'rmagick', ['>= 2.0', '< 5.0']
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,13 @@ module Jekyll
|
|||||||
include Jekyll::ResponsiveImage::Utils
|
include Jekyll::ResponsiveImage::Utils
|
||||||
|
|
||||||
def render(context)
|
def render(context)
|
||||||
attributes = YAML.load(super)
|
content = super
|
||||||
|
|
||||||
|
if content.include?("\t")
|
||||||
|
content = content.lines.map {|line| line.gsub(/\G[\t ]/, " ")}.join("\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
attributes = YAML.load(content)
|
||||||
Renderer.new(context.registers[:site], attributes).render_responsive_image
|
Renderer.new(context.registers[:site], attributes).render_responsive_image
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -17,8 +17,19 @@ module Jekyll
|
|||||||
@site = site
|
@site = site
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def valid_config(config)
|
||||||
|
config.has_key?('responsive_image') && config['responsive_image'].is_a?(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
DEFAULTS.merge(@site.config['responsive_image'])
|
config = {}
|
||||||
|
|
||||||
|
if valid_config(@site.config)
|
||||||
|
config = @site.config['responsive_image']
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULTS.merge(config)
|
||||||
.merge(site_source: @site.source, site_dest: @site.dest)
|
.merge(site_source: @site.source, site_dest: @site.dest)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,6 +2,7 @@ module Jekyll
|
|||||||
module ResponsiveImage
|
module ResponsiveImage
|
||||||
class ExtraImageGenerator < Jekyll::Generator
|
class ExtraImageGenerator < Jekyll::Generator
|
||||||
include Jekyll::ResponsiveImage::Utils
|
include Jekyll::ResponsiveImage::Utils
|
||||||
|
include FileTest
|
||||||
|
|
||||||
def generate(site)
|
def generate(site)
|
||||||
config = Config.new(site).to_h
|
config = Config.new(site).to_h
|
||||||
@ -9,6 +10,7 @@ module Jekyll
|
|||||||
|
|
||||||
config['extra_images'].each do |pathspec|
|
config['extra_images'].each do |pathspec|
|
||||||
Dir.glob(site.in_source_dir(pathspec)) do |image_path|
|
Dir.glob(site.in_source_dir(pathspec)) do |image_path|
|
||||||
|
if FileTest.file?(image_path)
|
||||||
path = Pathname.new(image_path)
|
path = Pathname.new(image_path)
|
||||||
relative_image_path = path.relative_path_from(site_source)
|
relative_image_path = path.relative_path_from(site_source)
|
||||||
|
|
||||||
@ -20,3 +22,4 @@ module Jekyll
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
@ -6,14 +6,13 @@ module Jekyll
|
|||||||
def process(image_path, config)
|
def process(image_path, config)
|
||||||
absolute_image_path = File.expand_path(image_path.to_s, config[:site_source])
|
absolute_image_path = File.expand_path(image_path.to_s, config[:site_source])
|
||||||
|
|
||||||
raise SyntaxError.new("Invalid image path specified: #{image_path}") unless File.file?(absolute_image_path)
|
Jekyll.logger.warn "Invalid image path specified: #{image_path.inspect}" unless File.file?(absolute_image_path)
|
||||||
|
|
||||||
resize_handler = ResizeHandler.new
|
resize_handler = ResizeHandler.new(absolute_image_path, config)
|
||||||
img = Magick::Image::read(absolute_image_path).first
|
|
||||||
|
|
||||||
{
|
{
|
||||||
original: image_hash(config, image_path, img.columns, img.rows),
|
original: image_hash(config, image_path, resize_handler.original_image.columns, resize_handler.original_image.rows),
|
||||||
resized: resize_handler.resize_image(img, config),
|
resized: resize_handler.resize_image,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,7 +25,11 @@ module Jekyll
|
|||||||
partial = File.read(image_template)
|
partial = File.read(image_template)
|
||||||
template = Liquid::Template.parse(partial)
|
template = Liquid::Template.parse(partial)
|
||||||
|
|
||||||
result = template.render!(@attributes.merge(@site.site_payload))
|
info = {
|
||||||
|
registers: { site: @site }
|
||||||
|
}
|
||||||
|
|
||||||
|
result = template.render!(@attributes.merge(@site.site_payload), info)
|
||||||
|
|
||||||
RenderCache.set(cache_key, result)
|
RenderCache.set(cache_key, result)
|
||||||
end
|
end
|
||||||
|
@ -3,26 +3,39 @@ module Jekyll
|
|||||||
class ResizeHandler
|
class ResizeHandler
|
||||||
include ResponsiveImage::Utils
|
include ResponsiveImage::Utils
|
||||||
|
|
||||||
def resize_image(img, config)
|
attr_reader :original_image
|
||||||
img.auto_orient! if config['auto_rotate']
|
|
||||||
|
|
||||||
|
def initialize(original_image_absolute_path, config)
|
||||||
|
@config = config
|
||||||
|
|
||||||
|
@original_image_absolute_path = original_image_absolute_path
|
||||||
|
|
||||||
|
if @config['auto_rotate']
|
||||||
|
load_full_image
|
||||||
|
@original_image.auto_orient!
|
||||||
|
else
|
||||||
|
load_image_properties_only
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def resize_image
|
||||||
resized = []
|
resized = []
|
||||||
|
|
||||||
config['sizes'].each do |size|
|
@config['sizes'].each do |size|
|
||||||
width = size['width']
|
width = size['width']
|
||||||
ratio = width.to_f / img.columns.to_f
|
ratio = width.to_f / @original_image.columns.to_f
|
||||||
height = (img.rows.to_f * ratio).round
|
height = (@original_image.rows.to_f * ratio).round
|
||||||
|
|
||||||
next unless needs_resizing?(img, width)
|
next unless needs_resizing?(width)
|
||||||
|
|
||||||
image_path = img.filename.force_encoding(Encoding::UTF_8)
|
image_path = @original_image.filename.force_encoding(Encoding::UTF_8)
|
||||||
filepath = format_output_path(config['output_path_format'], config, image_path, width, height)
|
filepath = format_output_path(@config['output_path_format'], @config, image_path, width, height)
|
||||||
resized.push(image_hash(config, filepath, width, height))
|
resized.push(image_hash(@config, filepath, width, height))
|
||||||
|
|
||||||
site_source_filepath = File.expand_path(filepath, config[:site_source])
|
site_source_filepath = File.expand_path(filepath, @config[:site_source])
|
||||||
site_dest_filepath = File.expand_path(filepath, config[:site_dest])
|
site_dest_filepath = File.expand_path(filepath, @config[:site_dest])
|
||||||
|
|
||||||
if config['save_to_source']
|
if @config['save_to_source']
|
||||||
target_filepath = site_source_filepath
|
target_filepath = site_source_filepath
|
||||||
else
|
else
|
||||||
target_filepath = site_dest_filepath
|
target_filepath = site_dest_filepath
|
||||||
@ -36,16 +49,22 @@ module Jekyll
|
|||||||
|
|
||||||
Jekyll.logger.info "Generating #{target_filepath}"
|
Jekyll.logger.info "Generating #{target_filepath}"
|
||||||
|
|
||||||
if config['strip']
|
load_full_image unless @original_image_pixels_loaded
|
||||||
img.strip!
|
|
||||||
end
|
if @config['strip']
|
||||||
i = img.scale(ratio)
|
@original_image.strip!
|
||||||
i.write(target_filepath) do |f|
|
|
||||||
f.interlace = i.interlace
|
|
||||||
f.quality = size['quality'] || config['default_quality']
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if config['save_to_source']
|
i = @original_image.scale(ratio)
|
||||||
|
|
||||||
|
quality = size['quality'] || @config['default_quality']
|
||||||
|
|
||||||
|
i.write(target_filepath) do |f|
|
||||||
|
f.interlace = i.interlace
|
||||||
|
f.quality = quality
|
||||||
|
end
|
||||||
|
|
||||||
|
if @config['save_to_source']
|
||||||
# Ensure the generated file is copied to the _site directory
|
# Ensure the generated file is copied to the _site directory
|
||||||
Jekyll.logger.info "Copying resized image to #{site_dest_filepath}"
|
Jekyll.logger.info "Copying resized image to #{site_dest_filepath}"
|
||||||
FileUtils.copy_file(site_source_filepath, site_dest_filepath)
|
FileUtils.copy_file(site_source_filepath, site_dest_filepath)
|
||||||
@ -54,7 +73,7 @@ module Jekyll
|
|||||||
i.destroy!
|
i.destroy!
|
||||||
end
|
end
|
||||||
|
|
||||||
img.destroy!
|
@original_image.destroy!
|
||||||
|
|
||||||
resized
|
resized
|
||||||
end
|
end
|
||||||
@ -65,8 +84,18 @@ module Jekyll
|
|||||||
Pathname.new(format % params).cleanpath.to_s
|
Pathname.new(format % params).cleanpath.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def needs_resizing?(img, width)
|
def needs_resizing?(width)
|
||||||
img.columns > width
|
@original_image.columns > width
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_full_image
|
||||||
|
@original_image = Magick::Image::read(@original_image_absolute_path).first
|
||||||
|
@original_image_pixels_loaded = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_image_properties_only
|
||||||
|
@original_image = Magick::Image::ping(@original_image_absolute_path).first
|
||||||
|
@original_image_pixels_loaded = false
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_output_dir_exists!(path)
|
def ensure_output_dir_exists!(path)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
module Jekyll
|
module Jekyll
|
||||||
module ResponsiveImage
|
module ResponsiveImage
|
||||||
VERSION = '1.5.0'.freeze
|
VERSION = '1.6.0'.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
25
sample-templates/imager-js.html
Normal file
25
sample-templates/imager-js.html
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{% comment %}
|
||||||
|
Render your responsive images using Imager.js (https://github.com/BBC-News/Imager.js/), with the smallest resized image used as a fallback.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
{% responsive_image path: assets/image.jpg alt: "A description of the image" %}
|
||||||
|
|
||||||
|
(P.S. You can safely delete this comment block)
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{% assign smallest = resized | sort: 'width' | first %}
|
||||||
|
|
||||||
|
<div class="responsive-image">
|
||||||
|
<img class="responsive-image__placeholder" src="/{{ smallest.path }}">
|
||||||
|
<div class="responsive-image__delayed" data-src="/assets/resized/{width}/{{ original.basename }}"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
new Imager('.responsive-image__delayed', {
|
||||||
|
availableWidths: [{{ resized | map: 'width' | join: ', ' }}],
|
||||||
|
onImagesReplaced: function() {
|
||||||
|
$('.responsive-image__placeholder').hide()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
16
sample-templates/picture.html
Normal file
16
sample-templates/picture.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% comment %}
|
||||||
|
Render your responsive images using <picture>, with the original asset used as a fallback. Note: If your original assets are not web-friendly (e.g. they are very large), you can use a resized image as the fallback instead. See the srcset-resized-fallback.html template for how to do this.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
{% responsive_image path: assets/image.jpg alt: "A description of the image" %}
|
||||||
|
|
||||||
|
(P.S. You can safely delete this comment block)
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
<picture>
|
||||||
|
{% for i in resized %}
|
||||||
|
<source media="(min-width: {{ i.width }}px)" srcset="/{{ i.path }}">
|
||||||
|
{% endfor %}
|
||||||
|
<img src="/{{ path }}">
|
||||||
|
</picture>
|
18
sample-templates/srcset-resized-fallback.html
Normal file
18
sample-templates/srcset-resized-fallback.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{% comment %}
|
||||||
|
Render your responsive images using <img srcset>, with the largest resized image used as a fallback.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
{% responsive_image path: assets/image.jpg alt: "A description of the image" %}
|
||||||
|
|
||||||
|
(P.S. You can safely delete this comment block)
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{% assign largest = resized | sort: 'width' | last %}
|
||||||
|
{% capture srcset %}
|
||||||
|
{% for i in resized %}
|
||||||
|
/{{ i.path }} {{ i.width }}w,
|
||||||
|
{% endfor %}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
<img src="/{{ largest.path }}" alt="{{ alt }}" srcset="{{ srcset | strip_newlines }} /{{ path }} {{ original.width }}w">
|
17
sample-templates/srcset.html
Normal file
17
sample-templates/srcset.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{% comment %}
|
||||||
|
Render your responsive images using <img srcset>, with the original asset used as a fallback. Note: If your original assets are not web-friendly (e.g. they are very large), you might prefer to use the srcset-resized-fallback.html template.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
{% responsive_image path: assets/image.jpg alt: "A description of the image" %}
|
||||||
|
|
||||||
|
(P.S. You can safely delete this comment block)
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{% capture srcset %}
|
||||||
|
{% for i in resized %}
|
||||||
|
/{{ i.path }} {{ i.width }}w,
|
||||||
|
{% endfor %}
|
||||||
|
{% endcapture %}
|
||||||
|
|
||||||
|
<img src="/{{ path }}" alt="{{ alt }}" srcset="{{ srcset | strip_newlines }} /{{ path }} {{ original.width }}w">
|
Loading…
x
Reference in New Issue
Block a user